Velocity powered rigidbody on a moving platform without parenting.

Hello, I’ve searched beforehand, and nothing applies to my specific situation, and I need to have moving platforms work, however, I’m using a rigidbody because I need it to be pushed around, and because of issues with scaling and being parented but just frozen in midair, I can’t use parenting to do this.

I’m moving the player by directly controlling velocity, the platform is ticked as kinematic (it has a rigidbody too), gravity on it is disabled, the way the platform moves is like this:

public class Platform : MonoBehaviour 
{
	public float speed = -1f;
	public Vector3 pointB;
	
	IEnumerator Start()
	{
		var pointA = transform.position;
		while (true)
		{
			yield return StartCoroutine(MoveObject(transform, pointA, pointB, speed));
			yield return StartCoroutine(MoveObject(transform, pointB, pointA, speed));
		}
	}
	
	IEnumerator MoveObject(Transform thisTransform, Vector3 startPos, Vector3 endPos, float time)
	{
		var i = 0.0f;
		var rate = 1.0f/time;
		
		while (i < 1.0f) 
		{
			i += Time.deltaTime * rate;
			thisTransform.position = Vector3.Lerp(startPos, endPos, i);
			yield return null;
		}
	}
}

What can I do to get the player to stick to the platform when needed?, and only when he’s standing on the top of it, a scenario with the player being stuck to the side of the moving platform wouldn’t be very good.

I know it is not the best way but you can use Fixed Joint for this purpose.

As you want to have your player character to just stand on the platform you can use Fixed Joint for this.

All you have to do is check when the player collides with the platform and create a joint between the platform and player.

Also you can just destroy the joint when not needed i.e. you want to make player move away from the platform.

Make the object on the platform share the velocity of the platform its on.
So on the callback OnCollisionStay(). Get the rigidbody and assign the velocity on it to be the same as the platform.
However for this to work you need to find out, make or use Vector3.SmoothDamp to find out the velocity of the platform.
Because looking at your script… You are manually moving it via the lerp function so there is no true way to know the velocity of the platform. You could take the normalized direction of where the platform is going and multiply it by the speed. You could also find out if the player is on the platform by using a trigger instead or find out the direction the player is relative to the platform.

var Direction = (transform.position - player.transform.position).normalized;
const float SafeZone = 0.5;//Adjust me a little!
//Player is on the platform
if(Direction.y > SafeZone)
{

}

I know this is super late, but even 6 years later there was little in way of example on how to do this when the character is using a dynamic Rigidbody 2d (or 3d) and the platforms are kinematic.

So I took the additive velocity approach and that seemed best.

Here is my moving platform component code

using Player;
using UnityEngine;

namespace Environment {
	public class MovingPlatform : MonoBehaviour {
		public ParticleSystem dirt;
		public float speed = .5f;
		public Vector2 startPosition;
		public Vector2 endPosition;

		[HideInInspector] public Vector3 velocity;

		private Rigidbody2D _self;
		private SwordMenMovement _player;
		private Vector2 _distance;
		private Vector2 _oldPosition;
		private bool _playerIsOnTop;

		private void Start() {
			_self = GetComponent<Rigidbody2D>();
			_oldPosition = _self.position;
		}
		

		private void FixedUpdate() {
			var time = Mathf.PingPong(Time.time * speed, 1);
			_distance = Vector2.Lerp(startPosition, endPosition, time);
			_self.MovePosition(_distance);
			// calculate velocity on kinematic object, I found a version of this on the internet and adopted it to the fixed update method.
			var newPosition = _self.position;
			var media = (newPosition - _oldPosition);
			velocity = media / Time.fixedDeltaTime;
			_oldPosition = newPosition;
			
			if (_playerIsOnTop && _player) {
                           // custom function on my player component
				_player.AddVelocity(velocity);
			}
		}
		

		private void OnCollisionEnter2D(Collision2D other) {
			if (!other.collider.CompareTag("Player")) return;
                    // only when player is on top of the platform
			if (!(Vector3.Dot(other.contacts[0].normal, Vector3.down) > 0.5)) return;
                   // optional particle effect
			dirt.Play();
			// some caching
			if (_player == null) {
                            // get whatever component used to able to access your player
				_player = other.transform.GetComponent<SwordMenMovement>();
			}

			_playerIsOnTop = true;
		}
		
		private void OnCollisionExit2D(Collision2D other) {
			if (!other.collider.CompareTag("Player")) return;
			_playerIsOnTop = false;
		}
		
		
	}
}

Within my player component for movement

public void AddVelocity(Vector2 v) {
		_velocity += v.x;
}

where the _velocity is applied in a fixed update with modified code from the Brackeys character controller;

var targetVelocity = new Vector2(_velocity, _rb.velocity.y);
_rb.velocity = Vector3.SmoothDamp(_rb.velocity, targetVelocity, ref _mVelocity, .0001f);

where the friction in the material is set to 1, though it’s not needed anymore so i’m going to remove it.