Search code examples
c#unity-game-enginegame-physics

Moving Platform works most of the time, but occasionally falls through and/or is jittery


I'm writing a 2D game and I'm trying to get moving platforms to work. After doing some previous investigation, I have it ALMOST working. The idea is to have 2 platform objects with colliders: 1 a visible object, the other an invisible object with isTrigger set (since the player would just go through a trigger). The code for the Moving Platform child (the trigger one) is set here.

using UnityEngine;
using System.Collections;

public class MovingPlatformChild : MonoBehaviour
{
public string parentPlatform = "";

void Start ()
{
    transform.parent = GameObject.Find(parentPlatform).transform;
}

// Update is called once per frame
void Update ()
{

}

void OnTriggerEnter(Collider playerObject)
{
    Debug.Log ("enter moving platform");
    if(playerObject.gameObject.name.Contains("Player"))
    {
        playerObject.transform.parent = gameObject.transform;
    }
}
int i = 0;
void OnTriggerStay(Collider playerObject)
{
    Debug.Log ("stay" + i++);
    if(playerObject.transform.position.y >= transform.position.y)
    {
        playerObject.transform.parent = gameObject.transform;
    }
    else
    {
        playerObject.transform.parent=null;
    }
}
void OnTriggerExit(Collider playerObject)
{
    Debug.Log ("EXIT");
    if(playerObject.gameObject.name.Contains("Player"))
    {
        playerObject.transform.parent=null;
    }
}
}

The Start() function just makes it a child of the visible platform. This can probably be done right in the Unity editor as well, instead of through code.

The OnTriggerEnter function adds the player object as a child of the trigger platform object, which is a child of the visible platform. So they should all move together.

The OnTriggerStay is an attempt to verify that this remains true only while the player is on the top of the platform. While the player is within the trigger, if the player is on top of the platform, then it remains attached. Otherwise, it's not. This is so that nothing happens on the bottom end.

The OnTriggerExit function just removes the player object as a child when it exits the trigger.

This is somewhat working (but we know somewhat isn't good enough). It works sometimes, but the player will be very jittery. Also, on the way down while standing atop the platform, the TriggerStay function doesn't appear to be called (implying the player is no longer within the trigger). This is observed through my Debug "stay" statement. Finally, sometimes the player will also fall straight through the platform.

What in this code would allow the player to fall through the platform, or be so jittery on the way up? Am I missing something crucial? If you need any more code, please let me know.

Below is the code for the movement of the non-trigger platform (the parent of the trigger platform and in an identical position). I will also share the Player's Update function after that.

void Start () 
{
    origY = transform.position.y;
    useSpeed = -directionSpeed;
}

// Update is called once per frame
void Update ()
{
    if(origY - transform.position.y > distance)
    {
        useSpeed = directionSpeed; //flip direction
    }
    else if(origY - transform.position.y < -distance)
    {
        useSpeed = -directionSpeed; //flip direction
    }
    transform.Translate(0,useSpeed*Time.deltaTime,0);
}

And now the player code:

  void Update()
{
    CharacterController controller = GetComponent<CharacterController>();
    float rotation = Input.GetAxis("Horizontal");
    if(controller.isGrounded)
    {
        moveDirection.Set(rotation, 0, 0); //moveDirection = new Vector3(rotation, 0, 0);
        moveDirection = transform.TransformDirection(moveDirection);

        //running code
        if(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) //check if shift is held
        { running = true; }
        else
        { running = false; }

        moveDirection *= running ? runningSpeed : walkingSpeed; //set speed

        //jump code
        if(Input.GetButtonDown("Jump"))
        {
            //moveDirection.y = jumpHeight;
            jump ();
        }
    }
    moveDirection.y -= gravity * Time.deltaTime;
    controller.Move(moveDirection * Time.deltaTime);
}

EDIT: I've added the specifications for the platforms and player in this imgur album:

https://i.sstatic.net/WjORu.jpg


Solution

  • The problem I was having included

    1. The moving platform was written using Translate. I rewrote it using a rigidbody and the rigidbody.Move function. This didn't immediately help, but...
    2. I realized the CharacterMotor script (Unity provides this) that I had attached to the player included moving platform support. I set the MovementTransfer value to PermaLocked, and also unchecked the "Use FixedUpdate" box on the script, and it now works 99% of the time. I've had one time where I did a particular behaviour and slipped through, but I can't recreate it.

    Hope this helps anyone who might be looking for an answer!