]> git.lizzy.rs Git - shadowclad.git/blob - src/game/player.c
Add copyright and license notices in source code
[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/render.h"
13
14 #include "level.h"
15
16 static const float movementSpeed = 0.5f;
17 static const float collisionRadius = 0.5f;
18
19 Scene* playerCharacter;
20 Scene* playerProjectedMovement;
21 static Transform screenToWorldMovementTransform;
22 static Vector worldMovementUp;
23 static Vector worldMovementDown;
24 static Vector worldMovementLeft;
25 static Vector worldMovementRight;
26 static Direction movementDirection;
27
28 static void movePlayer(Vector direction, float delta);
29 static Vector worldMovementDirection(float x, float y);
30
31
32
33 void initPlayer() {
34         screenToWorldMovementTransform = identity();
35         rotate(&screenToWorldMovementTransform, (Vector) { 0.0f, 1.0f, 0.0f }, - TAU / 8.0f);
36
37         worldMovementUp = worldMovementDirection(0.0f, 1.0f);
38         worldMovementDown = worldMovementDirection(0.0f, -1.0f);
39         worldMovementLeft = worldMovementDirection(-1.0f, 0.0f);
40         worldMovementRight = worldMovementDirection(1.0f, 0.0f);
41
42         playerCharacter = newScene();
43         cameraAnchor = playerCharacter;
44         playerCharacter->solid = importSolid("assets/playercharacter.3ds");
45
46         playerProjectedMovement = newScene();
47 }
48
49 void spawnPlayer(Transform transform) {
50         playerCharacter->transform = transform;
51         reparentScene(playerCharacter, currentScene);
52         reparentScene(playerProjectedMovement, currentScene);
53 }
54
55 void updatePlayer(float delta) {
56         Vector direction = { 0.0f, 0.0f, 0.0f };
57         if (movementDirection & DIRECTION_UP) {
58                 direction = addVectors(direction, worldMovementUp);
59         }
60         if (movementDirection & DIRECTION_DOWN) {
61                 direction = addVectors(direction, worldMovementDown);
62         }
63         if (movementDirection & DIRECTION_LEFT) {
64                 direction = addVectors(direction, worldMovementLeft);
65         }
66         if (movementDirection & DIRECTION_RIGHT) {
67                 direction = addVectors(direction, worldMovementRight);
68         }
69         movePlayer(direction, delta);
70 }
71
72 void startMovement(Direction direction) {
73         movementDirection |= direction;
74 }
75
76 void stopMovement(Direction direction) {
77         movementDirection &= ~direction;
78 }
79
80 static void movePlayer(Vector direction, float delta) {
81         direction = clampMagnitude(direction, 1.0f);
82         Vector displacement = scaleVector(direction, delta * movementSpeed);
83
84 {
85 Vector displacement = scaleVector(direction, 0.006944f * movementSpeed * 1000.0f);
86
87         playerProjectedMovement->transform = playerCharacter->transform;
88
89         Vector initialPosition = translationOf(playerCharacter->transform);
90         Vector position = initialPosition;
91
92         GridLocation location = gridLocationFromPosition(position);
93         Obstacle obstacle = getObstacles(location);
94
95         // Eliminate redundant corner checks
96         if (obstacle & OBSTACLE_XP) {
97                 obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XP_ZN);
98         }
99         if (obstacle & OBSTACLE_XN) {
100                 obstacle &= ~(OBSTACLE_XN_ZP | OBSTACLE_XN_ZN);
101         }
102         if (obstacle & OBSTACLE_ZP) {
103                 obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XN_ZP);
104         }
105         if (obstacle & OBSTACLE_ZN) {
106                 obstacle &= ~(OBSTACLE_XP_ZN | OBSTACLE_XN_ZN);
107         }
108
109         float edgeXp = cellBoundaryCoord(location.x + 1);
110         float edgeXn = cellBoundaryCoord(location.x);
111         float edgeZp = cellBoundaryCoord(location.z + 1);
112         float edgeZn = cellBoundaryCoord(location.z);
113         float distanceXp = edgeXp - position.x;
114         if (obstacle & OBSTACLE_XP) distanceXp -= collisionRadius;
115         float distanceXn = edgeXn - position.x;
116         if (obstacle & OBSTACLE_XN) distanceXn += collisionRadius;
117         float distanceZp = edgeZp - position.z;
118         if (obstacle & OBSTACLE_ZP) distanceZp -= collisionRadius;
119         float distanceZn = edgeZn - position.z;
120         if (obstacle & OBSTACLE_ZN) distanceZn += collisionRadius;
121
122         // Check all edges for intersecting already
123         if (distanceXp < 0.0f) {
124                 position.x += distanceXp;
125                 displacement = growVectorNoFlip(displacement, distanceXp);
126                 distanceXp = 0.0f;
127         }
128         if (distanceXn > 0.0f) {
129                 position.x += distanceXn;
130                 displacement = growVectorNoFlip(displacement, - distanceXn);
131                 distanceXn = 0.0f;
132         }
133         if (distanceZp < 0.0f) {
134                 position.z += distanceZp;
135                 displacement = growVectorNoFlip(displacement, distanceZp);
136                 distanceZp = 0.0f;
137         }
138         if (distanceZn > 0.0f) {
139                 position.z += distanceZn;
140                 displacement = growVectorNoFlip(displacement, - distanceZn);
141                 distanceZn = 0.0f;
142         }
143
144         // Calculate direct movement limits
145         float dx = displacement.x;
146         float dz = displacement.z;
147         if (dx > distanceXp) {
148                 dz *= distanceXp / dx;
149                 dx = distanceXp;
150                 // Might need a flag that we've reached a limit in X+?
151         }
152         if (dx < distanceXn) {
153                 dz *= distanceXn / dx;
154                 dx = distanceXn;
155                 // ?
156         }
157         if (dz > distanceZp) {
158                 dx *= distanceZp / dz;
159                 dz = distanceZp;
160                 // ?
161         }
162         if (dz < distanceZn) {
163                 dx *= distanceZn / dz;
164                 dz = distanceZn;
165                 // ?
166         }
167         // This is how far we can move until we collide or leave the grid cell
168         position = addVectors(position, (Vector) { dx, 0.0f, dz });
169         translate(&playerProjectedMovement->transform, subtractVectors(position, initialPosition));
170 }
171
172
173         translate(&playerCharacter->transform, displacement);
174 }
175
176 static Vector worldMovementDirection(float x, float y) {
177         Vector direction = (Vector) { x, 0.0f, -y };
178         direction = normalized(
179                 applyTransform(screenToWorldMovementTransform, direction));
180         return direction;
181 }