The Aim
As the title suggests, I’m pretty much trying to recreate Portal’s object interaction with regard to picking up and holding objects. The interactable objects each have a collider and a rigidbody. I’ve managed to get the basics down, but I can’t quite get it exactly how I want. The basic summary of what I want is as follows:
 
- Toggle the holding of objects with a single button press
- While held, the object should remain centred in the player camera viewport
- While held, the object’s position should remain stationary relative to the player
- While held, the object should not pass through level geometry such as walls and floors
- While held, the object should react to collisions, but not gravity
- While not held, the object should react to gravity and collisions
###The Code###
The following code is assigned to the player. It uses a raycast to check for an interactable object, and then calls the object’s interact function when a button is pressed (it’s a little sloppy while I play around with things; open to feedback and advice):
 
private void Update() {
if (Input.GetButtonDown("Fire1") && m_CanInteract == true) {
Interaction();
}
}
private void FixedUpdate() {
Ray ray = new Ray(m_CameraTransform.position, m_CameraTransform.forward);
if (Physics.Raycast(ray, out m_RaycastFocus, 3) && m_RaycastFocus.collider.transform.tag == "Interactable") {
m_CursorImage.color = Color.green;
m_CanInteract = true;
}
else {
m_CursorImage.color = Color.white;
m_CanInteract = false;
}
}
private void Interaction() {
IInteractable interactComponent = m_RaycastFocus.collider.transform.GetComponent<IInteractable>();
if (interactComponent != null) {
interactComponent.Interact();
}
}
 
And this code is found in the interactable object’s script. It simply toggles whether or not the object is held, and parent’s the object’s transform to the player camera if it is:
 
public void Interact() {
if (!held) {
held = true;
transform.parent = cameraTransform;
}
else if (held) {
held = false;
transform.parent = null;
}
}
###The Attempts###
I’ve been playing around with various properties and lines of code but not been able to achieve the effect I’m after. Here are some of my attempts and their faults:
 
Using only the code above, with default rigidbody component
Held object drops to the floor and does not follow the camera’s viewport accurately.
 
While held, rigidbody.useGravity = false
Held object does not follow the camera viewport accurately, and floats away when collided with another object.
 
While held, rigidbody.isKinematic = true
This is almost exactly what I’m after, until the held object is moved towards a wall or floor, at which point the object phases straight through.
 
While held, rigidbody.constraints = RigidbodyConstraints.FreezeAll
Basically the same as above, except the object now doesn’t rotate with the player (as rotation is frozen). Still phases through level geometry.
 
No rigidbody component
Mostly just a test, as I still want objects to be affected by physics when not held, but this did work well. The object moves with the player exactly as intended, and cannot pass through walls and floors. However, moving the object into a collision affects the player’s position (e.g. looking down whilst holding the object moves the player on top of it), it would be preferable if the object’s collisions did not affect the player’s rotation and position. Also, no rigidbody isn’t really feasible for my game anyway.
Apologies, this turned out wordier than expected! I’ve tried to be as specific as possible but if there’s any more info needed I’ll be happy to provide. Thanks in advance for any help, and thanks if you even just took the time to read through! ![]()
This is awesome and it works, but it also makes player to be able to float on the item. Best fix is to add:
– enerccioPhysics.IgnoreCollision(playerScript.GetComponent<Collider>(), GetComponent<Collider>());intoInteractandPhysics.IgnoreCollision(playerScript.GetComponent<Collider>(), GetComponent<Collider>(), false);into drops.