]> git.lizzy.rs Git - shadowclad.git/blob - src/game/player.c
52d747f96c3f31d320227dc0bacc774e732f2c05
[shadowclad.git] / src / game / player.c
1 /**
2  * Copyright 2019-2020 Iwo 'Outfrost' Bujkiewicz
3  *
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/.
7  */
8
9 #include "player.h"
10
11 #include "engine/asset.h"
12 #include "engine/logger.h"
13 #include "engine/render.h"
14
15 #include "level.h"
16
17 static const float movementSpeed = 1.5f;
18 static const float collisionRadius = 0.5f;
19
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;
28
29 static void movePlayer(Vector direction, float delta);
30 static Vector worldMovementDirection(float x, float y);
31
32
33
34 void initPlayer() {
35         screenToWorldMovementTransform = identity();
36         rotate(&screenToWorldMovementTransform, (Vector) { 0.0f, 1.0f, 0.0f }, - TAU / 8.0f);
37
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);
42
43         playerCharacter = newScene();
44         cameraAnchor = playerCharacter;
45         playerCharacter->solid = importSolid("assets/playercharacter.3ds");
46
47         playerProjectedMovement = newScene();
48 }
49
50 void spawnPlayer(Transform transform) {
51         playerCharacter->transform = transform;
52         reparentScene(playerCharacter, currentScene);
53         reparentScene(playerProjectedMovement, currentScene);
54 }
55
56 void updatePlayer(float delta) {
57         Vector direction = zeroVector();
58         if (movementDirection & DIRECTION_UP) {
59                 direction = addVectors(direction, worldMovementUp);
60         }
61         if (movementDirection & DIRECTION_DOWN) {
62                 direction = addVectors(direction, worldMovementDown);
63         }
64         if (movementDirection & DIRECTION_LEFT) {
65                 direction = addVectors(direction, worldMovementLeft);
66         }
67         if (movementDirection & DIRECTION_RIGHT) {
68                 direction = addVectors(direction, worldMovementRight);
69         }
70         movePlayer(direction, delta);
71 }
72
73 void startMovement(Direction direction) {
74         movementDirection |= direction;
75 }
76
77 void stopMovement(Direction direction) {
78         movementDirection &= ~direction;
79 }
80
81 static void movePlayer(Vector direction, float delta) {
82         direction = clampMagnitude(direction, 1.0f);
83         Vector displacement = scaleVector(direction, delta * movementSpeed);
84
85 //{
86 //Vector displacement = scaleVector(direction, 0.006944f * movementSpeed * 1000.0f);
87
88         playerProjectedMovement->transform = playerCharacter->transform;
89
90         Vector initialPosition = translationOf(playerCharacter->transform);
91         Vector position = initialPosition;
92
93         GridLocation location = gridLocationFromPosition(position);
94         bool enteredNewCell = true;
95
96         while (enteredNewCell) {
97                 enteredNewCell = false;
98                 Obstacle obstacle = getObstacles(location);
99
100                 // Eliminate redundant corner checks
101                 if (obstacle & OBSTACLE_XP) {
102                         obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XP_ZN);
103                 }
104                 if (obstacle & OBSTACLE_XN) {
105                         obstacle &= ~(OBSTACLE_XN_ZP | OBSTACLE_XN_ZN);
106                 }
107                 if (obstacle & OBSTACLE_ZP) {
108                         obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XN_ZP);
109                 }
110                 if (obstacle & OBSTACLE_ZN) {
111                         obstacle &= ~(OBSTACLE_XP_ZN | OBSTACLE_XN_ZN);
112                 }
113
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;
126
127                 // Check all edges for intersecting already
128                 if (distanceXp < 0.0f) {
129                         position.x += distanceXp;
130                         displacement = growVectorNoFlip(displacement, distanceXp);
131                         distanceXp = 0.0f;
132                 }
133                 if (distanceXn > 0.0f) {
134                         position.x += distanceXn;
135                         displacement = growVectorNoFlip(displacement, - distanceXn);
136                         distanceXn = 0.0f;
137                 }
138                 if (distanceZp < 0.0f) {
139                         position.z += distanceZp;
140                         displacement = growVectorNoFlip(displacement, distanceZp);
141                         distanceZp = 0.0f;
142                 }
143                 if (distanceZn > 0.0f) {
144                         position.z += distanceZn;
145                         displacement = growVectorNoFlip(displacement, - distanceZn);
146                         distanceZn = 0.0f;
147                 }
148
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);
158                         reachedXp = true;
159                 }
160                 if (displacementToLimit.x < distanceXn) {
161                         displacementToLimit = scaleVector(
162                                 displacementToLimit, distanceXn / displacementToLimit.x);
163                         reachedXn = true;
164                 }
165                 if (displacementToLimit.z > distanceZp) {
166                         displacementToLimit = scaleVector(
167                                 displacementToLimit, distanceZp / displacementToLimit.z);
168                         reachedZp = true;
169                 }
170                 if (displacementToLimit.z < distanceZn) {
171                         displacementToLimit = scaleVector(
172                                 displacementToLimit, distanceZn / displacementToLimit.z);
173                         reachedZn = true;
174                 }
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);
178                 // Update distances
179                 distanceXp -= displacementToLimit.x;
180                 distanceXn -= displacementToLimit.x;
181                 distanceZp -= displacementToLimit.z;
182                 distanceZn -= displacementToLimit.z;
183
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.
187                 if (reachedZn) {
188                         if (obstacle & OBSTACLE_ZN) {
189                                 float dx = clamp(displacement.x, distanceXn, distanceXp);
190                                 position.x += dx;
191                                 displacement = scaleVector(displacement, 1.0f - (dx / displacement.x));
192                         }
193                         else {
194                                 location.z -= 1;
195                                 enteredNewCell = true;
196                         }
197                 }
198
199                 if (reachedZp) {
200                         if (obstacle & OBSTACLE_ZP) {
201                                 float dx = clamp(displacement.x, distanceXn, distanceXp);
202                                 position.x += dx;
203                                 displacement = scaleVector(displacement, 1.0f - (dx / displacement.x));
204                         }
205                         else if (!enteredNewCell) {
206                                 location.z += 1;
207                                 enteredNewCell = true;
208                         }
209                 }
210
211                 if (reachedXn) {
212                         if (obstacle & OBSTACLE_XN) {
213                                 float dz = clamp(displacement.z, distanceZn, distanceZp);
214                                 position.z += dz;
215                                 displacement = scaleVector(displacement, 1.0f - (dz / displacement.z));
216                         }
217                         else if (!enteredNewCell) {
218                                 location.x -= 1;
219                                 enteredNewCell = true;
220                         }
221                 }
222
223                 if (reachedXp) {
224                         if (obstacle & OBSTACLE_XP) {
225                                 // Slide
226                                 float dz = clamp(displacement.z, distanceZn, distanceZp);
227                                 position.z += dz;
228                                 displacement = scaleVector(displacement, 1.0f - (dz / displacement.z));
229                         }
230                         else if (!enteredNewCell) {
231                                 // Enter new grid cell
232                                 location.x += 1;
233                                 enteredNewCell = true;
234                         }
235                 }
236         }
237         //translate(&playerProjectedMovement->transform, subtractVectors(position, initialPosition));
238
239         translate(&playerCharacter->transform, subtractVectors(position, initialPosition));
240 //}
241
242
243         //translate(&playerCharacter->transform, displacement);
244 }
245
246 static Vector worldMovementDirection(float x, float y) {
247         Vector direction = (Vector) { x, 0.0f, -y };
248         direction = normalized(
249                 applyTransform(screenToWorldMovementTransform, direction));
250         return direction;
251 }