#include "simulation.h" #include "consts.h" #include "level.h" void Simulation::tick( double dt, const Uint8* keystate) { for (id_type id : active_) { Entity& entity = entities_.at(id); // Control if (entity.controllable && !entity.moving) { if (keystate[SDL_SCANCODE_LSHIFT] || keystate[SDL_SCANCODE_RSHIFT]) { Direction lookDir = Direction::none; if (keystate[SDL_SCANCODE_LEFT]) { lookDir = Direction::left; } else if (keystate[SDL_SCANCODE_UP]) { lookDir = Direction::up; } else if (keystate[SDL_SCANCODE_RIGHT]) { lookDir = Direction::right; } else if (keystate[SDL_SCANCODE_DOWN]) { lookDir = Direction::down; } vec2s lookPos = posInDir(entity.gridPos, lookDir); for (id_type blockId : getGridEntities(lookPos)) { Entity& block = entities_.at(blockId); if (!block.moving && block.playerCanPush) { moveEntityOnGrid(blockId, lookDir); } } } else { if (keystate[SDL_SCANCODE_LEFT] && moveEntityOnGrid(id, Direction::left, true)) { entity.shouldMoveTo = Direction::left; } else if (keystate[SDL_SCANCODE_UP] && moveEntityOnGrid(id, Direction::up, true)) { entity.shouldMoveTo = Direction::up; } else if (keystate[SDL_SCANCODE_RIGHT] && moveEntityOnGrid(id, Direction::right, true)) { entity.shouldMoveTo = Direction::right; } else if (keystate[SDL_SCANCODE_DOWN] && moveEntityOnGrid(id, Direction::down, true)) { entity.shouldMoveTo = Direction::down; } else { entity.shouldMoveTo = Direction::none; } if (entity.shouldMoveTo != Direction::none) { moveEntityOnGrid(id, entity.shouldMoveTo); } } } // Collision // Movement if (entity.moving) { entity.movementTween += entity.speed * dt; if (entity.movementTween >= 1.0) { entity.moving = false; setGridPos(id, entity.destPos); } } if (entity.moving) { entity.pos.x() = TILE_SIZE.x() * entity.destPos.x() * entity.movementTween + TILE_SIZE.x() * entity.gridPos.x() * (1.0 - entity.movementTween); entity.pos.y() = TILE_SIZE.y() * entity.destPos.y() * entity.movementTween + TILE_SIZE.y() * entity.gridPos.y() * (1.0 - entity.movementTween); } else { entity.pos = TILE_SIZE * entity.gridPos; } } } Simulation::id_type Simulation::emplaceEntity() { id_type nextId; if (!available_.empty()) { nextId = available_.front(); available_.pop_front(); entities_.at(nextId) = Entity(); } else { nextId = entities_.size(); entities_.emplace_back(); } active_.insert(nextId); return nextId; } void Simulation::deleteEntity(id_type id) { available_.push_back(id); active_.erase(id); } void Simulation::setGridPos(id_type id, vec2s pos) { Entity& entity = entities_.at(id); size_t oldPosIndex = entity.gridPos.x() + entity.gridPos.y() * level_.getSize().w(); gridCache_[oldPosIndex].erase(id); entity.gridPos = pos; size_t newPosIndex = entity.gridPos.x() + entity.gridPos.y() * level_.getSize().w(); gridCache_[newPosIndex].insert(id); } const std::unordered_set& Simulation::getGridEntities(vec2s pos) const { size_t posIndex = pos.x() + pos.y() * level_.getSize().w(); return gridCache_[posIndex]; } bool Simulation::moveEntityOnGrid( id_type id, Direction moveDir, bool validate) { Entity& entity = entities_.at(id); vec2s shouldMoveTo = posInDir(entity.gridPos, moveDir); switch (moveDir) { case Direction::left: { if (entity.gridPos.x() == 0) { return false; } break; } case Direction::right: { if (entity.gridPos.x() == level_.getSize().w() - 1) { return false; } break; } case Direction::up: { if (entity.gridPos.y() == 0) { return false; } break; } case Direction::down: { if (entity.gridPos.y() == level_.getSize().h() - 1) { return false; } break; } } if (entity.colliderType == ColliderType::player) { if (!level_.getTileset().canPlayerMoveTo(level_.at(shouldMoveTo))) { return false; } for (id_type blockId : getGridEntities(shouldMoveTo)) { Entity& block = entities_.at(blockId); if (block.moving || !block.playerCanPush) { return false; } if (!moveEntityOnGrid(blockId, moveDir, validate)) { return false; } } } if (!validate) { entity.moving = true; entity.destPos = shouldMoveTo; entity.movementTween = 0.0; } return true; } vec2s Simulation::posInDir(vec2s orig, Direction dir) { switch (dir) { case Direction::left: return orig - vec2s { 1, 0 }; case Direction::right: return orig + vec2s { 1, 0 }; case Direction::up: return orig - vec2s { 0, 1 }; case Direction::down: return orig + vec2s { 0, 1 }; case Direction::none: return orig; } }