EDIT: perhaps helpful gif strange problem, I’m not sure if the character is actually moving or not, maybe ever so slightly. also, now, after a key has been used, the “horizontal” movement stops automatically updating but the “vertical” movement keeps going.
(Note that this is just learning/testing, I’m not in “desperate” need of help since this isn’t for a specific game.)
I’ve been trying to follow some “math for game devs” tutorials made by Jorge Rodriguez, and they’re pretty good but they’re in C++ so I’m trying to “translate” them to C# and Unity. (Note: I’m open to the idea of discontinuing them if it’s not ultimately worth trying to “translate” all the time.) Current video
I’m having issues though; for right now I just want to get the smooth interpolation movement working correctly.
Jorge’s source code:
(“approach” function) MathForGameDevelopers/math/maths.h at lerping · BSVino/MathForGameDevelopers · GitHub
Trying to implement Jorge’s version, I have a script that checks horizontal (applied to x) and vertical movement (applied to z) and sets a velocity goal to reach, and a “smooth movement interpolation” script that sets the position and velocity based on the current position, the goal, and deltaTime * a scalar. (I don’t understand 100% how it works but am trying.)
I’m having an issue with position and velocity being applied even when a key isn’t being pressed. “rbVel.x + gravity * Time.deltaTime” is always applying a slight velocity to the rb.velocity because gravity is never 0. For some reason this doesn’t seem to be an issue with the C++ version, “box.vecVelocity = box.vecVelocity + box.vecGravity * dt;”. (Maybe it has something to do with the C++ version returning a “true” bool seemingly whenever a key is pressed? I’m not sure how that bool is used in the C++ Update method though.) If possible I’d like to know why this difference is (why the C++ version character isn’t constantly moving despite gravity always being added [u]vs C# character)[/u], but failing at that just some ideas for solutions. Should I just just use some bools to only let transform and velocity be affected when a key is pressed? (simple solution but I’m curious what the C++ version does different.)
Thanks for any info and help.
C++ portion from MathForGameDevelopers/game/main.cpp at lerping · BSVino/MathForGameDevelopers · GitHub :
bool CGame::KeyPress(int c)
{
if (c == 'W')
{
box.vecVelocityGoal.z = 15;
return true;
}
else if (c == 'A')
{
box.vecVelocityGoal.x = 15;
return true;
}
else if (c == 'S')
{
box.vecVelocityGoal.z = -15;
return true;
}
else if (c == 'D')
{
box.vecVelocityGoal.x = -15;
return true;
}
else if (c == ' ')
{
box.vecVelocity.y = 2;
return true;
}
else
return CApplication::KeyPress(c);
}
// This method gets called when the player releases a key.
void CGame::KeyRelease(int c)
{
if (c == 'W')
{
box.vecVelocityGoal.z = 0;
}
else if (c == 'A')
{
box.vecVelocityGoal.x = 0;
}
else if (c == 'S')
{
box.vecVelocityGoal.z = 0;
}
else if (c == 'D')
{
box.vecVelocityGoal.x = 0;
}
else
CApplication::KeyPress(c);
}
// In this Update() function we need to update all of our characters. Move them around or whatever we want to do.
void Update(float dt)
{
//Approach is called in a separate script; function is shown below
box.vecVelocity.x = Approach(box.vecVelocityGoal.x, box.vecVelocity.x, dt * 65);
box.vecVelocity.z = Approach(box.vecVelocityGoal.z, box.vecVelocity.z, dt * 65);
// Update position and vecVelocity.
box.vecPosition = box.vecPosition + box.vecVelocity * dt;
box.vecVelocity = box.vecVelocity + box.vecGravity * dt;
// Make sure the player doesn't fall through the floor. The y dimension is up/down, and the floor is at 0.
if (box.vecPosition.y < 0)
box.vecPosition.y = 0;
}
C++ “Approach” method in a different script:
float Approach(float flGoal, float flCurrent, float dt)
#pragma once
float Approach(float flGoal, float flCurrent, float dt)
{
float flDifference = flGoal - flCurrent;
if (flDifference > dt)
return flCurrent + dt;
if (flDifference < -dt)
return flCurrent - dt;
return flGoal;
}
My C# keyboard script (vecVelocityGoal is set here and used in interpolate script below):
//the velocity goal
[HideInInspector]
public Vector3 vecVelocityGoal;
public static bool keyDown = false;
//the fastest the player can move
public float topSpeedX = 10;
public float topSpeedZ = 10;
// Update is called once per frame
void Update()
{
//if moving left
if (Input.GetAxisRaw("Horizontal") < 0)
{
//set the fastest possible speed as negative
vecVelocityGoal.x = topSpeedX * -1;
}
//else if moving right
else if (Input.GetAxisRaw("Horizontal") > 0)
{
//set the fastest possible speed as positive
vecVelocityGoal.x = topSpeedX;
}
//if moving down
if (Input.GetAxisRaw("Vertical") < 0)
{
//set the fastest possible speed as negative (down)
vecVelocityGoal.z = topSpeedZ * -1;
}
//if moving up
else if (Input.GetAxisRaw("Vertical") > 0)
{
//set the fastest possible speed as positive (up)
vecVelocityGoal.z = topSpeedZ;
}
//if not moving left or right
if (Input.GetAxisRaw("Horizontal") == 0)
{
//set the fastest possible speed as unmoving
vecVelocityGoal.x = 0;
}
//if not moving up or down
if (Input.GetAxisRaw("Vertical") == 0)
{
//set the fastest possible speed as unmoving
vecVelocityGoal.z = 0;
}
}
My C# “SmoothMovementInterpolation” script:
public class EulerSmoothMovementInterpolation : MonoBehaviour {
EulerKeyboardControls kc;
float gravity = 4;
Rigidbody rb;
//scale the deltaTime by this (to speed up or slow interpolation)
float dtScaler = 35;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody>();
kc = GetComponent<EulerKeyboardControls>();
}
//interpolate up or down to the goal speed
float Approach(float goal, float current, float dt)
{
//how much left do we have to go before we reach our goal
float diff = goal - current;
//if dt is not enough to take us to our goal
if (diff > dt)
{
//return one step farther to our goal
return current + dt;
}
//if interpolating in the downward (on the graph) direction (ie, player is slowing down) and the difference is not enough for us to get to our goal
if (diff < -dt)
{
//return one step farther to our goal, in the downward/slowing direction
return current - dt;
}
//return goal if in range (previous returns will stop this return if need be)
return goal;
}
// Update is called once per frame
void Update()
{
//store velocity in a variable to access
Vector3 rbVel = rb.velocity;
float dt = Time.deltaTime;
if (dt > 0.15f)
dt = 0.15f;
//apply interpolation method and return x and z velocities and store in vars
rbVel.x = Approach(kc.vecVelocityGoal.x, rb.velocity.x, dt * dtScaler);
rbVel.z = Approach(kc.vecVelocityGoal.z, rb.velocity.z, dt * dtScaler);
//update position based on previous position + amount supposed to change * dt (to slow down)
transform.position = new Vector3(transform.position.x + rbVel.x * dt, transform.position.y, transform.position.z + rbVel.z * dt);
//update velocity based on the previous velocity + gravity * dt (to slow down)
rb.velocity = new Vector3(rbVel.x + gravity * dt, rb.velocity.y, rbVel.z + gravity * dt);
}
}