So I’ve managed to make a moving platform, but sadly my character slides off the platform as it moves. I’ve tried to increase the friction between my character’s feet and the platform itself, but it seems to make no difference.
Here’s a video demonstrating the problem:
If anyone knows how to fix this, I would really appreciate it
There was another question about this sort of thing just the other day, the consensus was that it just doesn’t work, and a workaround would be to try adding the Platforms velocity to the chick’s velocity whenever she is contacted with the platform. I’m not sure how well that would work however, but I would be interested to know.
It works very well, and is what I’ve done in my game. But this requires you to code velocity based movement for your moving platforms, as Animate Physics will not generate velocity values. The other solution is to create velocity from animations by doing postPos - prePos / Time.deltaTime, logging the prePos at the end of the script so that it’s updated value is only used on the next update cycle (or you can try Update/LateUpdate, but then you’re out of sync with FixedUpdate). Then you use OnCollision or a Raycast to grab the current platform your on and grab the value generated from the script on the platform which is generating that fake velocity value.
Guys I have found a way to make it work, but I don’t know how to program it. If I make the character a child of the platform, it all goes well, she moves with the platform, without any issues. I would love if she only was a child of this platform while she is grounded though. Anyone have any idea how I can script this? Here’s my character controller script if it helps:
I’m trying to do the same, but I run into several problems. I’m moving my platforms using translate and I keep track of the position offset, in the lateupdate I add this position offset to the player whenever he is inside a trigger around the platform. This sometimes works, sometimes doesn’t. For some reason OnTriggerStay2D is not firing properly depending on the hierarchy of objects…
How are you doing it? You directly move your platforms accessing the Rigidbody2d.velocity and add this also to the player rigidbody2d.velocity? Do you do all of this in the fixedupdate?
For this to work your platforms need a Rigidbody2d but then they are affected by gravity and will physically react to collisions with the player when it lands on them. I see two solutions for this: 1) set the gravity scale to 0 and the mass of the platform to a huge value so they don’t move when colliding with the player. Or, 2) make the platforms kinematic. Which one do you do?
Make your character’s gameobject a child of the moving platform when she jumps on it. That way she will move with the platform :). No need for crazy code!
I keep seeing this advice everywhere, and it doesn’t really work. For a platform that moves in all directions (horizontally, vertically, diagonally), when I tried that the character moves with the platform, but, when the character moves on top of it (while the platform also moving) the movement is jittery.
This is what finally worked for me. Hope it helps others. Parenting the player to the platform didn’t work as I wanted. I guess the approach is similar to what Invertex was proposing.
using UnityEngine;
using System.Collections;
public class Move_Ground : MonoBehaviour {
public Vector2 moveSpeed = new Vector2(0, 0);
public float timeToMove=1;
private float timeCounter;
private int moveDirection;
private bool isColliding=false;
void Start()
{
timeCounter = 0;
moveDirection = 1;
rigidbody2D.isKinematic = true;
}
void Update()
{
timeCounter += Time.deltaTime;
if (timeCounter > timeToMove)
{
timeCounter = 0;
moveDirection *= -1;
}
}
void OnCollisionStay2D(Collision2D coll)
{
if ((!isColliding) (coll.gameObject.tag == "Player"))
{
isColliding = true;
}
}
void OnCollisionExit2D(Collision2D coll)
{
if ((isColliding) (coll.gameObject.tag == "Player"))
{
isColliding = false;
}
}
void FixedUpdate()
{
rigidbody2D.velocity = moveSpeed * moveDirection;
if ((isColliding) (!(GameCore.Instance.isPlayerJumping)))
{
GameCore.Instance.player.rigidbody2D.velocity = rigidbody2D.velocity;
}
}
}
Hey, yes, I put rigidbodies on my platforms. And they are set to isKinematic so that they aren’t affected by other objects/forces. I have 3 raycasts coming down from the bottom of my character, one on both corners and one in the middle. I have a condition for if the middle raycast hit an object tagged “MovingPlatform”, then I add the velocity taken from the current platform I’m on, allowing my player can still move around on the platform respective to it’s movement. If I hit jump, or my raycast no longer returns that tagged gameObject type, then I stop receiving that velocity.
Since it’s doing it with my middle raycast, it also means that you get that nice platform to platform style where it’s only the platform the majority of you is on, that affects you (and otherwise if the middle raycast hasn’t hit a moving platform, check one of the sides for one and do the velocity if so).
I wrote up a nice script for my moving platforms that allows me to define distances I want the platform to go, as well as what speed, using rigidbody2D.velocity. And use Vector2.Distance() < goalDistance, to tell if my platform reached it’s destination. My “goalDistance” being a minimum distance + a small distance that’s multiplied by my platform “moveSpeed” to make up for physics oversteps due to speed. It seems to work consistently, I’ve had my platforms running for looong periods at both lightning speed and a snails pace, and they keep in sync with eachother, always meeting up where the should.
And yes, I do this in the FixedUpdate(), since we are dealing with physics forces here.
You can also use a script that generates a value for you using translate instead, by having the script on the platform constantly calculating currentPosition - lastPosition / Time.deltaTime, and having your player accessing that calculated value when on the platform and apply it to it’s velocity. (Though it didn’t seem to work well for me, as it was always a step too late, and even then didn’t seem to work right (partly likely due to translation steps being out of sync with physics steps). Though that may have just been a conflict with other code of mine.
How is your script even working? Your moveSpeed is 0, and thus your set velocity would be 0. But also, transform speed is not the same as velocity speed… This seems like it should only be working by luck at the speed you’re currently using, but at other speeds you wouldn’t be moving the same rate as the platform…
Parenting is a very dirty way to do things, that can lead to issues further down the road as your game becomes more fleshed out.
Thanks for the explanation, I think I will modify my script taking some of your ideas. I like specially the concept of using a goal distance rather than a moving time as I’m using now.
It is … magic! :lol:
Kidding aside, my moveSpeed is a public variable that I modify directly in the inspector when I set up the platforms. I set it to 0 in script so that by default a moving platform will not move (silly I know, but I like to initialize my variables to 0 when I can).
I’m not using any transform speed in my script, only rigidbody velocity, I don’t understand your point on this. The only thing that it is a bit hacky is that I’m not adding the platform velocity to my player’s velocity, I actually assign my platform velocity to it. I tried adding it (like you do) on the first place but it made the player move at shooting speeds. I guess this has to do with how the physics engine work or maybe I’m just lucky. If somebody with more understanding of the new 2D physics can clarify I would appreciate. I move my player using addForce on its rigidbody. I have tried with several different platform speeds and move times and the movement is correct (the platform moves as it should and the player is able to move on top of it at the same time, no slippery thing)
Oh, I must be blind, don’t know where I saw transform. Anyways, were you by chance using “AddForce()” to add the velocity of the platform as well? That could be why. Although I also set my player velocity directly in my movement code, instead of using AddForce();, this means if you’ve not pressing a move button, I’m going to be 0 before the platform addition happens, and if I am pressing a button, it’s never going to be a greater amount than what I’m inputting, before the addition of the platform. Basically my movement code nullifies any previous platform added player velocity before it can add it again.
Also, as much as I dislike sharing complete code, since I believe people should learn instead of just copying (not talking about you, just random people that will see this thread haha), I’ll post my platform script as it is right now so you can see how I approached it. (Though I plan on tweaking it a bit to better support it’s parameters being animated for curved and complex movements).
//Proxy - MovingPhysicsPlatform Script v1.0
public Vector2 moveDistance = new Vector2(2f,0); //How far in Units we want to go in X/Y.
public float moveSpeed = 5f; //Self explanatory
public float waitDuration = 1.5f; //How long to sit still at goal, before going back in other direction
private Vector2 startPos;
private int direction = 1;
private float goalDistance;
void Start()
{
startPos = transform.position; //Store our starting position so we can check for when we've returned to this position
goalDistance = 0.006f + (moveSpeed * 0.008f); //Always have a goal distance of at least 0.006, for when our platforms are going very slow, but also increase the acceptable distance for goal based on move speed.
}
void FixedUpdate()
{
if( direction == 1 (Vector2.Distance(transform.position, startPos + moveDistance) < goalDistance ) ) //If the Distance between our current position and the position we wanted to reach is less than the goalDistance, change direction and wait if waitDuration set
{
StartCoroutine( ChangeDir() ); //Start our wait/change direction Coroutine once we hit goal
}
else if( direction == -1 (Vector2.Distance(transform.position, startPos) < goalDistance ) ) //Same as before, just with our stored startPosition. And only if we're moving in the opposite direction, as to not trigger this as the start of movement, only when heading towards startPos.
{
StartCoroutine( ChangeDir() );
}
rigidbody2D.velocity = (moveSpeed * moveDistance.normalized) * direction; //Normalize our moveDistance to a 0-1 range so our set speed is consistent no matter how far the distance, and multiply it by moveSpeed and the direction we want to go.
}
IEnumerator ChangeDir() //Delay for once our platform hits it's goal, if we want one. Most games tend to, it gives the player a better chance to get on...
{
direction *= -1; //change the direction since we're going to reverse
float lastMoveSpeed = moveSpeed; //store the moveSpeed temporarily
moveSpeed = 0; //and set the actual moveSpeed to 0 so it doesn't move
yield return new WaitForSeconds(waitDuration); //Wait for how long we choose
moveSpeed = lastMoveSpeed; //start moving again
}
Crap! That was my mistake. I was adding the velocity of the platform to the players velocity at EVERY fixedupdate of the platform. Of course it was going at shooting speeds, silly me!
Anyway, I think I now why my solution works. I move my player using forces and the velocity of the player is set to the one of the platform. So that when I apply a force it is applied to the player going at that velocity. Don’t know if I’m explaining myself clearly. In summary, the player is having a basic velocity equal to the platform and on top of that a force is applied when I want to move.
Thanks, no need to share you code if you didn’t want to. I was more interested in the player-platform relation with physics than in the code to move the platform anyway. I learned quite some things in the process about the physics engine, for example that while forces don’t apply to kinematic rigidbodies, velocities do work
Thanks, Stilghar. To add to this, I messaged Stilghar regarding setting the velocity of the player equal to that of the moving platform not really being ideal since the player then can’t move when on it. His response:
This helps quite a bit, however there’s still the issue of deceleration, and not having the player come to an abrupt halt once input isn’t being applied.
I really don’t think any of this would be an issue if the RigidBody2D wasn’t so gimped. It lacks the crucial MovePosition() and MoveRotation() functions that it’s big brother has. Also, Physics Material 2D is severely lacking with missing static/dynamic friction, etc.
You could have a Coroutine that starts on GetButtonUp(“movement keys”) that continues to keep adding force, but gradually reduces itself every frame, giving you fine control over slide stop time too.
One Method I go to work is to apply an offset to the player relative to the spot the player hit the platform at as long as the player is in contact with the platform. This was a pain but I got it to work. I am going to try and parent it to the platform when in contact and see if that works. It would really reduce down on the amount of coding.
Hi helios, I don’t seem to have that problem myself and I don’t understand why it happens to you. When do you see this issue of deceleration? With this solution you set the player velocity equal to that of the player all the time (at every FixedUpdate) except when moving on them…
We got it working in our game without issues, maybe the speed of your platforms is very high?
Parenting is a very bad solution. I have seen people recommending it all over the place and it REALLY DOESN’T WORK! You will get only glitchy results at best. It has been discussed in this thread already, so I would not try that if I were you. Take Invertex solution if you have your player movement based on velocity or try mine if you have your player movement based on AddForce().
Hi again, not sure how to explain it. The issue with only having the player velocity = platform velocity only when not moving is that if you are moving, but in the opposite direction that that platform is moving, then your movement will look twice as fast since you’re not accounting for the opposite velocity of the platform. Hope that made sense. Do you not have the problem?
That is indeed what happens in our game (but in our case is the intended game design). We want the player to move on the platforms at the same speed it moves when on static ground no matter what. As you are correctly saying the movement “looks” faster but it is really not faster (relative to the game world). If what you want is that your player has to offset the speed of the platform then change the condition of setting the player velocity = platform velocity from idle to moving and idle (except jumping).
We were doing that before but didn’t fit with the gameplay of our game. If the platform was moving fast against the player, the player was not able to advance (relative to the game world).
I think we both are doing the same thing. It “looks” kinda of crazy I think because of the pattern of my moving platform. What I had to do though, was something like this:
Otherwise, the player would shoot left/right depending on when you change directions and which direction the platform is moving. Did you not have to do something like that?