- Home /
Better jumping with "Lerpz" character controller
Hello,
I am working on a 2.5D platformer and I am using the character controller script from the 2.5D platformer tutorial (this doublejump "hack" to be exact: http://www.unifycommunity.com/wiki/index.php?title=DoubleJumpController).
However, this controller has a major flaw: since it's using the running speed to make the jump, you can move in the air when you jump if you don't run immediately before the jump.
This make precise platforming really difficult in certain situations, especially when dealing with narrow platforms. Does anyone knows a way to fix this or another script that would correct that problem?
Our game is almost done, but the character controller is still making the jumping segments a lot harder than they should be.
If anyone have a solution, it would be very welcome.
Thank you.
Answer by skovacs1 · Sep 21, 2010 at 05:32 PM
"since it's using the running speed to make the jump, you can move in the air when you jump if you don't run immediately before the jump." is kind of confusingly worded - I'm not sure that the one actually necessarily implies the other in this case and, from your script, I'm pretty sure you can still move in the air when you run, just not nearly as noticeably.
Firstly, if you're using any script, you should figure out what it's doing. Just grabbing people's stuff and plugging it in, assuming it will work for you is a terrible practice (and moreover, asking for help the moment it doesn't fit your usage without trying to understand is even worse - I'm not saying that's what you're doing, but I have no way to know).
The simple answer is to tune the value of inAirControlAcceleration
and it should give you something more like what you imagine. For even more control, you could also replace the compound assignment of movement.inAirVelocity
with movement.inAirVelocity += movement.direction * Time.deltaTime * movement.inAirControlAcceleration
so that the value is scaled by the amount of input of h.
If that still doesn't get you what you want, assuming that you are using the exact script linked (because you didn't post anything else), here's what the relevant functional code in Update here does:
//move horizontally as calculated in UpdateSmoothedMovementDirection * speed
//+ vertically by the speed calculated in ApplyGravity or ApplyJumping
//+ horizontally + vertically by the inAirMovement calculated in ApplyJumping
//+ horizontally by the adjustment to inAirMovement calculated in
//UpdateSmoothedMovementDirection
var currentMovementOffset = movement.direction * movement.speed
+ Vector3(0,movement.verticalSpeed,0)
+ movement.inAirVelocity;
currentMovementOffset *= Time.deltaTime;
movement.collisionFlags = controller.Move (currentMovementOffset);
All you seem to care about is the horizontal movement, so the only variables you actually need to care about are movement.direction
, movement.speed
and movement.inAirVelocity
.
The part that does the work:
function UpdateSmoothedMovementDirection() { //called by Update every frame //...irrelevant stuff //move direction is *always* (canControl is never changed in this script) //the horizontal input when the absolute horizontal input is greater than 0.1 if (movement.isMoving) movement.direction = Vector3 (h, 0, 0);
//calculate the speed change only when on the ground
if (controller.isGrounded) {
var curSmooth = movement.speedSmoothing * Time.deltaTime;
var targetSpeed = Mathf.Min (Mathf.Abs(h), 1.0);
if(Input.GetButton("Fire2") && canControl)
targetSpeed *= movement.runSpeed;
else
targetSpeed *= movement.walkSpeed;
movement.speed = Mathf.Lerp (movement.speed, targetSpeed, curSmooth);
//...irrelevant stuff
}
//inAirVelocity is going to be adjusted horizontally by Time.deltaTime
//in the direction of horizontal input
else {
//...irrelevant stuff
if (movement.isMoving)
movement.inAirVelocity += Vector3(Mathf.Sign(h),0,0) * Time.deltaTime
* movement.inAirControlAcceleration;
}
}
The part that sets initial inAirVelocity:
function ApplyJumping() { //called by Update every frame
//...irrelevant stuff
//When on the ground and we can jump, the inAirVelocity will be
//the motion of the platform we're on
if (controller.isGrounded) {
if (jump.enabled && Time.time < jump.lastButtonTime + jump.timeout) {
//...irrelevant stuff
movement.inAirVelocity = lastPlatformVelocity;
//...irrelevant stuff
}
}
}
What's probably not what you expect is that you only ever calculate the speed when on the ground. Once in the air, you move at the speed you were moving when you were last on the ground in the input direction (movement.direction) + some adjustment affected by the input direction (inAirVelocity). I assume this is supposed to simulate inertia somehow, but it really doesn't work that way because you can change direction still and there's no deceleration.
To get proper direction on the inertia, you would need to move the change to movement.direction
into the if(Controller.isGrounded)
block which follows. To get the actual inertial deceleration, you would subtract from speed in the else statement at some smoothing rate until it is 0 and keep the lastPlatformVelocity
separate from inAirVelocity
, add that as a separate term and decelerate it as well.
To give full speed control while in the air, I recommend you move the speed stuff out of that if block (in which case, inAirVelocity may not need to be changed in UpdateSmoothedMovementDirection). Alternatively, you can change what you use to calculate movement when jumping by doing something like if(!controller.isGrounded) movement.speed = inAirSpeed;
, but this will result in some unnatural behaviour and you will likely need to do some tuning in the air.
Your answer
Follow this Question
Related Questions
Make a 2D jump? 0 Answers
Choose Start and End Frame for 2D Animation 0 Answers
Lerpz 2D Tutorial - Can't Save Scene And Proceed 0 Answers
2.5D Platformer - Jump Question 1 Answer