Implement sliding and crossing grid cell boundaries

This commit is contained in:
outfrost 2020-09-21 01:05:04 +02:00
parent ab9db26b9f
commit eb0ee96f2f
3 changed files with 153 additions and 73 deletions

View File

@ -62,6 +62,10 @@ void rotate(Transform* transform, Vector axis, float angle) {
*transform);
}
Vector zeroVector() {
return (Vector) { 0.0f, 0.0f, 0.0f };
}
Vector addVectors(Vector v1, Vector v2) {
return (Vector) { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
}
@ -130,3 +134,7 @@ Vector normalized(Vector vec) {
float m = magnitude(vec);
return (Vector) { vec.x / m, vec.y / m, vec.z / m };
}
float clamp(float x, float lower, float upper) {
return fmax(lower, fmin(upper, x));
}

View File

@ -33,6 +33,7 @@ Transform identity();
Transform multiply(Transform t1, Transform t2);
void translate(Transform* transform, Vector vec);
void rotate(Transform* transform, Vector axis, float angle);
Vector zeroVector();
Vector addVectors(Vector v1, Vector v2);
Vector subtractVectors(Vector v1, Vector v2);
Vector crossProduct(Vector v1, Vector v2);
@ -44,5 +45,6 @@ float magnitude(Vector vec);
Vector applyTransform(Transform transform, Vector vec);
Vector translationOf(Transform transform);
Vector normalized(Vector vec);
float clamp(float x, float lower, float upper);
#endif // ENGINE_GEOMETRY_H_

View File

@ -9,6 +9,7 @@
#include "player.h"
#include "engine/asset.h"
#include "engine/logger.h"
#include "engine/render.h"
#include "level.h"
@ -53,7 +54,7 @@ void spawnPlayer(Transform transform) {
}
void updatePlayer(float delta) {
Vector direction = { 0.0f, 0.0f, 0.0f };
Vector direction = zeroVector();
if (movementDirection & DIRECTION_UP) {
direction = addVectors(direction, worldMovementUp);
}
@ -90,6 +91,10 @@ Vector displacement = scaleVector(direction, 0.006944f * movementSpeed * 1000.0f
Vector position = initialPosition;
GridLocation location = gridLocationFromPosition(position);
bool enteredNewCell = true;
while (enteredNewCell) {
enteredNewCell = false;
Obstacle obstacle = getObstacles(location);
// Eliminate redundant corner checks
@ -142,31 +147,96 @@ Vector displacement = scaleVector(direction, 0.006944f * movementSpeed * 1000.0f
}
// Calculate direct movement limits
float dx = displacement.x;
float dz = displacement.z;
if (dx > distanceXp) {
dz *= distanceXp / dx;
dx = distanceXp;
// Might need a flag that we've reached a limit in X+?
Vector displacementToLimit = displacement;
bool reachedXp = false;
bool reachedXn = false;
bool reachedZp = false;
bool reachedZn = false;
if (displacementToLimit.x > distanceXp) {
displacementToLimit = scaleVector(
displacementToLimit, distanceXp / displacementToLimit.x);
reachedXp = true;
}
if (dx < distanceXn) {
dz *= distanceXn / dx;
dx = distanceXn;
// ?
if (displacementToLimit.x < distanceXn) {
displacementToLimit = scaleVector(
displacementToLimit, distanceXn / displacementToLimit.x);
reachedXn = true;
}
if (dz > distanceZp) {
dx *= distanceZp / dz;
dz = distanceZp;
// ?
if (displacementToLimit.z > distanceZp) {
displacementToLimit = scaleVector(
displacementToLimit, distanceZp / displacementToLimit.z);
reachedZp = true;
}
if (dz < distanceZn) {
dx *= distanceZn / dz;
dz = distanceZn;
// ?
if (displacementToLimit.z < distanceZn) {
displacementToLimit = scaleVector(
displacementToLimit, distanceZn / displacementToLimit.z);
reachedZn = true;
}
// This is how far we can move until we collide or leave the grid cell
position = addVectors(position, (Vector) { dx, 0.0f, dz });
position = addVectors(position, displacementToLimit);
displacement = subtractVectors(displacement, displacementToLimit);
// Update distances
distanceXp -= displacementToLimit.x;
distanceXn -= displacementToLimit.x;
distanceZp -= displacementToLimit.z;
distanceZn -= displacementToLimit.z;
// Resolve slides and crossing cell boundaries
// in reverse order to direct movement limits, because
// we only want to cross the closest cell boundary.
if (reachedZn) {
if (obstacle & OBSTACLE_ZN) {
float dx = clamp(displacement.x, distanceXn, distanceXp);
position.x += dx;
displacement = scaleVector(displacement, 1.0f - (dx / displacement.x));
}
else {
location.z -= 1;
enteredNewCell = true;
}
}
if (reachedZp) {
if (obstacle & OBSTACLE_ZP) {
float dx = clamp(displacement.x, distanceXn, distanceXp);
position.x += dx;
displacement = scaleVector(displacement, 1.0f - (dx / displacement.x));
}
else if (!enteredNewCell) {
location.z += 1;
enteredNewCell = true;
}
}
if (reachedXn) {
if (obstacle & OBSTACLE_XN) {
float dz = clamp(displacement.z, distanceZn, distanceZp);
position.z += dz;
displacement = scaleVector(displacement, 1.0f - (dz / displacement.z));
}
else if (!enteredNewCell) {
location.x -= 1;
enteredNewCell = true;
}
}
if (reachedXp) {
if (obstacle & OBSTACLE_XP) {
// Slide
float dz = clamp(displacement.z, distanceZn, distanceZp);
position.z += dz;
displacement = scaleVector(displacement, 1.0f - (dz / displacement.z));
}
else if (!enteredNewCell) {
// Enter new grid cell
location.x += 1;
enteredNewCell = true;
}
}
}
translate(&playerProjectedMovement->transform, subtractVectors(position, initialPosition));
//translate(&playerCharacter->transform, subtractVectors(position, initialPosition));
}