From 683e22c419757744ce853c35d732f607ddb9af16 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Wed, 3 Feb 2021 12:33:03 -0500 Subject: Added input system --- CMakeLists.txt | 1 + src/character_system.cpp | 271 ++++++++++++++++++++++++----------------------- src/character_system.h | 14 ++- src/game.h | 17 +-- src/input_system.cpp | 89 ++++++++++++++++ src/input_system.h | 22 ++++ src/main.cpp | 43 +++----- src/sprite.h | 9 +- src/system.h | 5 +- 9 files changed, 295 insertions(+), 176 deletions(-) create mode 100644 src/input_system.cpp create mode 100644 src/input_system.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 65abfe1..a87b017 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ add_executable(tanetane src/camera_system.cpp src/animation_system.cpp src/character_system.cpp + src/input_system.cpp ) set_property(TARGET tanetane PROPERTY CXX_STANDARD 17) diff --git a/src/character_system.cpp b/src/character_system.cpp index 64e2f3b..ac0f01a 100644 --- a/src/character_system.cpp +++ b/src/character_system.cpp @@ -6,6 +6,11 @@ #include "transform_system.h" #include "animation_system.h" +void CharacterSystem::initSprite(int spriteId) { + Sprite& sprite = game_.getSprite(spriteId); + sprite.orientable = true; +} + void CharacterSystem::addSpriteToParty(int leaderId, int followerId) { Sprite& leader = game_.getSprite(leaderId); Sprite& follower = game_.getSprite(followerId); @@ -18,146 +23,124 @@ void CharacterSystem::addSpriteToParty(int leaderId, int followerId) { game_.getSystem().setSpriteAnimation(followerId, "still"); } -void CharacterSystem::moveSprite(int spriteId, Mixer& mixer, const Input& keystate) { +void CharacterSystem::moveInDirection(int spriteId, Direction dir) { 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) { + if (sprite.characterState == CharacterState::Still) { + setPartyState(spriteId, CharacterState::Walking); + } else 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"); - } - } +void CharacterSystem::stopDirecting(int spriteId) { + Sprite& sprite = game_.getSprite(spriteId); - 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 (sprite.characterState == CharacterState::Walking) { + setPartyState(spriteId, CharacterState::Still); } +} - 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; - } - } - } +void CharacterSystem::tick(double dt) { + inputTimer_.accumulate(dt); + while (inputTimer_.step()) { + for (int spriteId : game_.getSprites()) { + Sprite& sprite = game_.getSprite(spriteId); - 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 (sprite.orientable) { + vec2i pLoc = sprite.loc; - 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 (sprite.characterState == CharacterState::Still || + sprite.characterState == CharacterState::Crouching) { + continue; + } - if (blocked && sprite.characterState == CharacterState::Running) { - stopRunning(spriteId); - mixer.playSound("../res/bump.wav"); - } + int speed = MOVEMENT_SPEED; + if (sprite.characterState == CharacterState::Running) { + speed *= 2; + } - // Move everything - if (pLoc != sprite.loc) { - game_.getSystem().moveSprite(spriteId, pLoc); + pLoc += (unitVecInDirection(sprite.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(sprite.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; + } + } + } - 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); + if (dirHasDir(sprite.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; + } + } + } - pNext.trail.pop_front(); - pNext.trail.push_back({.pos = pLoc, .dir = dir}); + if (dirHasDir(sprite.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(sprite.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); + game_.getMixer().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 = sprite.dir}); + } + } + } } } } @@ -168,12 +151,7 @@ void CharacterSystem::beginCrouch(int 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"); - } + setPartyState(spriteId, CharacterState::Crouching); } } @@ -181,12 +159,9 @@ void CharacterSystem::endCrouch(int spriteId) { Sprite& sprite = game_.getSprite(spriteId); if (sprite.characterState == CharacterState::Crouching) { - sprite.characterState = CharacterState::Running; + setPartyState(spriteId, 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; @@ -204,7 +179,7 @@ void CharacterSystem::endCrouch(int spriteId) { void CharacterSystem::stopRunning(int spriteId) { Sprite& sprite = game_.getSprite(spriteId); - sprite.characterState = CharacterState::Normal; + setPartyState(spriteId, CharacterState::Still); // Double the movement buffer for the followers. for (int followerId : sprite.followers) { @@ -227,3 +202,33 @@ void CharacterSystem::stopRunning(int spriteId) { follower.trail = std::move(newMove); } } + +void CharacterSystem::setPartyState(int spriteId, CharacterState state) { + std::string animName; + switch (state) { + case CharacterState::Still: { + animName = "still"; + break; + } + case CharacterState::Walking: { + animName = "walk"; + break; + } + case CharacterState::Crouching: { + animName = "crouch"; + break; + } + case CharacterState::Running: { + animName = "run"; + break; + } + } + + Sprite& sprite = game_.getSprite(spriteId); + sprite.characterState = state; + + game_.getSystem().setSpriteAnimation(spriteId, animName); + for (int followerId : sprite.followers) { + game_.getSystem().setSpriteAnimation(followerId, animName); + } +} diff --git a/src/character_system.h b/src/character_system.h index ff5db02..2eea233 100644 --- a/src/character_system.h +++ b/src/character_system.h @@ -2,6 +2,9 @@ #define PARTY_H_826F91BA #include "system.h" +#include "direction.h" +#include "timer.h" +#include "sprite.h" class Mixer; class Game; @@ -14,9 +17,15 @@ public: CharacterSystem(Game& game) : game_(game) {} + void initSprite(int spriteId); + + void tick(double dt) override; + void addSpriteToParty(int leaderId, int followerId); - void moveSprite(int spriteId, Mixer& mixer, const Input& keystate); + void moveInDirection(int spriteId, Direction dir); + + void stopDirecting(int spriteId); void beginCrouch(int spriteId); @@ -26,7 +35,10 @@ private: void stopRunning(int spriteId); + void setPartyState(int spriteId, CharacterState state); + Game& game_; + Timer inputTimer_ {33}; }; #endif /* end of include guard: PARTY_H_826F91BA */ diff --git a/src/game.h b/src/game.h index f8e4b0d..36398bc 100644 --- a/src/game.h +++ b/src/game.h @@ -10,17 +10,17 @@ #include "map.h" #include "consts.h" #include "system.h" - -struct Input { - bool left = false; - bool right = false; - bool up = false; - bool down = false; -}; +#include "mixer.h" class Game { public: + Mixer& getMixer() { return mixer_; } + + bool shouldQuit() const { return shouldQuit_; } + + void quit() { shouldQuit_ = true; } + template void emplaceSystem() { systems_.push_back(std::make_unique(*this)); @@ -70,6 +70,9 @@ public: private: + Mixer mixer_; + bool shouldQuit_ = false; + std::list> systems_; std::map systemByKey_; diff --git a/src/input_system.cpp b/src/input_system.cpp new file mode 100644 index 0000000..54a291c --- /dev/null +++ b/src/input_system.cpp @@ -0,0 +1,89 @@ +#include "input_system.h" +#include "game.h" +#include "character_system.h" + +struct Input { + bool left = false; + bool right = false; + bool up = false; + bool down = false; +}; + +void InputSystem::tick(double dt) { + SDL_Event e; + while (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT || (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE)) { + game_.quit(); + + return; + } else if (e.type == SDL_KEYDOWN && (e.key.keysym.sym == SDLK_LSHIFT || e.key.keysym.sym == SDLK_RSHIFT)) { + for (int spriteId : game_.getSprites()) { + Sprite& sprite = game_.getSprite(spriteId); + if (sprite.controllable) { + game_.getSystem().beginCrouch(spriteId); + } + } + } else if (e.type == SDL_KEYUP && (e.key.keysym.sym == SDLK_LSHIFT || e.key.keysym.sym == SDLK_RSHIFT)) { + for (int spriteId : game_.getSprites()) { + Sprite& sprite = game_.getSprite(spriteId); + if (sprite.controllable) { + game_.getSystem().endCrouch(spriteId); + } + } + } + } + + Input keystate; + const Uint8* state = SDL_GetKeyboardState(NULL); + keystate.left = state[SDL_SCANCODE_LEFT]; + keystate.right = state[SDL_SCANCODE_RIGHT]; + keystate.up = state[SDL_SCANCODE_UP]; + keystate.down = state[SDL_SCANCODE_DOWN]; + + for (int spriteId : game_.getSprites()) { + Sprite& sprite = game_.getSprite(spriteId); + + if (sprite.controllable) { + bool directed = false; + Direction dir = Direction::left; + + if (keystate.up) + { + directed = true; + dir = Direction::up; + } else if (keystate.down) + { + directed = true; + dir = Direction::down; + } + + if (keystate.left) + { + directed = true; + 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) + { + directed = true; + if (dir == Direction::up) { + dir = Direction::up_right; + } else if (dir == Direction::down) { + dir = Direction::down_right; + } else { + dir = Direction::right; + } + } + + if (directed) { + game_.getSystem().moveInDirection(spriteId, dir); + } else { + game_.getSystem().stopDirecting(spriteId); + } + } + } +} diff --git a/src/input_system.h b/src/input_system.h new file mode 100644 index 0000000..4e5bb22 --- /dev/null +++ b/src/input_system.h @@ -0,0 +1,22 @@ +#ifndef INPUT_SYSTEM_H_47764575 +#define INPUT_SYSTEM_H_47764575 + +#include "system.h" + +class Game; + +class InputSystem : public System { +public: + + static constexpr SystemKey Key = SystemKey::Input; + + InputSystem(Game& game) : game_(game) {} + + void tick(double dt) override; + +private: + + Game& game_; +}; + +#endif /* end of include guard: INPUT_SYSTEM_H_47764575 */ diff --git a/src/main.cpp b/src/main.cpp index 3ac4d09..771aa1c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,15 +9,15 @@ #include "camera_system.h" #include "animation_system.h" #include "character_system.h" +#include "input_system.h" -void loop(Renderer& renderer, Mixer& mixer) { +void loop(Renderer& renderer) { Game game; game.emplaceSystem(); - game.emplaceSystem(); - game.emplaceSystem(); + game.emplaceSystem(); game.emplaceSystem(); - - Input keystate; + game.emplaceSystem(); + game.emplaceSystem(); auto map = std::make_unique("../res/map1.tmx", renderer); game.setMap(std::move(map)); @@ -25,6 +25,8 @@ void loop(Renderer& renderer, Mixer& mixer) { int lucasSprite = game.emplaceSprite(); game.getSystem().initSprite(lucasSprite, {32, 32}); game.getSystem().initSprite(lucasSprite, "../res/lucas_anim.txt", renderer); + game.getSprite(lucasSprite).controllable = true; + game.getSystem().initSprite(lucasSprite); int kumaSprite = game.emplaceSprite(); game.getSystem().initSprite(kumaSprite, {32, 32}); @@ -46,8 +48,6 @@ void loop(Renderer& renderer, Mixer& mixer) { renderer.render(game); - Timer inputTimer(33); - size_t lastTime = SDL_GetTicks(); for (;;) { @@ -55,33 +55,15 @@ void loop(Renderer& renderer, Mixer& mixer) { size_t frameTime = currentTime - lastTime; lastTime = currentTime; - SDL_Event e; - while (SDL_PollEvent(&e)) { - if (e.type == SDL_QUIT || (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE)) { - return; - } else if (e.type == SDL_KEYDOWN && (e.key.keysym.sym == SDLK_LSHIFT || e.key.keysym.sym == SDLK_RSHIFT)) { - game.getSystem().beginCrouch(lucasSprite); - } else if (e.type == SDL_KEYUP && (e.key.keysym.sym == SDLK_LSHIFT || e.key.keysym.sym == SDLK_RSHIFT)) { - game.getSystem().endCrouch(lucasSprite); - } - } - - const Uint8* state = SDL_GetKeyboardState(NULL); - keystate.left = state[SDL_SCANCODE_LEFT]; - keystate.right = state[SDL_SCANCODE_RIGHT]; - keystate.up = state[SDL_SCANCODE_UP]; - keystate.down = state[SDL_SCANCODE_DOWN]; - - inputTimer.accumulate(frameTime); - while (inputTimer.step()) { - game.getSystem().moveSprite(lucasSprite, mixer, keystate); - } - for (System& system : game.systems()) { system.tick(frameTime); } renderer.render(game); + + if (game.shouldQuit()) { + return; + } } } @@ -89,9 +71,8 @@ int main(int, char**) { try { Renderer renderer; - Mixer mixer; - loop(renderer, mixer); + loop(renderer); } catch (const sdl_error& ex) { std::cout << "SDL error (" << ex.what() << ")" << std::endl; diff --git a/src/sprite.h b/src/sprite.h index 65a7a66..2dc0ee1 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -16,7 +16,8 @@ struct SpriteFrame { }; enum class CharacterState { - Normal, + Still, + Walking, Crouching, Running }; @@ -44,9 +45,13 @@ public: std::map> nameDirToAnim; // Character + bool orientable = false; std::vector followers; std::deque trail; - CharacterState characterState = CharacterState::Normal; + CharacterState characterState = CharacterState::Still; + + // Input + bool controllable = false; }; #endif /* end of include guard: SPRITE_H_70503825 */ diff --git a/src/system.h b/src/system.h index 6f09d61..fc89503 100644 --- a/src/system.h +++ b/src/system.h @@ -3,9 +3,10 @@ enum class SystemKey { Transform, - Camera, + Input, + Character, Animation, - Character + Camera }; class System { -- cgit 1.4.1