I recently started rewriting my engine from scratch, because the old one was my first attempt and the structure was very messy. Everything has been going great, but now I'm being held back by some stuff related to character movement and collision detection.
So, I wanted to remake the character movement with acceleration and deceleration physics. I got it working fine, but I didn't use gameTime.ElapsedGameTime.TotalSeconds. Now it would seem to be complicated and messy to add it to all the places where I use velocity, Acceleration, and Deceleration
What I'm wondering is that, is it worth it to even use gameTime at all? I think I've read in many posts and tutorials that using gameTime is best practice because then movement isn't coupled to frame rate. And if it is worth using it, how would you implement it in such a system along with acceleration and normalizing for diagonal movement?
I wouldn't mind restructuring the code at all, but I just don't know where to start from. I've been thinking about and trying to solve this issue for so long and I don't know what to do. It's draining all my motivation :( If you notice any other improvements here, feel free to mention. Thanks.
Here is the movement code:
private void UpdateMovement(List<GameObject> objects) {
if (velocity != Vector2.Zero){
if (SimpleCollisionCheck(objects, out GameObject obj) == true) {
DirectionalCollisionCheck(obj);
}
}
position += velocity;
if (velocity.X > 0) { // Decrease X velocity over time
if (velocity.X - Deceleration > 0) { velocity.X -= Deceleration; } else { velocity.X = 0; }
} else if (velocity.X < 0) {
if (velocity.X + Deceleration < 0) { velocity.X += Deceleration; } else { velocity.X = 0; }
}
if (velocity.Y > 0) { // Decrease Y velocity over time
if (velocity.Y - Deceleration > 0) { velocity.Y -= Deceleration; } else { velocity.Y = 0; }
} else if (velocity.Y < 0) {
if (velocity.Y + Deceleration < 0) { velocity.Y += Deceleration; } else { velocity.Y = 0; }
}
}
protected void MoveLeft() {
if (velocity.X - Acceleration > -VelocityMaximum) { velocity.X -= Acceleration + Deceleration; }
direction.X = -1;
}
protected void MoveRight() {
if (velocity.X + Acceleration < VelocityMaximum) { velocity.X += Acceleration + Deceleration; }
direction.X = 1;
}
protected void MoveUp() {
if (velocity.Y - Acceleration > -VelocityMaximum) { velocity.Y -= Acceleration + Deceleration; }
direction.Y = -1;
}
protected void MoveDown() {
if (velocity.Y + Acceleration < VelocityMaximum) { velocity.Y += Acceleration + Deceleration; }
direction.Y = 1;
}
Here is the collision code:
protected bool SimpleCollisionCheck(List<GameObject> objects, out GameObject obj) {
Rectangle futureCollision = Collision;
if (Velocity.X != 0) {
if (Velocity.X > 0) { futureCollision.X += (int)VelocityMaximum; } else { futureCollision.X -= (int)VelocityMaximum; }
}
if (Velocity.Y != 0) {
if (Velocity.Y > 0) { futureCollision.Y += (int)VelocityMaximum; } else { futureCollision.Y -= (int)VelocityMaximum; }
}
foreach (GameObject o in objects) {
if (o != this && o.Active == true && o.CollisionEnabled == true && o.CollisionCheck(futureCollision) == true) {
obj = o;
return true;
}
}
obj = null;
return false;
}
private bool CollisionLeft(GameObject o) {
return ((Collision.Left - VelocityMaximum) < o.Collision.Right) &&
(Collision.Right >= o.Collision.Right) &&
(Collision.Top < o.Collision.Bottom) &&
(Collision.Bottom > o.Collision.Top);
}
private bool CollisionRight(GameObject o) {
return ((Collision.Right + VelocityMaximum) > o.Collision.Left) &&
(Collision.Left <= o.Collision.Left) &&
(Collision.Top < o.Collision.Bottom) &&
(Collision.Bottom > o.Collision.Top);
}
private bool CollisionUp(GameObject o) {
return ((Collision.Top - VelocityMaximum) < o.Collision.Bottom) &&
(Collision.Bottom >= o.Collision.Bottom) &&
(Collision.Left < o.Collision.Right) &&
(Collision.Right > o.Collision.Left);
}
private bool CollisionDown(GameObject o) {
return ((Collision.Bottom + VelocityMaximum) > o.Collision.Top) &&
(Collision.Top <= o.Collision.Top) &&
(Collision.Left < o.Collision.Right) &&
(Collision.Right > o.Collision.Left);
}
private void DirectionalCollisionCheck(GameObject o) {
if (velocity.X < 0.0f && CollisionLeft(o)) {
if (CollisionNudgeEnabled && o.CollisionNudgeEnabled) {
if ((PositionCentered.Y /*- CollisionThickness*/) < (o.Collision.Top - collisionNudgeOffset)) {
velocity.Y = velocity.X;
} else if ((PositionCentered.Y /*+ CollisionThickness*/) > (o.Collision.Bottom + collisionNudgeOffset)) {
velocity.Y = -velocity.X;
}
}
velocity.X = 0.0f;
} else if (velocity.X > 0.0f && CollisionRight(o)) {
if (CollisionNudgeEnabled && o.CollisionNudgeEnabled) {
if ((PositionCentered.Y /*- CollisionThickness*/) < (o.Collision.Top - collisionNudgeOffset)) {
velocity.Y = -velocity.X;
} else if ((PositionCentered.Y /*+ CollisionThickness*/) > (o.Collision.Bottom + collisionNudgeOffset)) {
velocity.Y = velocity.X;
}
}
velocity.X = 0.0f;
}
if (velocity.Y < 0.0f && CollisionUp(o)) {
if (CollisionNudgeEnabled && o.CollisionNudgeEnabled) {
if (PositionCentered.X < (o.Collision.Left - collisionNudgeOffset)) {
velocity.X = velocity.Y;
} else if (PositionCentered.X > (o.Collision.Right + collisionNudgeOffset)) {
velocity.X = -velocity.Y;
}
}
velocity.Y = 0.0f;
} else if (velocity.Y > 0.0f && CollisionDown(o)) {
if (CollisionNudgeEnabled && o.CollisionNudgeEnabled) {
if (PositionCentered.X < (o.Collision.Left - collisionNudgeOffset)) {
velocity.X = -velocity.Y;
} else if (PositionCentered.X > (o.Collision.Right + collisionNudgeOffset)) {
velocity.X = velocity.Y;
}
}
velocity.Y = 0.0f;
}
}
UPDATE:
So, I broke out some old physics formula books and had some sort of a revelation. I added updateTime = (float)gameTime.ElapsedGameTime.TotalSeconds; into the main update function of the character and changed the following code and now it seems to work (?):
private float accelDistance = 20f;
private float decelDistance = 60f;
public float VelocityMaximum = 180f;
private float updateTime;
public float Acceleration { protected get { return accelDistance * updateTime; } set { accelDistance = value; } }
public float Deceleration { protected get { return decelDistance * updateTime; } set { decelDistance = value; } }
public float VelocityMaximum{ protected get { return velocityMaximum * updateTime; } set { velocityMaximum= value; } }
Now there is still the diagonal normalization to implement...