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) {
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);
#include "geometry.h"
#include "performance.h"
+#include "game/player.h"
+
float viewportAspectRatio = 1.0f;
const Scene* cameraAnchor;
bool debugScene = false;
glDisable(GL_LIGHTING);
- if (debugScene) {
+ if (debugScene || scene == playerProjectedMovement) {
drawAxes();
}
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;
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;
+}
#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;
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];
grid.blocks[(z * grid.width) + x] = block;
}
+static inline float cellBoundaryCoord(size_t cellIndex) {
+ return cellIndex * BLOCKGRID_CELL_SIZE;
+}
+
#endif // LEVEL_H_
#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;
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) {
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);
typedef enum Direction Direction;
extern Scene* playerCharacter;
+extern Scene* playerProjectedMovement;
void initPlayer();
void spawnPlayer(Transform transform);