Search Unity

Have a rigidbody stay on a moving rigidbody ( Player on ship )

Discussion in 'Physics' started by KevinRevelj, Apr 6, 2018.

  1. KevinRevelj


    Aug 25, 2014
    So I am trying to get my player to be able to walk around on a ship that will be moving around at the same time. The ship is a rigidbody. But I can't get it to work.

    I tried to make the player a parent of the ship but that doesn't really work. So my question is how would you solve this? I'm completely out of ideas on how to solve this.

    If what I described above is unclear I basically am trying to make a ship that works similar to Sea of Thieves or Blackwake were you can walk around on the ship as it's moving.
  2. Snipe76


    May 23, 2017
    Well, the ship should be the parent and not the player. Because the player is the one that needs to be with the ship.

    Usually, some of the better options do still involve making the platform a parent of the character for this sort of thing. That way, when the platform begins moving, the player moves exactly with it, as though it were simply stationary ground the player is standing on.

    What causes problems with this easily, however, is making the transition between a moving platform and a stationary one (and vice versa). When the parent of a physics-driven object changes, the object keeps its current velocity... and adds it to the parent's. As a result, landing on a platform moving the same direction means suddenly shooting forward at incredible speed.

    Two options:

    • Parent the player to the platform when they are grounded on it and unparent them when they are grounded on a new platform or simply when they jump

    • Use physics. If you're using the built in rigidbody physics, keeping one body on a moving platform is a matter of playing with friction on the physic material
    You could also maybe try a more programmatic solution where you don't change the transform parent, but just also apply the movement of the platform to the player while they're standing on the platform.
    Last edited: Apr 8, 2018
    BrandyStarbrite likes this.
  3. BrandyStarbrite


    Aug 4, 2013
    Snipe75 gave alot of really good info. :D

    The other way you could do this, is to keep the ship stationary and make the sea/ocean move. Doing it this way, will make it easier for the player's character
    to move around the ship.

    If I remember correctly, they did something similar, in resident evil zero
    for nintendo gamecube. Where the train appeared to be moving, but was
    actually still. And the train's wheels, were animated to spin around.
    Giving it the illusion, that the train was travelling, to an unknown destination point.
    And Rebecca or Cody, could walk on top of the train, or throughout the train's
    interior with ease.

    The same tactic can be used, for a spaceship, travelling throughout space.

    Make the space enviroment move, when the ship is travelling.
    But in reality, the space ship is stationary. So when you zoom your camera,
    into the ship to control your character, he/she can easily move through the ship
    and do all sorts of cool stuff, without having to worry much about, lots of Cpu
    and physics calculations etc.
    And when the character, looks out the window, and sees the stars and planets
    zooming by, (fake moving space enviroment and planets) it'll appear as if the
    ship is travelling though space.

    And as you approach an island, or a planet, a trigger/sensor, will swap out the
    fake moving enviroment/or fake space enviroment and replace it, with the
    real enviroment/or space enviroment, island or planets, that you can land on
    and explore. :D
    Last edited: Oct 27, 2018
  4. Sailendu


    Jul 23, 2009
    @BrandyStarbrite Those are some really awesome ideas you shared here. Thanks a lot.
    BrandyStarbrite likes this.
  5. BrandyStarbrite


    Aug 4, 2013
    Thanks dude. Glad to help as always. :D
    Sailendu likes this.
  6. BrandyStarbrite


    Aug 4, 2013
    I put more details in my post, to make it more understandable.
    I might come back and add in more details.
    Enjoy! :D
    Last edited: Oct 27, 2018
  7. hippocoder


    Digital Ape Moderator

    Apr 11, 2010
    Simply add the velocity difference to the velocity of the player each physics frame, from that point. Don't use parenting or anything of that nature if you're using rigidbodies.
  8. Jawsarn


    Jan 12, 2017
    I'm doing something similar in my game, and the best solution for my case was to have two objects as the (space)ship and two physics layers. One ship object that contains the external colliders + rigidbody, and an internal ship object that simply mirror the transform of the external one and has the internal colliders. So when somone walks on/off the ship(I use triggers here), I simply parent/unparent them and swap their layer. :)
  9. Ava42


    Aug 4, 2012
    Hi! here is my solution of rigidbody move on rigidbody:

    in short - it moves virtual point as child of platform, then get delta of moving and rotation of it in world space and affect it on character rigid. Character rotation capsule must be fixed in all axis, only Y rotation of "spaceship" will affect character rotation.

    Also it have some "inertia" illusion when character jumps off ship / elevator. it represented in variable PowerOfAligment. It setups 2.5 seconds and use 0.5 seconds of this time for tracing every 0.5 so it will not affect while it more then 2.0
    it also will work if you have boxes on your spaceship and it will align to any surface traced below.
    also recommended setup tracing distance on jump height and more (so character will keep ship contact while jumps inside ship)

    p.s. it also works with root motion animations that controls rigid.

    Script must be last in execution order list.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    5. public class PlatformSolver : MonoBehaviour
    6. {
    7.     [SerializeField] float TraceOfs = 1.0f;// if we need to lift tracing start point
    8.     [SerializeField] float TraceDst = 5.0f;// tracing down distance
    9.     [SerializeField] LayerMask ColisWhat; //set only ground or ship or elevators layer!
    10.     [SerializeField] Rigidbody MyRig;
    12.     Transform VirtPoint;
    13.     Vector3 GrndPrevPos;
    14.     float GrndPrevRotY;
    16.     float TraceTimer=0.0f;
    17.     float PowerOfAligment = 0.0f;
    19.     void LateUpdate()
    20.     {
    21.         if (VirtPoint == null) //create if point is lost
    22.         {
    23.             GameObject temp = new GameObject("vptp");
    24.             VirtPoint = temp.transform;
    25.         }
    27.         TraceTimer += Time.deltaTime;
    28.         if (TraceTimer > 0.5f)//trace from character to down sometime
    29.         {
    30.             TraceTimer = 0.0f;
    32.             RaycastHit hit;
    33.             if (Physics.Raycast(MyRig.position + Vector3.up * TraceOfs, Vector3.down, out hit, TraceDst, ColisWhat))
    34.             if (hit.collider != null)
    35.             {
    36.                 if (VirtPoint.parent != hit.collider.transform) // check if we change platform we staying in.
    37.                 {
    38.                     VirtPoint.parent = hit.collider.transform; // set virtual point as child of ship / elevator or just ground
    39.                     GrndPrevPos = VirtPoint.position = MyRig.position; // reset virtual point to current sharacter position
    41.                     //do same for rotation
    42.                     GrndPrevRotY = MyRig.rotation.eulerAngles.y;
    43.                     VirtPoint.rotation = MyRig.rotation;
    44.                 }
    45.                 PowerOfAligment = 2.5f;
    46.             }
    48.         }
    50.         //power of platform aligment will be ceepet at 2.5 sec every 0.5 sec, so we have 2.0 seconds to fade off platform aligment power;
    51.         if (PowerOfAligment>0.0f) PowerOfAligment -= Time.deltaTime;
    53.         if (GrndPrevPos != VirtPoint.position) // if platform under characters legs is moved in any direction
    54.         {
    55.             float align = Mathf.Clamp01(PowerOfAligment*0.5f); // it will fade off aligment power first 2 seconds of legs lost contact with platform (if character jumps from platform - it will work as impulse illusion )
    57.             //we perform move character on that delta. (so we dont need move it if there is no moving at all)
    58.             Vector3 delta = VirtPoint.position - GrndPrevPos;
    59.             MyRig.MovePosition(MyRig.position + delta * align);
    60.         }
    62.         //same for rotations.
    63.         if (GrndPrevRotY != VirtPoint.rotation.eulerAngles.y)
    64.         {
    65.             float align = Mathf.Clamp01(PowerOfAligment * 0.5f); // it will fade off aligment power first 2 seconds of legs lost contact with platform (if character jumps from platform - it will work as impulse illusion )
    67.             Vector3 wasRot = MyRig.rotation.eulerAngles;
    68.             float delta = VirtPoint.eulerAngles.y - GrndPrevRotY;
    69.             if (delta > 180.0f) delta -= 360.0f;
    70.             if (delta < -180.0f) delta += 360.0f;
    71.             wasRot.y += delta * align;
    73.             MyRig.MoveRotation(Quaternion.Euler(wasRot));
    74.         }
    76.         //prepearing data for next frame
    77.         GrndPrevPos = VirtPoint.position = MyRig.position;
    78.         GrndPrevRotY = MyRig.rotation.eulerAngles.y;
    79.         VirtPoint.rotation = MyRig.rotation;
    80.     }
    81. }
    Last edited: Nov 29, 2019
    paul_meynckens likes this.
  10. paul_meynckens


    Nov 30, 2019
    @Ava42 That is a really nice work and I am sure it could solve the problem. But I am not sure I understand.

    Which object do you attach this script to? Is it the "spaceship"?

    What object do we need to put into these fields :
    [SerializeField] LayerMask ColisWhat; //set only ground or ship or elevators layer!
    [SerializeField] Rigidbody MyRig;