11/9/15

Two Amnesia-style "Gravity Gun" scripts for Unity

Let's get this out of the way first: I'm not the best programmer out there.  Not even close.  In fact, I'm kind of a terrible programmer (as the following scripts will evidence).

When I was working on Fingerbones, I originally wanted the player to be able to pick up items and carry/throw them around, like you can in Amnesia: The Dark Descent.  At the time, however, I couldn't figure out how to accomplish this, and wasn't able to find any real help online.  I avoided the problem for the next three games, ignoring physical interaction entirely in The Moon Sliver and using a "hold the item in your hand" system for The Music Machine and A Wolf in Autumn that didn't require any physics interaction while the item was held.


I recently decided to try solving the problem, however, and thought I'd share my scripts online, in case anyone else happens to need them.

Note that both of these are just code for holding objects, not for picking them up.

The problem with the Amnesia-style "pick up system" in Unity is basically that "picking up" an object is trivially easy, but dealing with collisions while you're holding the object isn't quite as simple.  This first script solves the problem by dropping the object if it encounters something else.

(both of these are in Javascript)

************************************

// this script is not very good, and should probably not be used
// for intense physics interactions.  It's best used for
// a garnish effect.

// objects you can pick up must have a rigidbody and a collider attached.
// rigidbody usegravity and rotation constraints will have to be reset when the object is dropped.
// each object should have its own radius for the Spherecast
// in this state only supports box colliders.
// Can be modified to support other colliders by adding lines of code
// to deal with enabling and disabling other colliders

var ObIHave : GameObject;
var HoldDist : float;
var MaxStretchDist : float;

@HideInInspector
var oldcoors : Vector3;



function Start () {

}

function FixedUpdate () {

if (ObIHave != null)
{
var goal : Vector3;
var rb : Rigidbody;
var hit : RaycastHit;
// disable rigidbody and collider
rb = ObIHave.GetComponent(Rigidbody);
rb.useGravity = false;
rb.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;
if (ObIHave.GetComponent(BoxCollider)){ObIHave.GetComponent(BoxCollider).enabled = false;}
// calculate where it's trying to go
goal = transform.position + (transform.forward * HoldDist);
// check if it can get there.  If so, set its position to the goal
// and parent it to the player for smooth movement.
// if not, make its parernt null and do nothing else
if(!Physics.SphereCast(transform.position,.3,transform.forward,hit,HoldDist))
{
ObIHave.transform.parent = transform;
ObIHave.transform.position = goal;
}
else
{
ObIHave.transform.parent = null;
}


// check if object is too far from its goal
// if so, drop it
if (Vector3.Distance(goal,ObIHave.transform.position) > MaxStretchDist)
{
DropObject();
}

}

}


// generic function for dropping a held object
function DropObject()
{
var rb : Rigidbody;
rb = ObIHave.GetComponent(Rigidbody);
rb.useGravity = true;
rb.constraints = RigidbodyConstraints.None;
if (ObIHave.GetComponent(BoxCollider)){ObIHave.GetComponent(BoxCollider).enabled = true;}
ObIHave = null;
}


*************************************

Obviously the big problem with this script is that it doesn't ACTUALLY allow for any physical interaction from the held object.  It does the basic effect, though, and maybe some of you will get some use out of it.

This next one is a bit better.  It actually uses the Unity physics system and allows a held object to interact with other physics objects, as well as simply avoiding clipping into them.

*****************************************

var carrydistance : float;
var resolvespeed : float;
var maxdist : float;

function Start () {

}

function FixedUpdate () {
if (obihave != null)
{
carryit();
}
}


function carryit()
{
// this is the point the object is trying to reach
var carrygoal : Vector3;
carrygoal = transform.position + (transform.forward * carrydistance);

var r : Rigidbody;
r = obihave.GetComponent(Rigidbody);
r.useGravity = false;
r.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;

// this sets the object's velocity based on both distance and the
// "resolve speed," in the direction of carrygoal
var force : Vector3;
force = carrygoal - obihave.transform.position;
force = Vector3.Normalize(force);
force = force * resolvespeed;
var dist : float;
dist = Vector3.Distance(carrygoal,obihave.transform.position);
force *= dist;
r.velocity = force;

// drop the object if it's too far from the goal
if (dist > maxdist)
{
dropobject();
}
}




function dropobject()
{
var r : Rigidbody;
r = obihave.GetComponent(Rigidbody);
obihave = null;
r.useGravity = true;
r.constraints = RigidbodyConstraints.None;
r.velocity = Vector3(0,0,0);
}


*************************************************

There are still some problems with this one, however.  First, object movement can be a bit jerky.  Second, the object itself doesn't rotate with the player, meaning it will actually appear to turn in place as you turn.  I'll probably work on this a bit more to see about fixing these problems, but in its current state it's still very usable.

And, it goes without saying that I'm very open to suggestions for ways to improve my approach.

4 comments:

  1. Dear Mr Szymanski,

    Are you interested in receiving publicity for your game A Wolf in Autumn?

    I am currently running a Giveaway group on Steam called: MTOKA Le Group[ http://steamcommunity.com/groups/MTOKALeGroup ].

    We promise to review your game once the our Steam curration goes underway. All we ask for in return is a few keys to test and fully review the game. And of course giveaway on Steamcompanion.
    Please send me an Email of you are interested.


    Nazir MTOKA

    Thank you for your time.

    PS. My email is mtokalegroup@gmail.com

    ReplyDelete
  2. VERY POPULAR Techno Song?? HELP!!! They play it in clubs!!?
    Gamrini - I Can't Feel My Face

    ReplyDelete