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/render.h"
16 static const float movementSpeed = 0.5f;
17 static const float collisionRadius = 0.5f;
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;
28 static void movePlayer(Vector direction, float delta);
29 static Vector worldMovementDirection(float x, float y);
34 screenToWorldMovementTransform = identity();
35 rotate(&screenToWorldMovementTransform, (Vector) { 0.0f, 1.0f, 0.0f }, - TAU / 8.0f);
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);
42 playerCharacter = newScene();
43 cameraAnchor = playerCharacter;
44 playerCharacter->solid = importSolid("assets/playercharacter.3ds");
46 playerProjectedMovement = newScene();
49 void spawnPlayer(Transform transform) {
50 playerCharacter->transform = transform;
51 reparentScene(playerCharacter, currentScene);
52 reparentScene(playerProjectedMovement, currentScene);
55 void updatePlayer(float delta) {
56 Vector direction = { 0.0f, 0.0f, 0.0f };
57 if (movementDirection & DIRECTION_UP) {
58 direction = addVectors(direction, worldMovementUp);
60 if (movementDirection & DIRECTION_DOWN) {
61 direction = addVectors(direction, worldMovementDown);
63 if (movementDirection & DIRECTION_LEFT) {
64 direction = addVectors(direction, worldMovementLeft);
66 if (movementDirection & DIRECTION_RIGHT) {
67 direction = addVectors(direction, worldMovementRight);
69 movePlayer(direction, delta);
72 void startMovement(Direction direction) {
73 movementDirection |= direction;
76 void stopMovement(Direction direction) {
77 movementDirection &= ~direction;
80 static void movePlayer(Vector direction, float delta) {
81 direction = clampMagnitude(direction, 1.0f);
82 Vector displacement = scaleVector(direction, delta * movementSpeed);
85 Vector displacement = scaleVector(direction, 0.006944f * movementSpeed * 1000.0f);
87 playerProjectedMovement->transform = playerCharacter->transform;
89 Vector initialPosition = translationOf(playerCharacter->transform);
90 Vector position = initialPosition;
92 GridLocation location = gridLocationFromPosition(position);
93 Obstacle obstacle = getObstacles(location);
95 // Eliminate redundant corner checks
96 if (obstacle & OBSTACLE_XP) {
97 obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XP_ZN);
99 if (obstacle & OBSTACLE_XN) {
100 obstacle &= ~(OBSTACLE_XN_ZP | OBSTACLE_XN_ZN);
102 if (obstacle & OBSTACLE_ZP) {
103 obstacle &= ~(OBSTACLE_XP_ZP | OBSTACLE_XN_ZP);
105 if (obstacle & OBSTACLE_ZN) {
106 obstacle &= ~(OBSTACLE_XP_ZN | OBSTACLE_XN_ZN);
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;
122 // Check all edges for intersecting already
123 if (distanceXp < 0.0f) {
124 position.x += distanceXp;
125 displacement = growVectorNoFlip(displacement, distanceXp);
128 if (distanceXn > 0.0f) {
129 position.x += distanceXn;
130 displacement = growVectorNoFlip(displacement, - distanceXn);
133 if (distanceZp < 0.0f) {
134 position.z += distanceZp;
135 displacement = growVectorNoFlip(displacement, distanceZp);
138 if (distanceZn > 0.0f) {
139 position.z += distanceZn;
140 displacement = growVectorNoFlip(displacement, - distanceZn);
144 // Calculate direct movement limits
145 float dx = displacement.x;
146 float dz = displacement.z;
147 if (dx > distanceXp) {
148 dz *= distanceXp / dx;
150 // Might need a flag that we've reached a limit in X+?
152 if (dx < distanceXn) {
153 dz *= distanceXn / dx;
157 if (dz > distanceZp) {
158 dx *= distanceZp / dz;
162 if (dz < distanceZn) {
163 dx *= distanceZn / dz;
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));
173 translate(&playerCharacter->transform, displacement);
176 static Vector worldMovementDirection(float x, float y) {
177 Vector direction = (Vector) { x, 0.0f, -y };
178 direction = normalized(
179 applyTransform(screenToWorldMovementTransform, direction));