Zak Woolley
Zak Woolley

Reputation: 179

player won't stick on a moving platform

I have created some moving platforms for my game. There's a game object called PlatformPath1 which has children that define the start and end of the platform's cycle and then obviously there's the actual platform which follows the path. The platform moves perfect however, like expected, the player does not move with the platform. How would I get the player to move with the platform?

Here is the code for PlatformPath1

using System.Collections.Generic;
using UnityEngine;
using System.Collections;

public class FollowPath : MonoBehaviour
{
    public enum FollowType
    {
        MoveTowards,
        Lerp
    }

    public FollowType Type = FollowType.MoveTowards;
    public PathDefinition Path;
    public float Speed = 1;
    public float MaxDistanceToGoal = .1f;

    private IEnumerator<Transform> _currentPoint;

    public void Start()
    {
        if (Path == null)
        {
            Debug.LogError("Path cannot be null", gameObject);
            return;
        }

        _currentPoint = Path.GetPathEnumerator();
        _currentPoint.MoveNext();

        if (_currentPoint.Current == null)
            return;

        transform.position = _currentPoint.Current.position;
    }

    public void Update()
    {
        if (_currentPoint == null || _currentPoint.Current == null)
            return;

        if (Type == FollowType.MoveTowards)
            transform.position = Vector3.MoveTowards (transform.position, _currentPoint.Current.position, Time.deltaTime * Speed);
        else if (Type == FollowType.Lerp)
            transform.position = Vector3.Lerp(transform.position, _currentPoint.Current.position, Time.deltaTime * Speed);

        var distanceSquared = (transform.position - _currentPoint.Current.position).sqrMagnitude;
        if (distanceSquared < MaxDistanceToGoal * MaxDistanceToGoal)
            _currentPoint.MoveNext();
    }
}

And here is the code for the platform

using System;
using UnityEngine;
using System.Collections.Generic;
using System.Collections;

public class PathDefinition : MonoBehaviour
{
    public Transform[] Points;

    public IEnumerator<Transform> GetPathEnumerator()
    {
        if(Points == null || Points.Length < 1)
            yield break;

        var direction = 1;
        var index = 0;
        while (true)
        {
            yield return Points[index];

            if (Points.Length == 1)
                continue;

            if (index <= 0)
                direction = 1;
            else if (index >= Points.Length - 1)
                direction = -1;

            index = index + direction;
        }
    }

    public void OnDrawGizmos()
    {
        if (Points == null || Points.Length < 2)
            return;

        for (var i = 1; i < Points.Length; i++) {
            Gizmos.DrawLine (Points [i - 1].position, Points [i].position);
        }
    }
}

Upvotes: 1

Views: 4116

Answers (3)

ArtOfWarfare
ArtOfWarfare

Reputation: 21476

I thought this was going to be difficult, but I actually found it really simple to make a solution that seems to work pretty well.

The character in my game has a Box Collider. It's not a trigger and it doesn't use a physics material. It has a Rigidbody with a Mass of 1, Drag of 0, Angular Drag of 0.05, Uses Gravity, is not Kinematic, does not Interpolate, and Collision Detection is Discrete. It has No Constraints. For lateral movement, I use transform.Translate and for jumping I use Rigidbody's AddForce with ForceMode.VelocityChange as the final argument.

The moving platform also has a Box Collider. I set the transform.position based on the results of a call to Vector3.Lerp on every frame. I also have this script on the moving platform:

void OnCollisionEnter(Collision collision) {
    // Attach the object to this platform, but have them stay where they are in world space.
    collision.transform.SetParent(transform, true);
    Debug.Log("On platform.");
}

void OnCollisionExit(Collision collision) {
    // Detach the object from this platform, but have them stay where they are in world space.
    collision.transform.SetParent(transform.parent, true);
    Debug.Log("Off platform.");
}

And that's all. Really, it's just two lines of code in the script to declare that I'm implementing the two methods, and then the actual implementation of each is a single line. All of the info at the start is just for in case the Collision Detection isn't actually working out in your project (I always forget what the rules are for what does and doesn't count as a collision and/or a trigger.)

Upvotes: 1

Agumander
Agumander

Reputation: 686

If you were to stand on a moving platform in the real world, the reason you would move with the platform is because of the friction between the platform and your feet. If the platform were covered in ice, you might not move with the platform if it begins its motion while you're on it!

Now we can implement this in your game's physics. Normally your friction might just slow your player down to zero speed when you're not trying to walk. Instead you can check the ground collider on impact to see if it has a moving platform script, and get the speed of the platform. Then use this speed as the "zero point" for your motion calculation.

Upvotes: 1

Venkat at Axiom Studios
Venkat at Axiom Studios

Reputation: 2516

You could add the Player as a child to the platform. That way, when the platform moves, the player will too.
At the end of the movement (or on some user input), you could break the parenting. Here's some code you can try out.

public GameObject platform; //The platform Game Object
public GameObject player;   //The player Game Object

//Call this to have the player parented to the platform.
//So, say for example, you have a trigger that the player steps on 
//to activate the platform, you can call this method then
void AttachPlayerToPlatform () {
    player.transform.parent = platform.transform;
}

//Use this method alternatively, if you wish to specify which 
//platform the player Game Object needs to attach to (more useful)
void AttachPlayerToPlatform (GameObject platformToAttachTo) {
    player.transform.parent = platformToAttachTo.transform;
}

//Call this to detach the player from the platform
//This can be used say at the end of the platform's movement
void DetachPlayerFromPlatform () {
    player.transform.parent = null;
}

Upvotes: 2

Related Questions