Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Moving Object & Player with Push/Pull || Applying Opposing Force

Discussion in 'Physics' started by dkirilov, Mar 24, 2018.

  1. dkirilov

    dkirilov

    Joined:
    May 25, 2017
    Posts:
    12
    Hey, so I've been struggling with a problem for a while, not sure how to approach it.

    I'm trying to simulate a magic system similar to The Force used in Star Wars in Unity, and have ran into some troubles. I'm trying to simulate pushing and pulling on objects appropriately. This means that when the player pushes an object, both the player and the object get a force applied to them. If the object is light enough, the player shouldn't be affected in any noticeable way, and the object should be pushed away. If their masses are similar, both should be pushed away at some rate, and if the object is heaver, the player should be mainly pushed away. The same goes with pulling. The problem is when objects are anchored against something. If a player pushes a light object into a wall, the player should start receiving enough force to start pushing them backwards, since the combined mass of the wall and the object are pushing the player back.

    Currently, I'm able to do the first part with the following code when a key is pressed:
    Note that the force is determined based off the distance from the player to the object and the mass of them.

    // dir: push or pull (-1 or 1)
    Vector3 directionToPlayer = (dir * (player.transform.position - transform.position)).normalized;
    rb.AddRelativeForce(directionToPlayer * f * Time.deltaTime);
    player.GetComponent<Rigidbody>().AddRelativeForce(-directionToPlayer * f * Time.deltaTime);


    As it is, the code works fine when the objects are just by themselves just by relying on Unity's Physics system. However, it does NOT work when an object is being pushed against a wall, or something really heavy. This is pretty clear as I'm just applying the same force to both the object and the player, and letting Unity decide whether to move the entity based off its rigidbody mass.

    My question is, how can I detect if an object is anchored, and if it is combine the mass of the object and the object which it is anchored to, and apply that force to the player? I was thinking how to do this, and I know that I need to figure out the direction of which the force is being applied from, and then determine whether the object that's being pushed or pulled is colliding with anything in that direction, and if so apply a force to the player based off the combined masses. This gets a little tricky however when pushing an object at an angle that's against a wall. For example consider the following scenario:
    upload_2018-3-23_19-45-55.png
    There is both a horizontal and a vertical component of the force being applied on the cube, and so that should be considered when the cube+wall combined object pushes back on the player. How could this be accomplished or approached? I'm really struggling coming up with how to do this without hard coding direcitons.

    Any help is appreciated, and I'll gladly clarify if anything is unclear.


    *NOTE* The system is really based from a book series called Mistborn, but the concept is really close to The Force in Star Wars, and so I'll run with that as more people are familiar with it
     
    Last edited: Mar 24, 2018
  2. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    I'm not sure this is a great approach, and it could be tricky to get it connected, but the first thing that comes to mind would be to try to make use of `Collision.impulse` (https://docs.unity3d.com/ScriptReference/Collision-impulse.html). I haven't tested this, but what I have in mind is something like this:

    Have an OnCollisionEnter/OnCollisionStay handler on a script on any object you can push around. As long as the player is using their "Force" power to push the object, look at the `collision.impulse` value of the object's `collision`, and apply that force to the player. For example:

    Code (CSharp):
    1. void OnCollisionEnter(Collision collision) {
    2.     // Make sure the collision is against something other than the player
    3.     if (!collision.other.CompareTag("Player")) {\
    4.         // Note: Assume you acquired a reference to the player rigidbody in Start(), or by it being assigned in the inspector
    5.         // Apply the impulse to the player. Make sure you don't need to invert it...but I think this is right.
    6.         PlayerRigidBody.AddForce(collision.impulse);
    7.     }
    8. }
    9.  
    You'd have to play around with it a bit, but that might be enough. Oh, and do the same thing in OnCollisionStay().

    The tricky part is that let's say something else falls on the object while the player is Force pushing it, ideally you wouldn't apply that force to the player. Figuring it which forces to apply and which to ignore could be tricky.
     
    Last edited: Mar 24, 2018
  3. dkirilov

    dkirilov

    Joined:
    May 25, 2017
    Posts:
    12
    I see what you're saying, but then I get in the issue of how to know not to apply a force when a player is pushing an object, it collides with something, and then the player decides to pull it. The OnCollisionStay will continue to apply the force until the object is no longer colliding which isn't ideal since no new force should be applied on the player when they switch to pulling. I definitely see how it's tricky though. I'll keep poking around for now I guess.