2 * Copyright 2019-2020 Iwo 'Outfrost' Bujkiewicz
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 #include "engine/asset.h"
12 #include "engine/logger.h"
13 #include "engine/render.h"
17 static const float movementSpeed = 0.5f;
18 static const float collisionRadius = 0.5f;
20 Scene* playerCharacter;
21 Scene* playerProjectedMovement;
22 static Transform screenToWorldMovementTransform;
23 static Vector worldMovementUp;
24 static Vector worldMovementDown;
25 static Vector worldMovementLeft;
26 static Vector worldMovementRight;
27 static Direction movementDirection;
29 static void movePlayer(Vector direction, float delta);
30 static Vector worldMovementDirection(float x, float y);
35 screenToWorldMovementTransform = identity();
36 rotate(&screenToWorldMovementTransform, (Vector) { 0.0f, 1.0f, 0.0f }, - TAU / 8.0f);
38 worldMovementUp = worldMovementDirection(0.0f, 1.0f);
39 worldMovementDown = worldMovementDirection(0.0f, -1.0f);
40 worldMovementLeft = worldMovementDirection(-1.0f, 0.0f);
41 worldMovementRight = worldMovementDirection(1.0f, 0.0f);
43 playerCharacter = newScene();
44 cameraAnchor = playerCharacter;
45 playerCharacter->solid = importSolid("assets/playercharacter.3ds");
47 playerProjectedMovement = newScene();
50 void spawnPlayer(Transform transform) {
51 playerCharacter->transform = transform;
52 reparentScene(playerCharacter, currentScene);
53 reparentScene(playerProjectedMovement, currentScene);
56 void updatePlayer(float delta) {
57 Vector direction = zeroVector();
58 if (movementDirection & DIRECTION_UP) {
59 direction = addVectors(direction, worldMovementUp);
61 if (movementDirection & DIRECTION_DOWN) {
62 direction = addVectors(direction, worldMovementDown);
64 if (movementDirection & DIRECTION_LEFT) {
65 direction = addVectors(direction, worldMovementLeft);
67 if (movementDirection & DIRECTION_RIGHT) {
68 direction = addVectors(direction, worldMovementRight);
70 movePlayer(direction, delta);
73 void startMovement(Direction direction) {
74 movementDirection |= direction;
77 void stopMovement(Direction direction) {
78 movementDirection &= ~direction;
81 static void movePlayer(Vector direction, float delta) {
82 direction = clampMagnitude(direction, 1.0f);
83 Vector displacement = scaleVector(direction, delta * movementSpeed);
86 Vector displacement = scaleVector(direction, 0.006944f * movementSpeed * 1000.0f);
88 playerProjectedMovement->transform = playerCharacter->transform;
90 Vector initialPosition = translationOf(playerCharacter->transform);
91 Vector position = initialPosition;
93 GridLocation location = gridLocationFromPosition(position);
94 bool enteredNewCell = true;
96 while (enteredNewCell) {
97 enteredNewCell = false;
98 Obstacle obstacle = getObstacles(location);
100 // Eliminate redundant corner checks
101 if (obstacle & OBSTACLE_XP) {
102 obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XP_ZN);
104 if (obstacle & OBSTACLE_XN) {
105 obstacle &= ~(OBSTACLE_XN_ZP | OBSTACLE_XN_ZN);
107 if (obstacle & OBSTACLE_ZP) {
108 obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XN_ZP);
110 if (obstacle & OBSTACLE_ZN) {
111 obstacle &= ~(OBSTACLE_XP_ZN | OBSTACLE_XN_ZN);
114 float edgeXp = cellBoundaryCoord(location.x + 1);
115 float edgeXn = cellBoundaryCoord(location.x);
116 float edgeZp = cellBoundaryCoord(location.z + 1);
117 float edgeZn = cellBoundaryCoord(location.z);
118 float distanceXp = edgeXp - position.x;
119 if (obstacle & OBSTACLE_XP) distanceXp -= collisionRadius;
120 float distanceXn = edgeXn - position.x;
121 if (obstacle & OBSTACLE_XN) distanceXn += collisionRadius;
122 float distanceZp = edgeZp - position.z;
123 if (obstacle & OBSTACLE_ZP) distanceZp -= collisionRadius;
124 float distanceZn = edgeZn - position.z;
125 if (obstacle & OBSTACLE_ZN) distanceZn += collisionRadius;
127 // Check all edges for intersecting already
128 if (distanceXp < 0.0f) {
129 position.x += distanceXp;
130 displacement = growVectorNoFlip(displacement, distanceXp);
133 if (distanceXn > 0.0f) {
134 position.x += distanceXn;
135 displacement = growVectorNoFlip(displacement, - distanceXn);
138 if (distanceZp < 0.0f) {
139 position.z += distanceZp;
140 displacement = growVectorNoFlip(displacement, distanceZp);
143 if (distanceZn > 0.0f) {
144 position.z += distanceZn;
145 displacement = growVectorNoFlip(displacement, - distanceZn);
149 // Calculate direct movement limits
150 Vector displacementToLimit = displacement;
151 bool reachedXp = false;
152 bool reachedXn = false;
153 bool reachedZp = false;
154 bool reachedZn = false;
155 if (displacementToLimit.x > distanceXp) {
156 displacementToLimit = scaleVector(
157 displacementToLimit, distanceXp / displacementToLimit.x);
160 if (displacementToLimit.x < distanceXn) {
161 displacementToLimit = scaleVector(
162 displacementToLimit, distanceXn / displacementToLimit.x);
165 if (displacementToLimit.z > distanceZp) {
166 displacementToLimit = scaleVector(
167 displacementToLimit, distanceZp / displacementToLimit.z);
170 if (displacementToLimit.z < distanceZn) {
171 displacementToLimit = scaleVector(
172 displacementToLimit, distanceZn / displacementToLimit.z);
175 // This is how far we can move until we collide or leave the grid cell
176 position = addVectors(position, displacementToLimit);
177 displacement = subtractVectors(displacement, displacementToLimit);
179 distanceXp -= displacementToLimit.x;
180 distanceXn -= displacementToLimit.x;
181 distanceZp -= displacementToLimit.z;
182 distanceZn -= displacementToLimit.z;
184 // Resolve slides and crossing cell boundaries
185 // in reverse order to direct movement limits, because
186 // we only want to cross the closest cell boundary.
188 if (obstacle & OBSTACLE_ZN) {
189 float dx = clamp(displacement.x, distanceXn, distanceXp);
191 displacement = scaleVector(displacement, 1.0f - (dx / displacement.x));
195 enteredNewCell = true;
200 if (obstacle & OBSTACLE_ZP) {
201 float dx = clamp(displacement.x, distanceXn, distanceXp);
203 displacement = scaleVector(displacement, 1.0f - (dx / displacement.x));
205 else if (!enteredNewCell) {
207 enteredNewCell = true;
212 if (obstacle & OBSTACLE_XN) {
213 float dz = clamp(displacement.z, distanceZn, distanceZp);
215 displacement = scaleVector(displacement, 1.0f - (dz / displacement.z));
217 else if (!enteredNewCell) {
219 enteredNewCell = true;
224 if (obstacle & OBSTACLE_XP) {
226 float dz = clamp(displacement.z, distanceZn, distanceZp);
228 displacement = scaleVector(displacement, 1.0f - (dz / displacement.z));
230 else if (!enteredNewCell) {
231 // Enter new grid cell
233 enteredNewCell = true;
237 translate(&playerProjectedMovement->transform, subtractVectors(position, initialPosition));
239 //translate(&playerCharacter->transform, subtractVectors(position, initialPosition));
243 translate(&playerCharacter->transform, displacement);
246 static Vector worldMovementDirection(float x, float y) {
247 Vector direction = (Vector) { x, 0.0f, -y };
248 direction = normalized(
249 applyTransform(screenToWorldMovementTransform, direction));