Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
4
Question by Soilyman · Jan 25, 2018 at 03:36 PM · rigidbodygrabportalpick upholding

[SOLVED] Picking Up/Holding Objects Portal Style

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! :)

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
4
Best Answer

Answer by Soilyman · Jan 26, 2018 at 10:43 AM

I'm now a small step closer to my aim. I've added a "Player Hands" object which is a child of the player camera. This object has a kinematic Rigidbody and a Fixed Joint component. When an object is picked up by the player, its useGravity property is disabled and it becomes connected to the Fixed Joint. The object now follows the player camera viewport and collides with static colliders.

 

Sadly, the collision using this method is very erratic and pushing the held object against a wall or floor causes it to jump about rapidly. I've tried also parenting the object to the Player Hands object, and I've tried the different Collision Detection properties with no success.

 

I think the joint component might be the solution. Maybe a tense Spring Joint which will accurately follow the camera viewport and close the distance between it and the player when pushed against a collider, coiling back to it's original position when it has room to do so. Joint components are a new venture for me so I'm not quite there yet.


The Solution

Apologies for bumping this thread multiple times, but I've come up with a solution I'm satisfied with and I figured I'd share it for anyone stumbling upon this post in the future.

 

I was spending too much time getting this how I wanted so I came up with a bit of a shortcut method that resolves multiple possible roadblocks. Basically the held object will now be dropped if a large force is acted upon it; such as pushing the object against a wall or floor. I'll share my own personal scripts so they can be copied and tweaked by whoever needs them. This first script is attached to my player object:

 

 public class PlayerController : MonoBehaviour {
     [SerializeField] private Transform m_CameraTransform = null;
     public Transform m_HandTransform = null;
     [SerializeField] private Image m_CursorImage = null;
     public float m_ThrowForce = 200f;
 
     private RaycastHit m_RaycastFocus;
     private bool m_CanInteract = false;
 
 
     private void Start() {
         m_CameraTransform = GetComponentInChildren<Camera>().transform;
     }
 
     private void Update() {
         // Has interact button been pressed whilst interactable object is in front of player?
         if (Input.GetButtonDown("Fire1") && m_CanInteract == true) {
             IInteractable interactComponent = m_RaycastFocus.collider.transform.GetComponent<IInteractable>();
 
             if (interactComponent != null) {
                 // Perform object's interaction
                 interactComponent.Interact(this);
             }
         }
 
         // Has action button been pressed whilst interactable object is in front of player?
         if (Input.GetButtonDown("Fire3") && m_CanInteract == true) {
             IInteractable interactComponent = m_RaycastFocus.collider.transform.GetComponent<IInteractable>();
 
             if (interactComponent != null) {
                 // Perform object's action
                 interactComponent.Action(this);
             }
         }
     }
 
     private void FixedUpdate() {
         Ray ray = new Ray(m_CameraTransform.position, m_CameraTransform.forward);
 
         // Is interactable object detected in front of player?
         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;
         }
     }
 }

 

And the next script is attached to the object which can be picked up. It uses an IInteractable interface which simply contains void Interact(playerController script) and void Action(playerController script) functions.

 

 public class PhysicsObject : MonoBehaviour, IInteractable {
     public bool m_Held = false;
 
     private Rigidbody m_ThisRigidbody = null;
     private FixedJoint m_HoldJoint = null;
 
 
     private void Start() {
         gameObject.tag = "Interactable";
         m_ThisRigidbody = GetComponent<Rigidbody>();
     }
 
     private void Update() {
         // If the holding joint has broken, drop the object
         if (m_HoldJoint == null && m_Held == true) {
             m_Held = false;
             m_ThisRigidbody.useGravity = true;
         }
     }
 
     // Pick up the object, or drop it if it is already being held
     public void Interact(PlayerController playerScript) {
         // Is the object currently being held?
         if (m_Held) {
             Drop();
         }
         else {
             m_Held = true;
             m_ThisRigidbody.useGravity = false;
 
             m_HoldJoint = playerScript.m_HandTransform.gameObject.AddComponent<FixedJoint>();
             m_HoldJoint.breakForce = 10000f; // Play with this value
             m_HoldJoint.connectedBody = m_ThisRigidbody;
         }
     }
 
     // Throw the object
     public void Action(PlayerController playerScript) {
         // Is the object currently being held?
         if (m_Held) {
             Drop();
 
             // Force the object away in the opposite direction of the player
             Vector3 forceDir = transform.position - playerScript.m_HandTransform.position;
             m_ThisRigidbody.AddForce(forceDir * playerScript.m_ThrowForce);
         }
     }
 
     // Drop the object
     private void Drop() {
         m_Held = false;
         m_ThisRigidbody.useGravity = true;
 
         Destroy(m_HoldJoint);
     }
 } 

 

I've butchered my own scripts a little bit to focus the above on the topic in question, so apologies if I made an error anywhere. Also worth pointing out that I'm using a 'Player' GameObject, with the main camera attached as a child, and a 'Hands' object with a Rigidbody attached to the camera as a child.

 

Hopefully I've been as clear as possible, and it's a fairly basic script anyway, but if anyone has any difficulties just leave a comment and I'll try to help out :)

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image enerccio · Aug 19, 2019 at 06:18 AM 1
Share

This is awesome and it works, but it also makes player to be able to float on the item. Best fix is to add:

Physics.IgnoreCollision(playerScript.GetComponent<Collider>(), GetComponent<Collider>()); into Interact and Physics.IgnoreCollision(playerScript.GetComponent<Collider>(), GetComponent<Collider>(), false); into drops.

avatar image
0

Answer by timmyiscool8 · Mar 12, 2019 at 06:28 PM

Unity is giving me an issue I can't solve. What is IInteractable? I can't find anything on google about it... @Soilyman

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image RunninglVlan · Jun 19, 2019 at 02:01 PM 2
Share

IInteractable interface ... simply contains void Interact(playerController script) and void Action(playerController script) functions.

avatar image Ljrnet RunninglVlan · Aug 19, 2019 at 04:08 AM 0
Share

why did you necro this.

avatar image gstudios2008 Ljrnet · Dec 22, 2020 at 06:27 AM 1
Share

I do that and get Class 'PhysicsObject' cannot have multiple base classes: '$$anonymous$$onoBehaviour' and 'IInteractable'

avatar image cjmort10 · Apr 19, 2021 at 12:20 AM 0
Share

Me Too. idk y

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

104 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Method for grabbing rigidbody 2 Answers

How to keep objects from passing through colliders 2 Answers

Pick Up Object using Rigidbody FPS 0 Answers

Pick up object 0 Answers

Prevent a specific RB to influence another, but still collide with everything 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges