Implement sliding and crossing grid cell boundaries
This commit is contained in:
parent
ab9db26b9f
commit
eb0ee96f2f
@ -62,7 +62,11 @@ void rotate(Transform* transform, Vector axis, float angle) {
|
|||||||
*transform);
|
*transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector addVectors(Vector v1, Vector v2){
|
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 };
|
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);
|
float m = magnitude(vec);
|
||||||
return (Vector) { vec.x / m, vec.y / m, vec.z / m };
|
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));
|
||||||
|
}
|
||||||
|
@ -33,6 +33,7 @@ Transform identity();
|
|||||||
Transform multiply(Transform t1, Transform t2);
|
Transform multiply(Transform t1, Transform t2);
|
||||||
void translate(Transform* transform, Vector vec);
|
void translate(Transform* transform, Vector vec);
|
||||||
void rotate(Transform* transform, Vector axis, float angle);
|
void rotate(Transform* transform, Vector axis, float angle);
|
||||||
|
Vector zeroVector();
|
||||||
Vector addVectors(Vector v1, Vector v2);
|
Vector addVectors(Vector v1, Vector v2);
|
||||||
Vector subtractVectors(Vector v1, Vector v2);
|
Vector subtractVectors(Vector v1, Vector v2);
|
||||||
Vector crossProduct(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 applyTransform(Transform transform, Vector vec);
|
||||||
Vector translationOf(Transform transform);
|
Vector translationOf(Transform transform);
|
||||||
Vector normalized(Vector vec);
|
Vector normalized(Vector vec);
|
||||||
|
float clamp(float x, float lower, float upper);
|
||||||
|
|
||||||
#endif // ENGINE_GEOMETRY_H_
|
#endif // ENGINE_GEOMETRY_H_
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
|
|
||||||
#include "engine/asset.h"
|
#include "engine/asset.h"
|
||||||
|
#include "engine/logger.h"
|
||||||
#include "engine/render.h"
|
#include "engine/render.h"
|
||||||
|
|
||||||
#include "level.h"
|
#include "level.h"
|
||||||
@ -53,7 +54,7 @@ void spawnPlayer(Transform transform) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updatePlayer(float delta) {
|
void updatePlayer(float delta) {
|
||||||
Vector direction = { 0.0f, 0.0f, 0.0f };
|
Vector direction = zeroVector();
|
||||||
if (movementDirection & DIRECTION_UP) {
|
if (movementDirection & DIRECTION_UP) {
|
||||||
direction = addVectors(direction, worldMovementUp);
|
direction = addVectors(direction, worldMovementUp);
|
||||||
}
|
}
|
||||||
@ -90,83 +91,152 @@ Vector displacement = scaleVector(direction, 0.006944f * movementSpeed * 1000.0f
|
|||||||
Vector position = initialPosition;
|
Vector position = initialPosition;
|
||||||
|
|
||||||
GridLocation location = gridLocationFromPosition(position);
|
GridLocation location = gridLocationFromPosition(position);
|
||||||
Obstacle obstacle = getObstacles(location);
|
bool enteredNewCell = true;
|
||||||
|
|
||||||
// Eliminate redundant corner checks
|
while (enteredNewCell) {
|
||||||
if (obstacle & OBSTACLE_XP) {
|
enteredNewCell = false;
|
||||||
obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XP_ZN);
|
Obstacle obstacle = getObstacles(location);
|
||||||
}
|
|
||||||
if (obstacle & OBSTACLE_XN) {
|
|
||||||
obstacle &= ~(OBSTACLE_XN_ZP | OBSTACLE_XN_ZN);
|
|
||||||
}
|
|
||||||
if (obstacle & OBSTACLE_ZP) {
|
|
||||||
obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XN_ZP);
|
|
||||||
}
|
|
||||||
if (obstacle & OBSTACLE_ZN) {
|
|
||||||
obstacle &= ~(OBSTACLE_XP_ZN | OBSTACLE_XN_ZN);
|
|
||||||
}
|
|
||||||
|
|
||||||
float edgeXp = cellBoundaryCoord(location.x + 1);
|
// Eliminate redundant corner checks
|
||||||
float edgeXn = cellBoundaryCoord(location.x);
|
if (obstacle & OBSTACLE_XP) {
|
||||||
float edgeZp = cellBoundaryCoord(location.z + 1);
|
obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XP_ZN);
|
||||||
float edgeZn = cellBoundaryCoord(location.z);
|
}
|
||||||
float distanceXp = edgeXp - position.x;
|
if (obstacle & OBSTACLE_XN) {
|
||||||
if (obstacle & OBSTACLE_XP) distanceXp -= collisionRadius;
|
obstacle &= ~(OBSTACLE_XN_ZP | OBSTACLE_XN_ZN);
|
||||||
float distanceXn = edgeXn - position.x;
|
}
|
||||||
if (obstacle & OBSTACLE_XN) distanceXn += collisionRadius;
|
if (obstacle & OBSTACLE_ZP) {
|
||||||
float distanceZp = edgeZp - position.z;
|
obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XN_ZP);
|
||||||
if (obstacle & OBSTACLE_ZP) distanceZp -= collisionRadius;
|
}
|
||||||
float distanceZn = edgeZn - position.z;
|
if (obstacle & OBSTACLE_ZN) {
|
||||||
if (obstacle & OBSTACLE_ZN) distanceZn += collisionRadius;
|
obstacle &= ~(OBSTACLE_XP_ZN | OBSTACLE_XN_ZN);
|
||||||
|
}
|
||||||
|
|
||||||
// Check all edges for intersecting already
|
float edgeXp = cellBoundaryCoord(location.x + 1);
|
||||||
if (distanceXp < 0.0f) {
|
float edgeXn = cellBoundaryCoord(location.x);
|
||||||
position.x += distanceXp;
|
float edgeZp = cellBoundaryCoord(location.z + 1);
|
||||||
displacement = growVectorNoFlip(displacement, distanceXp);
|
float edgeZn = cellBoundaryCoord(location.z);
|
||||||
distanceXp = 0.0f;
|
float distanceXp = edgeXp - position.x;
|
||||||
}
|
if (obstacle & OBSTACLE_XP) distanceXp -= collisionRadius;
|
||||||
if (distanceXn > 0.0f) {
|
float distanceXn = edgeXn - position.x;
|
||||||
position.x += distanceXn;
|
if (obstacle & OBSTACLE_XN) distanceXn += collisionRadius;
|
||||||
displacement = growVectorNoFlip(displacement, - distanceXn);
|
float distanceZp = edgeZp - position.z;
|
||||||
distanceXn = 0.0f;
|
if (obstacle & OBSTACLE_ZP) distanceZp -= collisionRadius;
|
||||||
}
|
float distanceZn = edgeZn - position.z;
|
||||||
if (distanceZp < 0.0f) {
|
if (obstacle & OBSTACLE_ZN) distanceZn += collisionRadius;
|
||||||
position.z += distanceZp;
|
|
||||||
displacement = growVectorNoFlip(displacement, distanceZp);
|
|
||||||
distanceZp = 0.0f;
|
|
||||||
}
|
|
||||||
if (distanceZn > 0.0f) {
|
|
||||||
position.z += distanceZn;
|
|
||||||
displacement = growVectorNoFlip(displacement, - distanceZn);
|
|
||||||
distanceZn = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate direct movement limits
|
// Check all edges for intersecting already
|
||||||
float dx = displacement.x;
|
if (distanceXp < 0.0f) {
|
||||||
float dz = displacement.z;
|
position.x += distanceXp;
|
||||||
if (dx > distanceXp) {
|
displacement = growVectorNoFlip(displacement, distanceXp);
|
||||||
dz *= distanceXp / dx;
|
distanceXp = 0.0f;
|
||||||
dx = distanceXp;
|
}
|
||||||
// Might need a flag that we've reached a limit in X+?
|
if (distanceXn > 0.0f) {
|
||||||
|
position.x += distanceXn;
|
||||||
|
displacement = growVectorNoFlip(displacement, - distanceXn);
|
||||||
|
distanceXn = 0.0f;
|
||||||
|
}
|
||||||
|
if (distanceZp < 0.0f) {
|
||||||
|
position.z += distanceZp;
|
||||||
|
displacement = growVectorNoFlip(displacement, distanceZp);
|
||||||
|
distanceZp = 0.0f;
|
||||||
|
}
|
||||||
|
if (distanceZn > 0.0f) {
|
||||||
|
position.z += distanceZn;
|
||||||
|
displacement = growVectorNoFlip(displacement, - distanceZn);
|
||||||
|
distanceZn = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate direct movement limits
|
||||||
|
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 (displacementToLimit.x < distanceXn) {
|
||||||
|
displacementToLimit = scaleVector(
|
||||||
|
displacementToLimit, distanceXn / displacementToLimit.x);
|
||||||
|
reachedXn = true;
|
||||||
|
}
|
||||||
|
if (displacementToLimit.z > distanceZp) {
|
||||||
|
displacementToLimit = scaleVector(
|
||||||
|
displacementToLimit, distanceZp / displacementToLimit.z);
|
||||||
|
reachedZp = true;
|
||||||
|
}
|
||||||
|
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, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (dx < distanceXn) {
|
|
||||||
dz *= distanceXn / dx;
|
|
||||||
dx = distanceXn;
|
|
||||||
// ?
|
|
||||||
}
|
|
||||||
if (dz > distanceZp) {
|
|
||||||
dx *= distanceZp / dz;
|
|
||||||
dz = distanceZp;
|
|
||||||
// ?
|
|
||||||
}
|
|
||||||
if (dz < distanceZn) {
|
|
||||||
dx *= distanceZn / dz;
|
|
||||||
dz = distanceZn;
|
|
||||||
// ?
|
|
||||||
}
|
|
||||||
// This is how far we can move until we collide or leave the grid cell
|
|
||||||
position = addVectors(position, (Vector) { dx, 0.0f, dz });
|
|
||||||
translate(&playerProjectedMovement->transform, subtractVectors(position, initialPosition));
|
translate(&playerProjectedMovement->transform, subtractVectors(position, initialPosition));
|
||||||
|
|
||||||
|
//translate(&playerCharacter->transform, subtractVectors(position, initialPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user