]> git.lizzy.rs Git - shadowclad.git/commitdiff
Implement first stage of obstacle detection
authoroutfrost <kotlet.bahn@gmail.com>
Thu, 16 Jul 2020 01:15:20 +0000 (03:15 +0200)
committeroutfrost <kotlet.bahn@gmail.com>
Thu, 16 Jul 2020 01:15:20 +0000 (03:15 +0200)
src/engine/geometry.c
src/engine/geometry.h
src/engine/render.c
src/game/level.c
src/game/level.h
src/game/player.c
src/game/player.h

index ae224b133ab3ef3ae9e13276cd2bbb69c4f2fa29..c37eb4aecaa60ad8f1df2f5b75593ef3e8d4d264 100644 (file)
@@ -78,6 +78,15 @@ Vector scaleVector(Vector vec, float scale) {
                          vec.z * scale };
 }
 
+Vector growVectorNoFlip(Vector vec, float amount) {
+       float mag = magnitude(vec);
+       float factor = (mag + amount) / mag;
+       if (factor < 0.0f) {
+               factor = 0.0f;
+       }
+       return scaleVector(vec, factor);
+}
+
 Vector clampMagnitude(Vector vec, float maxMagnitude) {
        float m = magnitude(vec);
        if (m > maxMagnitude) {
index e23a75a159f5ff9169074f99dfee3b1d9e9ab7dc..38dd5e6b9ce6ae5597509deaf5d3b66a8987c923 100644 (file)
@@ -30,6 +30,7 @@ Vector subtractVectors(Vector v1, Vector v2);
 Vector crossProduct(Vector v1, Vector v2);
 float dotProduct(Vector v1, Vector v2);
 Vector scaleVector(Vector vec, float scale);
+Vector growVectorNoFlip(Vector vec, float amount);
 Vector clampMagnitude(Vector vec, float maxMagnitude);
 float magnitude(Vector vec);
 Vector applyTransform(Transform transform, Vector vec);
index 4188755d3fa51482ff7287a6bd51338c2e6c029e..616b971ce14e4c3fc067796b0a94cbfa81c2cfdc 100644 (file)
@@ -3,6 +3,8 @@
 #include "geometry.h"
 #include "performance.h"
 
+#include "game/player.h"
+
 float viewportAspectRatio = 1.0f;
 const Scene* cameraAnchor;
 bool debugScene = false;
@@ -67,7 +69,7 @@ static void renderScene(const Scene* scene, const Transform baseTransform) {
 
        glDisable(GL_LIGHTING);
 
-       if (debugScene) {
+       if (debugScene || scene == playerProjectedMovement) {
                drawAxes();
        }
 
index c814e4e48588f68b946712c5a035e08c5246f057..b9a6b5884ec16b72bceaf0bfb64b45510cc90f05 100644 (file)
 
 BlockGrid levelGrid;
 
-static const float BLOCKGRID_CELL_SIZE = 2.5f;
-
 static Block blockEmpty = { .type = BLOCKTYPE_SPACE,
                             .solid = NULL };
-static Block blockWall01 = { .type = BLOCKTYPE_OBSTACLE,
+static Block blockWall01 = { .type = BLOCKTYPE_OBSTACLE_X | BLOCKTYPE_OBSTACLE_Z,
                              .solid = NULL };
 
 static Transform playerSpawnTransform;
@@ -106,8 +104,61 @@ static inline size_t nonNegative(long n) {
        return n < 0 ? 0u : n;
 }
 
-GridLocation gridLocationFromTransform(Transform transform) {
-       Vector scaledPos = scaleVector(translationOf(transform), 1.0f / BLOCKGRID_CELL_SIZE);
+GridLocation gridLocationFromPosition(Vector pos) {
+       Vector scaledPos = scaleVector(pos, 1.0f / BLOCKGRID_CELL_SIZE);
        return (GridLocation) { .x = nonNegative(scaledPos.x),
                                .z = nonNegative(scaledPos.z) };
 }
+
+Obstacle getObstacles(GridLocation loc) {
+       Obstacle result = OBSTACLE_NONE;
+       if (loc.x == 0) {
+               result |= OBSTACLE_XN | OBSTACLE_XN_ZP | OBSTACLE_XN_ZN;
+       }
+       if (loc.x >= levelGrid.width - 1) {
+               result |= OBSTACLE_XP | OBSTACLE_XP_ZP | OBSTACLE_XP_ZN;
+       }
+       if (loc.z == 0) {
+               result |= OBSTACLE_ZN | OBSTACLE_XP_ZN | OBSTACLE_XN_ZN;
+       }
+       if (loc.z >= levelGrid.depth - 1) {
+               result |= OBSTACLE_ZP | OBSTACLE_XP_ZP | OBSTACLE_XN_ZP;
+       }
+       if (!(result & OBSTACLE_XP)
+           && getBlockFromGrid(levelGrid, loc.x + 1, loc.z)->type & BLOCKTYPE_OBSTACLE_X) {
+               result |= OBSTACLE_XP;
+       }
+       if (!(result & OBSTACLE_XN)
+           && getBlockFromGrid(levelGrid, loc.x - 1, loc.z)->type & BLOCKTYPE_OBSTACLE_X) {
+               result |= OBSTACLE_XN;
+       }
+       if (!(result & OBSTACLE_ZP)
+           && getBlockFromGrid(levelGrid, loc.x, loc.z + 1)->type & BLOCKTYPE_OBSTACLE_Z) {
+               result |= OBSTACLE_ZP;
+       }
+       if (!(result & OBSTACLE_ZN)
+           && getBlockFromGrid(levelGrid, loc.x, loc.z - 1)->type & BLOCKTYPE_OBSTACLE_Z) {
+               result |= OBSTACLE_ZN;
+       }
+       if (!(result & OBSTACLE_XP_ZP)
+           && getBlockFromGrid(levelGrid, loc.x + 1, loc.z + 1)->type
+              & (BLOCKTYPE_OBSTACLE_X | BLOCKTYPE_OBSTACLE_Z)) {
+               result |= OBSTACLE_XP_ZP;
+       }
+       if (!(result & OBSTACLE_XP_ZN)
+           && getBlockFromGrid(levelGrid, loc.x + 1, loc.z - 1)->type
+              & (BLOCKTYPE_OBSTACLE_X | BLOCKTYPE_OBSTACLE_Z)) {
+               result |= OBSTACLE_XP_ZN;
+       }
+       if (!(result & OBSTACLE_XN_ZP)
+           && getBlockFromGrid(levelGrid, loc.x - 1, loc.z + 1)->type
+              & (BLOCKTYPE_OBSTACLE_X | BLOCKTYPE_OBSTACLE_Z)) {
+               result |= OBSTACLE_XN_ZP;
+       }
+       if (!(result & OBSTACLE_XN_ZN)
+           && getBlockFromGrid(levelGrid, loc.x - 1, loc.z - 1)->type
+              & (BLOCKTYPE_OBSTACLE_X | BLOCKTYPE_OBSTACLE_Z)) {
+               result |= OBSTACLE_XN_ZN;
+       }
+       return result;
+}
index 3ce8241f8a85b33e060ffa63182bd716c631e589..cca8a8e469202e0a54e8c52a8486c4ac80e7f062 100644 (file)
@@ -6,13 +6,25 @@
 #include "engine/asset.h"
 
 enum BlockType {
-       BLOCKTYPE_SPACE,
-       BLOCKTYPE_OBSTACLE_X,
-       BLOCKTYPE_OBSTACLE_Z,
-       BLOCKTYPE_OBSTACLE
+       BLOCKTYPE_SPACE = 0,
+       BLOCKTYPE_OBSTACLE_X = 1 << 0,
+       BLOCKTYPE_OBSTACLE_Z = 1 << 1
+};
+
+enum Obstacle {
+       OBSTACLE_NONE = 0,
+       OBSTACLE_XP = 1 << 0,
+       OBSTACLE_XN = 1 << 1,
+       OBSTACLE_ZP = 1 << 2,
+       OBSTACLE_ZN = 1 << 3,
+       OBSTACLE_XP_ZP = 1 << 4,
+       OBSTACLE_XP_ZN = 1 << 5,
+       OBSTACLE_XN_ZP = 1 << 6,
+       OBSTACLE_XN_ZN = 1 << 7
 };
 
 typedef enum BlockType BlockType;
+typedef enum Obstacle Obstacle;
 typedef struct Block Block;
 typedef struct BlockGrid BlockGrid;
 typedef struct GridLocation GridLocation;
@@ -33,11 +45,14 @@ struct GridLocation {
        size_t z;
 };
 
+static const float BLOCKGRID_CELL_SIZE = 2.5f;
+
 extern BlockGrid levelGrid;
 
 void initLevel();
 void startLevel();
-GridLocation gridLocationFromTransform(Transform transform);
+GridLocation gridLocationFromPosition(Vector pos);
+Obstacle getObstacles(GridLocation loc);
 
 static inline Block* getBlockFromGrid(BlockGrid grid, size_t x, size_t z) {
        return grid.blocks[(z * grid.width) + x];
@@ -47,4 +62,8 @@ static inline void setBlockInGrid(BlockGrid grid, size_t x, size_t z, Block* blo
        grid.blocks[(z * grid.width) + x] = block;
 }
 
+static inline float cellBoundaryCoord(size_t cellIndex) {
+       return cellIndex * BLOCKGRID_CELL_SIZE;
+}
+
 #endif // LEVEL_H_
index f5dcac79e84aae2a2889fff0634b8e767ea316c8..636b130603dfc820218d5898150bad36af2049f2 100644 (file)
@@ -5,9 +5,11 @@
 
 #include "level.h"
 
-static const float movementSpeed = 2.5f;
+static const float movementSpeed = 0.5f;
+static const float collisionRadius = 0.5f;
 
 Scene* playerCharacter;
+Scene* playerProjectedMovement;
 static Transform screenToWorldMovementTransform;
 static Vector worldMovementUp;
 static Vector worldMovementDown;
@@ -32,11 +34,14 @@ void initPlayer() {
        playerCharacter = newScene();
        cameraAnchor = playerCharacter;
        playerCharacter->solid = importSolid("assets/playercharacter.3ds");
+
+       playerProjectedMovement = newScene();
 }
 
 void spawnPlayer(Transform transform) {
        playerCharacter->transform = transform;
        reparentScene(playerCharacter, currentScene);
+       reparentScene(playerProjectedMovement, currentScene);
 }
 
 void updatePlayer(float delta) {
@@ -68,21 +73,93 @@ static void movePlayer(Vector direction, float delta) {
        direction = clampMagnitude(direction, 1.0f);
        Vector displacement = scaleVector(direction, delta * movementSpeed);
 
+{
+Vector displacement = scaleVector(direction, 0.006944f * movementSpeed * 1000.0f);
+
+       playerProjectedMovement->transform = playerCharacter->transform;
+
+       Vector initialPosition = translationOf(playerCharacter->transform);
+       Vector position = initialPosition;
+
+       GridLocation location = gridLocationFromPosition(position);
+       Obstacle obstacle = getObstacles(location);
+
+       // Eliminate redundant corner checks
+       if (obstacle & OBSTACLE_XP) {
+               obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XP_ZN);
+       }
+       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);
+       }
 
-       //GridLocation location = gridLocationFromTransform(playerCharacter->transform);
+       float edgeXp = cellBoundaryCoord(location.x + 1);
+       float edgeXn = cellBoundaryCoord(location.x);
+       float edgeZp = cellBoundaryCoord(location.z + 1);
+       float edgeZn = cellBoundaryCoord(location.z);
+       float distanceXp = edgeXp - position.x;
+       if (obstacle & OBSTACLE_XP) distanceXp -= collisionRadius;
+       float distanceXn = edgeXn - position.x;
+       if (obstacle & OBSTACLE_XN) distanceXn += collisionRadius;
+       float distanceZp = edgeZp - position.z;
+       if (obstacle & OBSTACLE_ZP) distanceZp -= collisionRadius;
+       float distanceZn = edgeZn - position.z;
+       if (obstacle & OBSTACLE_ZN) distanceZn += collisionRadius;
+
+       // Check all edges for intersecting already
+       if (distanceXp < 0.0f) {
+               position.x += distanceXp;
+               displacement = growVectorNoFlip(displacement, distanceXp);
+               distanceXp = 0.0f;
+       }
+       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;
+       }
 
-       if (displacement.x >= 0) {
-               // need to test +X edge
+       // 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+?
        }
-       if (displacement.x <= 0) {
-               // need to test -X edge
+       if (dx < distanceXn) {
+               dz *= distanceXn / dx;
+               dx = distanceXn;
+               // ?
        }
-       if (displacement.z >= 0) {
-               // need to test +Z edge
+       if (dz > distanceZp) {
+               dx *= distanceZp / dz;
+               dz = distanceZp;
+               // ?
        }
-       if (displacement.z <= 0) {
-               // need to test -Z edge
+       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(&playerCharacter->transform, displacement);
index 216e676ce5e5c33ccf092d7d213465fb7ac4b77d..2515d1da4538f1596559f157f1f2f7543f1e0eb5 100644 (file)
@@ -15,6 +15,7 @@ enum Direction {
 typedef enum Direction Direction;
 
 extern Scene* playerCharacter;
+extern Scene* playerProjectedMovement;
 
 void initPlayer();
 void spawnPlayer(Transform transform);