#include "character_system.h" #include "consts.h" #include "mixer.h" #include "sprite.h" #include "game.h" #include "transform_system.h" #include "animation_system.h" void CharacterSystem::addSpriteToParty(int leaderId, int followerId) { Sprite& leader = game_.getSprite(leaderId); Sprite& follower = game_.getSprite(followerId); int index = leader.followers.size() + 1; follower.trail = std::deque(PARTY_FRAME_DELAY * index, {.pos = follower.loc, .dir = follower.dir}); leader.followers.push_back(followerId); game_.getSystem().setSpriteAnimation(followerId, "still"); } void CharacterSystem::moveSprite(int spriteId, Mixer& mixer, const Input& keystate) { Sprite& sprite = game_.getSprite(spriteId); Direction dir = sprite.dir; if (!keystate.up && !keystate.down && !keystate.left && !keystate.right) { if (sprite.characterState != CharacterState::Running) { if (sprite.characterState == CharacterState::Normal) { game_.getSystem().setSpriteAnimation(spriteId, "still"); for (int followerId : sprite.followers) { game_.getSystem().setSpriteAnimation(followerId, "still"); } } return; } } else { if (keystate.up) { dir = Direction::up; } else if (keystate.down) { dir = Direction::down; } if (keystate.left) { if (dir == Direction::up) { dir = Direction::up_left; } else if (dir == Direction::down) { dir = Direction::down_left; } else { dir = Direction::left; } } else if (keystate.right) { if (dir == Direction::up) { dir = Direction::up_right; } else if (dir == Direction::down) { dir = Direction::down_right; } else { dir = Direction::right; } } } vec2i pLoc = sprite.loc; game_.getSystem().setSpriteDirection(spriteId, dir); if (sprite.characterState == CharacterState::Crouching) { for (int followerId : sprite.followers) { game_.getSystem().setSpriteDirection(followerId, dir); } return; } int speed = MOVEMENT_SPEED; if (sprite.characterState == CharacterState::Running) { speed *= 2; } else { game_.getSystem().setSpriteAnimation(spriteId, "walk"); for (int followerId : sprite.followers) { game_.getSystem().setSpriteAnimation(followerId, "walk"); } } pLoc += (unitVecInDirection(dir) * speed); // Check collision. const Map& map = game_.getMap(); bool blocked = false; const vec2i UL_COL_BOX = { 8, 8 }; const vec2i DR_COL_BOX = { 4, 0 }; vec2i oldColPosUL = (sprite.loc - UL_COL_BOX) / map.getTileSize(); vec2i newColPosUL = (pLoc - UL_COL_BOX) / map.getTileSize(); vec2i oldColPosDR = (sprite.loc + DR_COL_BOX) / map.getTileSize(); vec2i newColPosDR = (pLoc + DR_COL_BOX) / map.getTileSize(); if (dirHasDir(dir, Direction::right) && newColPosDR.x() > oldColPosDR.x()) { for (int y = newColPosUL.y(); y <= newColPosDR.y(); y++) { if (map.isBlocked(newColPosDR.x(), y)) { blocked = true; pLoc.x() = sprite.loc.x();//(newColPosDR * map.getTileSize() - (collisionBox / 2)).x() - 1; break; } } } if (dirHasDir(dir, Direction::left) && newColPosUL.x() < oldColPosUL.x()) { for (int y = newColPosUL.y(); y <= newColPosDR.y(); y++) { if (map.isBlocked(newColPosUL.x(), y)) { blocked = true; pLoc.x() = sprite.loc.x();//(newColPosDR * map.getTileSize() - (collisionBox / 2)).x() - 1; break; } } } if (dirHasDir(dir, Direction::down) && newColPosDR.y() > oldColPosDR.y()) { for (int x = newColPosUL.x(); x <= newColPosDR.x(); x++) { if (map.isBlocked(x, newColPosDR.y())) { blocked = true; pLoc.y() = sprite.loc.y();//(newColPosDR * map.getTileSize() - (collisionBox / 2)).x() - 1; break; } } } if (dirHasDir(dir, Direction::up) && newColPosUL.y() < oldColPosUL.y()) { for (int x = newColPosUL.x(); x <= newColPosDR.x(); x++) { if (map.isBlocked(x, newColPosUL.y())) { blocked = true; pLoc.y() = sprite.loc.y();//(newColPosDR * map.getTileSize() - (collisionBox / 2)).x() - 1; break; } } } if (blocked && sprite.characterState == CharacterState::Running) { stopRunning(spriteId); mixer.playSound("../res/bump.wav"); } // Move everything if (pLoc != sprite.loc) { game_.getSystem().moveSprite(spriteId, pLoc); for (int followerId : sprite.followers) { Sprite& pNext = game_.getSprite(followerId); const Movement& posdir = pNext.trail.front(); game_.getSystem().moveSprite(followerId, posdir.pos); game_.getSystem().setSpriteDirection(followerId, posdir.dir); pNext.trail.pop_front(); pNext.trail.push_back({.pos = pLoc, .dir = dir}); } } } void CharacterSystem::beginCrouch(int spriteId) { Sprite& sprite = game_.getSprite(spriteId); if (sprite.characterState == CharacterState::Running) { stopRunning(spriteId); } else { sprite.characterState = CharacterState::Crouching; game_.getSystem().setSpriteAnimation(spriteId, "crouch"); for (int followerId : sprite.followers) { game_.getSystem().setSpriteAnimation(followerId, "crouch"); } } } void CharacterSystem::endCrouch(int spriteId) { Sprite& sprite = game_.getSprite(spriteId); if (sprite.characterState == CharacterState::Crouching) { sprite.characterState = CharacterState::Running; game_.getSystem().setSpriteAnimation(spriteId, "run"); for (int followerId : sprite.followers) { game_.getSystem().setSpriteAnimation(followerId, "run"); // Halve the movement buffer for the followers. Sprite& follower = game_.getSprite(followerId); std::deque newMove; while (!follower.trail.empty()) { newMove.push_back(follower.trail.front()); follower.trail.pop_front(); follower.trail.pop_front(); } follower.trail = std::move(newMove); } } } void CharacterSystem::stopRunning(int spriteId) { Sprite& sprite = game_.getSprite(spriteId); sprite.characterState = CharacterState::Normal; // Double the movement buffer for the followers. for (int followerId : sprite.followers) { Sprite& follower = game_.getSprite(followerId); std::deque newMove; vec2i lastPos = follower.loc; while (!follower.trail.empty()) { Movement m1 = follower.trail.front(); Movement m2 = m1; m1.pos = (m1.pos + lastPos) / 2; lastPos = m2.pos; newMove.push_back(m1); newMove.push_back(m2); follower.trail.pop_front(); } follower.trail = std::move(newMove); } }