Unity Physics Gun

Unity Physics Gun

Always been a fan of Garry’s mod thought I would try implementing the physics gun in unity. In some ways it turned out to be more challenging than I anticipated though I ended up with a fairly functional prototype. It could definitely do with some more polish it’s pretty ugly at the moment…

The Gun

The gun was crudely constructed in blender just for the prototype. I never actually got round to texturing it.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///

/// Fire 1 = Tool action, default prop manipulation
/// Fire 2 = Teleport to position
///

[RequireComponent(typeof(LineRenderer))]
public class WarpGun : Weapon {

// for use when the ray collides with an object.
public ParticleSystem physGunPSystem;

// Button down?
bool fire1Down = false;
bool fire2Down = false;

LineRenderer physRay;
public Material laserMaterial;

float hitDistance = 0.0f;

Rigidbody attachedBody = null;

float targetDistance = 0;
Vector3 targetPosition = Vector3.zero;
Vector3 anchorPoint = Vector3.zero;

float scrollSpeed = 1.0f;

void Awake () {
// add a line renderer to the gameobject
this.physRay = this.gameObject.GetComponent();
this.physRay.positionCount = 2;
this.physRay.material = this.laserMaterial;

// disabled on start
this.physGunPSystem.Stop();
}

private void Update() {

}

// Update is called once per frame
void FixedUpdate () {

Ray cameraRay = this.playerCamera.ViewportPointToRay(new Vector3(0.5F, 0.5F, 0));

if (this.fire1Down) {

float castDistance = 3000;
hitDistance = castDistance;

this.physRay.enabled = true;
this.physRay.SetPosition(0, this.barrelEnd.position);

RaycastHit hitInfo;

if (Physics.Raycast(cameraRay,out hitInfo,castDistance)) {
this.physRay.SetPosition(1, hitInfo.point);
targetPosition = hitInfo.point;

this.physGunPSystem.gameObject.transform.position = targetPosition;
if (!this.physGunPSystem.isPlaying)
this.physGunPSystem.Play();

if (attachedBody == null) {
if (hitInfo.collider.gameObject.tag == "Prop") {
Rigidbody _body = hitInfo.collider.gameObject.GetComponent() ;
if (attachedBody == null) {
targetDistance = Vector3.Distance(cameraRay.origin, hitInfo.point);
this.anchorPoint = hitInfo.collider.gameObject.transform.position -hitInfo.point;
_body.constraints = RigidbodyConstraints.None;
_body.velocity = Vector3.zero;
_body.angularVelocity = Vector3.zero;
attachedBody = _body;
}
}
}

}
else {
this.physRay.SetPosition(1, cameraRay.GetPoint(hitDistance));
this.physGunPSystem.Stop();
}

//Set material properties
//material.mainTextureScale = new Vector2(_target.y - this.transform.position.y, 1);
this.laserMaterial.mainTextureOffset += new Vector2(-this.scrollSpeed * Time.deltaTime, 0);

if (this.fire2Down) {
if (this.attachedBody) {
this.attachedBody.constraints = RigidbodyConstraints.FreezeAll;
}
}

}
else {
//disabled line renderer
this.physRay.enabled = false;

this.physGunPSystem.Stop();

if (this.attachedBody)
this.attachedBody.useGravity = true;

this.attachedBody = null;
}

if (attachedBody != null) {
//Ray cameraRay = this.playerCamera.ViewportPointToRay(new Vector3(0.5F, 0.5F, 0));

float maxVelocity = 30;
float maxForce = 100;

this.attachedBody.useGravity = false;
Vector3 rPos = cameraRay.GetPoint(this.targetDistance) - (this.attachedBody.transform.position - anchorPoint);
float distance = Vector3.Distance(this.attachedBody.transform.position, cameraRay.GetPoint(this.targetDistance));
Vector3 targetVelocity = Vector3.ClampMagnitude(10.0f * rPos, maxVelocity);
Vector3 relativeForce = targetVelocity - this.attachedBody.velocity;
Vector3 force = Vector3.ClampMagnitude(10.0f * relativeForce, maxForce);
this.attachedBody.AddForce(force);

}

}

public override void fire2() {
base.fire2();
this.fire2Down = true;
}

public override void fire2Released() {
base.fire2Released();
this.fire2Down = false;
}

public override void fire1() {
base.fire1();
this.fire1Down = true;
}

public override void fire1Released() {
base.fire1Released();
this.fire1Down = false;
}

}

 

The Level

The level was also crudely constructed in blender however I used textures obtained from the unity asset store to texture the walls, floor, ceiling and the cubes seen in the demo. Credit for the textures should be designated towards the original creator.

 

 

The Ray

The ray was constructed using a line renderer effectively using the following snippet of code to tile the texture along the length of the line.

public Material laserMaterial;
float scrollSpeed = 1.0f;

void FixedUpdate(){
///... code
this.laserMaterial.mainTextureOffset += new Vector2(-this.scrollSpeed * Time.deltaTime, 0);

}

Leave a Reply