Character flickering on moving platform
Hi everyone... I created a lift for my 2D platformer, and when my player with rigidbody enter on it, I set the player as child of lift, and it works perfectly.... The problem is when I walk on it! The player stay slower, and flickering a bit, looking like the lift is holding him. I tried to make the lift as a rigidbody, and move it with velocity, solved this problem, but the player doesn't stay stick to the lift. And if I use this lift horizontal, my player doesn't move with this lift :/
- More Details:
My player character has Rigidbody and 2 Colliders2D, one Box for body and one Circle for legs, like the Standard Character Robotboy of Unity. For his movement I'm using:
playerRigidbody.velocity = new Vector2(move* maxSpeed, playerRigidbody.velocity.y);
My lift has a simple Box Collider2D and I'm moving it using:
using UnityEngine;
using System.Collections;
public class Lift : MonoBehaviour
{
[SerializeField] private float speed = 20;
[SerializeField] private Transform endPosTransform;
[SerializeField] private GameObject player;
private Transform myTransform;
private Vector2 startPos;
private Vector2 endPos;
private Vector2 nextPos;
void Start()
{
myTransform = transform;
startPos = myTransform.localPosition;
endPos = endPosTransform.localPosition;
nextPos = endPos;
}
void Update()
{
SetMovement();
SetDirection();
}
void SetMovement()
{
myTransform.localPosition = Vector2.MoveTowards(myTransform.localPosition, nextPos, speed * Time.deltaTime);
}
void SetDirection()
{
if (Vector2.Distance(myTransform.localPosition, nextPos) <= 0.1)
{
if (nextPos == endPos)
{
nextPos = startPos;
}
else
{
nextPos = endPos;
}
}
}
void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Player"))
{
other.transform.SetParent(transform);
}
}
void OnCollisionExit2D(Collision2D other)
{
if (other.gameObject.CompareTag("Player"))
{
other.transform.SetParent(null);
}
}
}
I uploaded a project with a character like my and the lift. If someone wants to check yourself what is happening when you walk on this lift: Download Project
If someone understand and could help me.. Thank you!
@$$anonymous$$avina Hi, you already helped me a lot... $$anonymous$$aybe you can help me on it, it's very importante to me, please.
I would suggest that ins$$anonymous$$d of trying to reinvent the wheel to first start off with Unity's built in PlatformCharacter2D
(you need to load the 2D asset package).
Hi @$$anonymous$$avina, but I'm using the PlatformCharacter2D and the same thing still happening. If you download this project I uploaded, you could test it and see.
Answer by Mike-Geig · Nov 10, 2016 at 03:12 PM
Howdy, after doing some testing and discuss with our physics folks I have a solution for you. Basically, a game object with a rigidbody on it has a transform position and a body position. The body position drives the transform of the game object. In this instance, interpolating the platform is causing direct changes to the player's transform, which is fighting with its rigidbody.
The easiest way to fix this is to stop parenting the player to the transform and instead simply move the player by the amount of movement of the platform every frame. Again, this movement needs to be calculated based off of the players body position and not its transform position (or else the same problem occurs). With all of that in mind, I modified your Lift script below. This is tested and works and avoids any hierarchy shuffling. You'll notice I added a LateUpdate to move the player based on its body. Also, I no longer parent the player to the platform in the OnCollision method.
using UnityEngine;
public class Lift : MonoBehaviour
{
[SerializeField] private float speed = 20f;
[SerializeField] private Transform endPosTransform;
private Vector2 startPos;
private Vector2 endPos;
private Vector2 nextPos;
//ADDED
private Rigidbody2D player;
private Vector3 moveDelta;
void Start()
{
startPos = transform.localPosition;
endPos = endPosTransform.localPosition;
nextPos = endPos;
}
void Update()
{
SetMovement();
SetMoveDirection();
}
//Move the player by the change in movement of the platform using the player's rigidbody instead of parenting
void LateUpdate()
{
if (player)
{
Vector2 playerBody = player.position;
player.transform.position = new Vector3 (playerBody.x, playerBody.y) + moveDelta;
}
}
void SetMovement()
{
//Calculate desired position
Vector2 desiredPosition = Vector2.MoveTowards(transform.localPosition, nextPos, speed * Time.deltaTime);
//Use that position to figure out the change in position of the platform
moveDelta = new Vector3 (desiredPosition.x, desiredPosition.y, 0f) - transform.position;
//Apply the new position
transform.localPosition = desiredPosition;
}
void SetMoveDirection()
{
if (Vector2.Distance(transform.localPosition, nextPos) <= 0.1)
{
if (nextPos == endPos)
{
nextPos = startPos;
}
else
{
nextPos = endPos;
}
}
}
void OnCollisionEnter2D(Collision2D other)
{
//Instead of parenting, grab a reference to the player's rigidbody
if (other.gameObject.CompareTag("Player"))
player = other.gameObject.GetComponent<Rigidbody2D>();
}
void OnCollisionExit2D(Collision2D other)
{
//Remove reference
if (other.gameObject.CompareTag("Player"))
player = null;
}
}
Cheers
Perfect... The explain was clear enough and the problem is solved. Thank you!
That what i looking for! Thank you man, best solution for me. And it will be more correct and flexible if change this line
moveDelta = new Vector3 (desiredPosition.x, desiredPosition.y, 0f) - transform.position;
to this
moveDelta = new Vector3(desiredPosition.x, desiredPosition.y, 0f)- transform.localPosition;
Answer by Stanchion · Oct 30, 2016 at 02:28 PM
Parent the player to the platform when it makes contact with it
@Stanchion But it's exactly what I'm doing... However, my player is walking weird on it
Answer by mareczkos · Jul 26, 2020 at 01:25 PM
I know it's an old issue but actually I had the same problem and answer might be helpful for someone else in the future.
So I assume you have 2 objects like Lift and Player. On collision you are adding Lift as a parent for Player object.
Create another object call it for example Platform and let it be a parent for Lift. In script which is attached to Lift object try moving Platform instead of Lift, like this
private void FixedUpdate()
{
transform.**parent**.position += (new Vector3(0,1f)* Time.deltaTime);
}
It'll move Parent of Lift which is Platform.
Instead of making Lift as a parent for Player you'll need to make Platform as a parent for your Player
void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Player"))
other.transform.SetParent(transform.**parent**);
}
In short words, use parent object to move your platform and his child object to detect collision. When collision is happening set Player's parent to platform which is moving.
Have fun
EDIT: It seems like flickering will appear when you change Scale of your Platform. So in your case you can scale Lift object but parent of Lift object which I proposed to add should not be scaled!
Your answer
Follow this Question
Related Questions
Player gets stuck on moving platform 0 Answers
Rotating a 2D sprite on a surface 0 Answers
Character wont stop Bouncing 1 Answer
2d platformer knockback without addforce 1 Answer
2d Moving Platforms 1 Answer