- Home /
Grab/Release object while pressing a key
Hello everyone! I am traying to make an script for a box. If the player is colliding with the box and presses ctrl, it grabs the box and can move it. If the player releases ctrl key, it releases the box and can't move it anymore.
Here´s my script:
void Update () {
if (Input.GetKeyDown(KeyCode.LeftControl) == true)
{
ctrl = true;
}
else if (Input.GetKeyUp(KeyCode.LeftControl) == true)
{
ctrl = false;
}
}
private void OnCollisionStay2D(Collision2D collision)
{
if (ctrl == true)
{
transform.parent = collision.transform;
}
if (ctrl == false)
{
transform.parent = null;
}
}
}
The problem is that if I press ctrl and grab the box, it doesn't release it when I release the key. My character is still its parent.
Answer by Lysander · Dec 27, 2017 at 08:34 PM
First off, use transform.SetParent(parentTransform, true) instead, unless you're using a Unity version too old to have that function.
This looks like the functionality "to be picked up" is on the box, when I think it would make more sense for "pick something up" to be on the player object instead. The act of picking something up should probably be based on a trigger radius (press control while in a small trigger zone, possibly even while facing the general direction of the object) rather than a collision event. All that the box needs is a tag or component that identifies it as being able to be picked up, and the character controller should handle the rest.
It's not necessarily bad to use OnCollisionStays as a limiting factor in triggering the pickup, but it definitely can't be relied upon for releasing. OnCollisionStays is the most fragile of all of the collision/trigger events, and is easy to disrupt in really unexpected ways. You can't confidently say the objects will still be in a colliding state at any point in the future, even after reparenting it. Whether you disable the collider or rigidbody on pickup or not, I highly doubt it'll be in constant contact for any length of time, and even if it is, OnCollisionStays will fire for every object in contact with that collider, not just the player's collider, so as it is, you pressing CTRL while the cube is leaning against a wall will reparent it to the wall.
How I would probably do this is: make a character controller on the player object, make an empty list of objects in range of pickup (where objects are added to the collection in OnTriggerEnter and removed in OnTriggerExit, provided they have the correct tag or component attached to be a "pickup item"). Pressing a button like CTRL should check the direction of each of the objects in that collection and find the one that's closest and/or most centered on the character's facing direction, assign the object to "pickedUpObject", and fire a function to reparent it. Then, when the button is released, it should check if there's a "pickedUpObject" set, and if so, unparent it (without relying on the colliders or triggers or anything).
That said, if you want to get your current code working as fast as possible, just make a new bool variable for "isPickedUp" that's made true when the reparenting happens, then change the un-parenting portion to be in the Update function when control is released IF "isPickedUp" is true, and switch it to false.
Something like this perhaps:
private bool _isPickedUp = false;
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftControl))
{
ctrl = true;
}
else if (Input.GetKeyUp(KeyCode.LeftControl))
{
ctrl = false;
if (_isPickedUp)
{
transform.SetParent(null);
_isPickedUp = false;
}
}
}
private void OnCollisionStay2D(Collision2D collision)
{
if (ctrl && !_isPickedUp && collision.gameObject.tag == "Player")
{
transform.SetParent(collision.transform, true);
_isPickedUp = true;
}
}
Your answer
Follow this Question
Related Questions
Check collision of childs Trigger in Parents script [JS] 1 Answer
How can I animate a GameObject that isn't parented, but will need to be for the animation? 1 Answer
Make a GameObject a Child of What it Collides With 2 Answers
How to glue Objects together on contact? 2 Answers
SetParent does not work. 1 Answer