X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fgame%2Fplayer.c;h=861b655b6a188f4807ee5bdf91bad11eb8276849;hb=eb0ee96f2ffdf6bd18116609a1372e9f9ae96e53;hp=144d0cfd4416486fc0a1d8e5649d2117f4601821;hpb=edfc39dc5ca88d91ab6a27121321fc1b719d1ad7;p=shadowclad.git diff --git a/src/game/player.c b/src/game/player.c index 144d0cf..861b655 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -1,19 +1,251 @@ +/** + * Copyright 2019-2020 Iwo 'Outfrost' Bujkiewicz + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "player.h" + #include "engine/asset.h" +#include "engine/logger.h" #include "engine/render.h" -#include "player.h" +#include "level.h" + +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; +static Vector worldMovementLeft; +static Vector worldMovementRight; +static Direction movementDirection; + +static void movePlayer(Vector direction, float delta); +static Vector worldMovementDirection(float x, float y); void initPlayer() { + screenToWorldMovementTransform = identity(); + rotate(&screenToWorldMovementTransform, (Vector) { 0.0f, 1.0f, 0.0f }, - TAU / 8.0f); + + worldMovementUp = worldMovementDirection(0.0f, 1.0f); + worldMovementDown = worldMovementDirection(0.0f, -1.0f); + worldMovementLeft = worldMovementDirection(-1.0f, 0.0f); + worldMovementRight = worldMovementDirection(1.0f, 0.0f); + 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) { + Vector direction = zeroVector(); + if (movementDirection & DIRECTION_UP) { + direction = addVectors(direction, worldMovementUp); + } + if (movementDirection & DIRECTION_DOWN) { + direction = addVectors(direction, worldMovementDown); + } + if (movementDirection & DIRECTION_LEFT) { + direction = addVectors(direction, worldMovementLeft); + } + if (movementDirection & DIRECTION_RIGHT) { + direction = addVectors(direction, worldMovementRight); + } + movePlayer(direction, delta); +} + +void startMovement(Direction direction) { + movementDirection |= direction; +} + +void stopMovement(Direction direction) { + movementDirection &= ~direction; +} + +static void movePlayer(Vector direction, 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); + bool enteredNewCell = true; + + while (enteredNewCell) { + enteredNewCell = false; + 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); + } + + 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; + } + + // Calculate direct movement limits + Vector displacementToLimit = displacement; + bool reachedXp = false; + bool reachedXn = false; + bool reachedZp = false; + bool reachedZn = false; + if (displacementToLimit.x > distanceXp) { + displacementToLimit = scaleVector( + displacementToLimit, distanceXp / displacementToLimit.x); + reachedXp = true; + } + if (displacementToLimit.x < distanceXn) { + displacementToLimit = scaleVector( + displacementToLimit, distanceXn / displacementToLimit.x); + reachedXn = true; + } + if (displacementToLimit.z > distanceZp) { + displacementToLimit = scaleVector( + displacementToLimit, distanceZp / displacementToLimit.z); + reachedZp = true; + } + if (displacementToLimit.z < distanceZn) { + displacementToLimit = scaleVector( + displacementToLimit, distanceZn / displacementToLimit.z); + reachedZn = true; + } + // This is how far we can move until we collide or leave the grid cell + position = addVectors(position, displacementToLimit); + displacement = subtractVectors(displacement, displacementToLimit); + // Update distances + distanceXp -= displacementToLimit.x; + distanceXn -= displacementToLimit.x; + distanceZp -= displacementToLimit.z; + distanceZn -= displacementToLimit.z; + + // Resolve slides and crossing cell boundaries + // in reverse order to direct movement limits, because + // we only want to cross the closest cell boundary. + if (reachedZn) { + if (obstacle & OBSTACLE_ZN) { + float dx = clamp(displacement.x, distanceXn, distanceXp); + position.x += dx; + displacement = scaleVector(displacement, 1.0f - (dx / displacement.x)); + } + else { + location.z -= 1; + enteredNewCell = true; + } + } + + if (reachedZp) { + if (obstacle & OBSTACLE_ZP) { + float dx = clamp(displacement.x, distanceXn, distanceXp); + position.x += dx; + displacement = scaleVector(displacement, 1.0f - (dx / displacement.x)); + } + else if (!enteredNewCell) { + location.z += 1; + enteredNewCell = true; + } + } + + if (reachedXn) { + if (obstacle & OBSTACLE_XN) { + float dz = clamp(displacement.z, distanceZn, distanceZp); + position.z += dz; + displacement = scaleVector(displacement, 1.0f - (dz / displacement.z)); + } + else if (!enteredNewCell) { + location.x -= 1; + enteredNewCell = true; + } + } + + if (reachedXp) { + if (obstacle & OBSTACLE_XP) { + // Slide + float dz = clamp(displacement.z, distanceZn, distanceZp); + position.z += dz; + displacement = scaleVector(displacement, 1.0f - (dz / displacement.z)); + } + else if (!enteredNewCell) { + // Enter new grid cell + location.x += 1; + enteredNewCell = true; + } + } + } + translate(&playerProjectedMovement->transform, subtractVectors(position, initialPosition)); + + //translate(&playerCharacter->transform, subtractVectors(position, initialPosition)); +} + + + translate(&playerCharacter->transform, displacement); +} + +static Vector worldMovementDirection(float x, float y) { + Vector direction = (Vector) { x, 0.0f, -y }; + direction = normalized( + applyTransform(screenToWorldMovementTransform, direction)); + return direction; }