diff --git a/HowToPlay.md b/HowToPlay.md new file mode 100644 index 0000000..72c900d --- /dev/null +++ b/HowToPlay.md @@ -0,0 +1,42 @@ +![welcome](./snapshot/welcome.png) + +开始界面,上方按钮进入游戏,下方按钮退出游戏 + + +![select-ship](./snapshot/select_ship.png) + +选择飞船和配置阵营界面。左边选择你的飞船(目前只有两架),右边可以配置阵营: + +* `Group Number`:要参战的队伍(最少2队,最多4队) +* `Plane Number`:每队的飞船数目 + +机种: + +* 防御机(圆圆的那个):血量高,但是速度慢,攻击频率慢,且只有炮弹武器,但是可以360度射击。 +* 战斗机(看上去就像战斗机的那个):血量少,但是速度快,攻击频率高,有炮弹和导弹两种武器,炮弹只可以向飞行方向射击。 + +战斗机和防御机的起始数量是随机的(总数为Plane Number)。 + + +![gaming](./snapshot/gaming.png) + +游戏界面。 + +* 左下角是雷达图,可以显示一定范围的飞机 +* 正下方是战队血量,展示了目前在场的战队的所有飞机血量和(红色是我方血量) +* 右下角是武器说明,第一栏为主武器(这里是Bullet子弹),第二栏是副武器(这里是Missile导弹),方括号里显示武器弹药数量(没有就是无限弹药) +* 右上角是你的飞船血量。 + +飞机的操作: + +* 防御机,按下w,a,s,d进行上下左右的移动,按下鼠标左键进行攻击。 +* 战斗机,按下a,d进行左右转向,w,s进行加速和减速(不能向后倒着飞),鼠标左键使用炮弹,鼠标右键发射导弹(导弹有数量限制)。 + +切换飞机: + +当你控制的飞机死亡后,视角会转到我方阵营的另一架飞机上,此时可以选择按空格键操控这辆飞机。 + +胜利条件: + +全灭其他所有阵营获得胜利 + diff --git a/ReadMe.md b/ReadMe.md index e4299bc..e11fca7 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -24,3 +24,15 @@ pack.sh ``` 最终的结果在`output`文件夹下。 + +## 游戏截图 + +![welcome](./snapshot/welcome.png) + +![select](./snapshot/select_ship.png) + +![gaming](./snapshot/gaming.png) + +## 游戏操作 + +[游戏操作](./HowToPlay.md) diff --git a/assets/explose.wav b/assets/explose.wav new file mode 100644 index 0000000..05da2cb Binary files /dev/null and b/assets/explose.wav differ diff --git a/assets/hurt.wav b/assets/hurt.wav new file mode 100644 index 0000000..d63b65c Binary files /dev/null and b/assets/hurt.wav differ diff --git a/assets/missile.wav b/assets/missile.wav new file mode 100644 index 0000000..141ef5d Binary files /dev/null and b/assets/missile.wav differ diff --git a/assets/tilesheet.png b/assets/tilesheet.png index 23190af..a4bb259 100644 Binary files a/assets/tilesheet.png and b/assets/tilesheet.png differ diff --git a/include/game/component.hpp b/include/game/component.hpp index 06e1bc1..dc5604c 100644 --- a/include/game/component.hpp +++ b/include/game/component.hpp @@ -228,8 +228,10 @@ public: void Init(AIFunc func) { this->func = func; + target = nullptr; } void Release() {} AIFunc func; + Entity* target; }; diff --git a/include/game/constants.hpp b/include/game/constants.hpp index 98f8281..6fa40d9 100644 --- a/include/game/constants.hpp +++ b/include/game/constants.hpp @@ -7,9 +7,10 @@ constexpr int FightShipLife = 10; constexpr float FightShipRotationDegree = 6; constexpr float FightShipAccelration = 200; -constexpr float FreightShipMaxSpeed = 100; -constexpr int FreightShipLife = 15; +constexpr float FreightShipMaxSpeed = 200; +constexpr int FreightShipLife = 20; constexpr float FreightShipAccelerate = 100; +constexpr float FreightShipLazerDelay = 0.3; constexpr float LazerDamage = 3.4; constexpr float LazerShooterSpeed = 800; @@ -34,3 +35,10 @@ constexpr int Enemy3Group = 3; constexpr float EntityRenderSize = 20; constexpr float EntityCollisionSize = 16; + +constexpr Color GroupSpecColor[4] = { + Color{0.8, 0, 0, 1}, + Color{0, 0.8, 0, 1}, + Color{0, 0, 0.8, 1}, + Color{0.8, 0.8, 0, 1} +}; diff --git a/include/game/quick_list.hpp b/include/game/quick_list.hpp index 54629e3..a1815a6 100644 --- a/include/game/quick_list.hpp +++ b/include/game/quick_list.hpp @@ -12,6 +12,8 @@ public: datas_.push_back(elem); } + bool Empty() const { return datas_.empty(); } + void RemoveAll(condition_func findFunc, destroy_func destroyFunc = nullptr) { std::size_t idx = 0; @@ -48,6 +50,11 @@ public: printf("\n"); } + + size_t Size() const { return datas_.size(); } + T& Get(size_t idx) { return datas_[idx]; } + + using const_iterator = typename std::vector::const_iterator; const_iterator begin() const { return datas_.begin(); } diff --git a/include/game/stages/space.hpp b/include/game/stages/space.hpp index fda1bef..60cf26d 100644 --- a/include/game/stages/space.hpp +++ b/include/game/stages/space.hpp @@ -16,15 +16,23 @@ public: void OnQuit() override; private: - Unique fightController_; + Unique controller_; + + Camera guiCamera_; + Camera gameCamera_; + Entity* lookAtEntity_; + + std::vector stars_; + int groupHps[4] = {0}; void renderBackground(); void renderGUI(); void renderMiniMap(); void renderWeapons(SpaceshipWeaponCmpt* weapon1, SpaceshipWeaponCmpt* weapon2); - - Camera guiCamera_; - Camera gameCamera_; - - std::vector stars_; + void initEnemies(); + void attachController(); + void generateEnemiesAt(int group, const Point& p, int num); + void initPlayer(); + void calcGroupHps(); + void drawGroupHp(); }; diff --git a/include/game/system.hpp b/include/game/system.hpp index 5e532d6..470f23c 100644 --- a/include/game/system.hpp +++ b/include/game/system.hpp @@ -53,7 +53,7 @@ public: void Render() override; private: - void renderEntity(Entity* entity, const RenderCmpt&, float rotation); + void renderEntity(Entity* entity, const RenderCmpt&, float rotation, const Color&); void renderCollideBox(Entity* entity); }; diff --git a/include/tinyengine/event.hpp b/include/tinyengine/event.hpp index 600cdc7..ac52a5b 100644 --- a/include/tinyengine/event.hpp +++ b/include/tinyengine/event.hpp @@ -11,6 +11,7 @@ bool IsRightPressing(); bool IsLeftPressed(); bool IsRightPressed(); Point GetMousePosition(); +Point GetMousePositionMapped(); void EventUpdate(); diff --git a/include/tinyengine/libmath.hpp b/include/tinyengine/libmath.hpp index 74f86ff..87d683a 100644 --- a/include/tinyengine/libmath.hpp +++ b/include/tinyengine/libmath.hpp @@ -195,8 +195,8 @@ inline Mat44 CreateSRT(const Point& pos, const Point& scale, float degree) { float sinTheta = std::sin(theta), cosTheta = std::cos(theta); return Mat44({ - scale.x * cosTheta, scale.y * sinTheta, 0, pos.x, - -scale.x * sinTheta, scale.y * cosTheta, 0, pos.y, + scale.x * cosTheta,-scale.y * sinTheta, 0, pos.x, + scale.x * sinTheta, scale.y * cosTheta, 0, pos.y, 0, 0, 1, 0, 0, 0, 0, 1, }); diff --git a/include/tinyengine/renderer.hpp b/include/tinyengine/renderer.hpp index 0e022a2..9ba1026 100644 --- a/include/tinyengine/renderer.hpp +++ b/include/tinyengine/renderer.hpp @@ -31,15 +31,17 @@ public: static void FillRect(const Rect& rect); static void DrawTile(const Tile& tile, const Point& pos, - const Size& size = {0, 0}, + const Size& = {0, 0}, float degree = 0, - FlipFlag flip = NoFlip); + FlipFlag = NoFlip, + const Color& = {1, 1, 1, 1}); static void DrawTexture(const Texture* texture, const Rect* srcrect, const Point& pos, - const Size& size = Size{0, 0}, + const Size& = Size{0, 0}, float degree = 0, - FlipFlag flip = NoFlip); + FlipFlag = NoFlip, + const Color& = {1, 1, 1, 1}); static void DrawTexture(const Texture* texture, const Rect* rect, const Mat44& transform, diff --git a/pack.sh b/pack.sh index 535554e..576f66a 100755 --- a/pack.sh +++ b/pack.sh @@ -8,3 +8,5 @@ mkdir output cp ./build/SpaceSector output cp -r ./assets output rm -rf ./output/assets/test +cp ./HowToPlay.md output/ +cp -r ./snapshot output diff --git a/snapshot/gaming.png b/snapshot/gaming.png new file mode 100644 index 0000000..e265647 Binary files /dev/null and b/snapshot/gaming.png differ diff --git a/snapshot/select_ship.png b/snapshot/select_ship.png new file mode 100644 index 0000000..313142e Binary files /dev/null and b/snapshot/select_ship.png differ diff --git a/snapshot/welcome.png b/snapshot/welcome.png new file mode 100644 index 0000000..f73e1db Binary files /dev/null and b/snapshot/welcome.png differ diff --git a/src/game/action.cpp b/src/game/action.cpp index 935c0db..62f8dd0 100644 --- a/src/game/action.cpp +++ b/src/game/action.cpp @@ -5,8 +5,6 @@ void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir) { return; } - Point playerCenterPos = weapon.owner->Get()->position; - Entity* bullet; bullet = weapon.ShootBullet(dir); if (bullet) { @@ -26,8 +24,7 @@ void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir, Entity* target) { Entity* bullet; bullet = weapon.ShootMissile(dir, target); if (bullet) { - // FIXME the rotation have some bugs - bullet->Use()->rotation = Degrees(std::acos(-Normalize(dir).y)); + bullet->Use()->rotation = Sign(dir.x) * Degrees(std::acos(-Normalize(dir).y)); Bullets.Add(bullet); weapon.coolDown = weapon.shootDuration; Sounds["shoot"]->Play(); @@ -51,19 +48,19 @@ void MoveDown(MotionCmpt& motion) { } void SpeedUp(MotionCmpt& motion, FightShipCmpt& ship) { - motion.acceleration = Rotate(Point{0, FightShipAccelration}, - -ship.degree); + motion.acceleration = Rotate(Point{0, -FightShipAccelration}, + ship.degree); } void SpeedDown(MotionCmpt& motion, FightShipCmpt& ship) { - motion.acceleration = Rotate(Point{0, -FightShipAccelration}, - -ship.degree); + motion.acceleration = Rotate(Point{0, FightShipAccelration}, + ship.degree); } void TurnLeft(FightShipCmpt& ship) { - ship.degree += FightShipRotationDegree; + ship.degree -= FightShipRotationDegree; } void TurnRight(FightShipCmpt& ship) { - ship.degree -= FightShipRotationDegree; + ship.degree += FightShipRotationDegree; } diff --git a/src/game/ai.cpp b/src/game/ai.cpp index cff2761..fab779d 100644 --- a/src/game/ai.cpp +++ b/src/game/ai.cpp @@ -1,7 +1,27 @@ #include "game/ai.hpp" +Entity* findRandomEntity(Entity* self) { + int groupIdx = Random(0, 3); + if (groupIdx == self->Get()->groupIdx) { + groupIdx ++; + if (groupIdx >= 4) { + groupIdx = 0; + } + } + auto& group = Groups[groupIdx]; + if (group.Empty()) + return nullptr; + return group.Get(Random(1, group.Size()) - 1); +} + void FreightShipAI(Entity* self) { - auto pmove = PlayerSpaceship->Get(); + auto ai = self->Use(); + if (!ai->target || !ai->target->IsAlive()) { + ai->target = findRandomEntity(self); + } + if (!ai->target) return; + + auto pmove = ai->target->Get(); auto smove = self->Get(); auto dir = pmove->position - smove->position; if (Len2(dir) > 250000) { @@ -22,29 +42,35 @@ void FreightShipAI(Entity* self) { } void FightShipAI(Entity* self) { - auto pmove = PlayerSpaceship->Get(); + auto ai = self->Use(); + if (!ai->target || !ai->target->IsAlive()) { + ai->target = findRandomEntity(self); + } + if (!ai->target) return; + + auto pmove = ai->target->Get(); auto smove = self->Get(); auto dir = pmove->position - smove->position; auto motion = self->Use(); auto ship = self->Use(); - auto nspd = Normalize(motion->speed), - ndir = Normalize(dir); + auto ndir = Normalize(dir); SpeedUp(*motion, *ship); - auto cross = Cross(nspd, ndir); - if (cross > std::sin(Radians(80))) { - TurnLeft(*ship); - } else if (cross < std::sin(Radians(10))) { + auto shipDir = Rotate(Point{0, -1}, self->Get()->degree); + auto cross = Cross(shipDir, ndir); + if (cross > 0) { TurnRight(*ship); + } else { + TurnLeft(*ship); + } + if (abs(Cross(Normalize(motion->speed), Normalize(dir))) < std::sin(Radians(10))) { + if (ship->weapon2->bulletAmount > 0 && Random(1.0f, 100.0f) < 5) { + Shoot(*ship->weapon2, shipDir, ai->target); + } else { + Shoot(*ship->weapon1, shipDir); + } } - // if (Cross(Normalize(motion->speed), Normalize(dir)) < std::sin(Radians(10))) { - // if (ship->weapon2->bulletAmount > 0 && Random(1.0f, 100.0f) < 5) { - // Shoot(*ship->weapon2, dir, PlayerSpaceship); - // } else { - // Shoot(*ship->weapon1, dir); - // } - // } } diff --git a/src/game/component.cpp b/src/game/component.cpp index d6802e9..d652128 100644 --- a/src/game/component.cpp +++ b/src/game/component.cpp @@ -23,5 +23,6 @@ Entity* SpaceshipWeaponCmpt::ShootMissile(const Point& dir, Entity* target) { } bullet->Use()->speed = Normalize(dir) * shootSpeed; bullet->Use()->position = owner->Get()->position; + Sounds["missile"]->Play(); return bullet; } diff --git a/src/game/controllers/fightship_controller.cpp b/src/game/controllers/fightship_controller.cpp index fec850f..cb92dab 100644 --- a/src/game/controllers/fightship_controller.cpp +++ b/src/game/controllers/fightship_controller.cpp @@ -5,6 +5,10 @@ FightShipController::FightShipController(Entity* entity) : entity_(entity) {} void FightShipController::Update(float dt) { + if (!entity_ || !entity_->IsAlive()) { + return; + } + const float spd = 100; auto motionCmpt = entity_->Use(); auto ship = entity_->Use(); @@ -15,14 +19,14 @@ void FightShipController::Update(float dt) { TurnRight(*ship); } if (IsKeyPressing(GLFW_KEY_S)) { - SpeedUp(*motionCmpt, *ship); + SpeedDown(*motionCmpt, *ship); } if (IsKeyPressing(GLFW_KEY_W)) { - SpeedDown(*motionCmpt, *ship); + SpeedUp(*motionCmpt, *ship); } motionCmpt->speed = Rotate(Point{0, -1} * Len(motionCmpt->speed), - -ship->degree); + ship->degree); auto moveCmpt = entity_->Get(); @@ -46,9 +50,9 @@ void FightShipController::weaponShoot(SpaceshipWeaponCmpt* weapon, const MoveCmp if (!weapon) return; Point dir; if (weapon->type == SpaceshipWeaponCmpt::Orientation) { - dir = Rotate(Point{0, -1}, -entity_->Get()->degree); + dir = Rotate(Point{0, -1}, entity_->Get()->degree); } else { - dir = GetMousePosition() - entity_->Get()->position; + dir = GetMousePosition() - GameWindowSize / 2; } if (weapon->bulletType == BulletCmpt::Bullet) { @@ -57,7 +61,7 @@ void FightShipController::weaponShoot(SpaceshipWeaponCmpt* weapon, const MoveCmp Entity* target = nullptr; for (auto& entity : Entities) { if (entity != entity_ && - IsPointInRect(MapPlayerCoord2Global(GetMousePosition()), entity->Get()->rect)) { + IsPointInRect(MapPlayerCoord2Global(GetMousePositionMapped()), entity->Get()->rect)) { target = entity; break; } diff --git a/src/game/controllers/freightship_controller.cpp b/src/game/controllers/freightship_controller.cpp index 232d889..b3601ea 100644 --- a/src/game/controllers/freightship_controller.cpp +++ b/src/game/controllers/freightship_controller.cpp @@ -5,6 +5,10 @@ FreightShipController::FreightShipController(Entity* entity) : entity_(entity) {} void FreightShipController::Update(float dt) { + if (!entity_ || !entity_->IsAlive()) { + return; + } + const float spd = 100; auto motionCmpt = entity_->Use(); if (IsKeyPressing(GLFW_KEY_A)) { @@ -29,7 +33,7 @@ void FreightShipController::Update(float dt) { Rotate(Point{0, -1}, entity_->Get()->degree)); } else { Shoot(*weapon, - GetMousePosition() - entity_->Get()->position); + GetMousePosition() - GameWindowSize / 2); } } } diff --git a/src/game/entity.cpp b/src/game/entity.cpp index d525fcb..ff08ded 100644 --- a/src/game/entity.cpp +++ b/src/game/entity.cpp @@ -13,7 +13,7 @@ Entity* CreateFreightShip(int group) { LazerDamage, LazerShooterSpeed, LazerShooterMaxSpeed, - LazerShooterCooldown + 1); + LazerShooterCooldown + FreightShipLazerDelay); entity->Add(Size{EntityCollisionSize, EntityCollisionSize}); entity->Add(FreightShipLife); entity->Add(weapon); @@ -56,7 +56,7 @@ Entity* CreateBullet(int group, int damage, Entity* owner, float maxSpeed) { Entity* entity = ECSContext.CreateEntity(); entity->Add(Point{0, 0}); entity->Add(Point{0, 0}, maxSpeed); - entity->Add(GameTileSheet->GetTile(0, 1)); + entity->Add(GameTileSheet->GetTile(4, 0)); entity->Add(BulletCmpt::Bullet, damage, owner); entity->Add(Size{8, 8}); entity->Add(group); @@ -67,7 +67,7 @@ Entity* CreateMissile(int group, int damage, Entity* owner, float maxSpeed, Enti Entity* entity = ECSContext.CreateEntity(); entity->Add(Point{0, 0}); entity->Add(Point{0, 0}, maxSpeed); - entity->Add(GameTileSheet->GetTile(2, 1)); + entity->Add(GameTileSheet->GetTile(6, 0)); entity->Add(BulletCmpt::Missile, damage, owner, target); entity->Add(Size{10, 10}); entity->Add(group); diff --git a/src/game/global.cpp b/src/game/global.cpp index 255f6b8..21f98ab 100644 --- a/src/game/global.cpp +++ b/src/game/global.cpp @@ -15,11 +15,14 @@ GameInitInfo InitInfo; std::array, 4> Groups; void loadImages() { - GameTileSheet.reset(new TileSheet("assets/tilesheet.png", 8, 8)); + GameTileSheet.reset(new TileSheet("assets/tilesheet.png", 7, 1)); } void loadSounds() { Sounds["shoot"] = std::make_unique("assets/shoot.wav"); + Sounds["hurt"] = std::make_unique("assets/hurt.wav"); + Sounds["explosion"] = std::make_unique("assets/explose.wav"); + Sounds["missile"] = std::make_unique("assets/missile.wav"); } void LoadResources() { diff --git a/src/game/gui.cpp b/src/game/gui.cpp index 660c53b..3f8f569 100644 --- a/src/game/gui.cpp +++ b/src/game/gui.cpp @@ -4,7 +4,7 @@ bool Button(Texture* texture, const Point& pos, const Size& size, bool hflip) { Renderer::DrawTexture(texture, nullptr, pos, size, 0, hflip ? Renderer::FlipFlag::Horizontal : Renderer::FlipFlag::NoFlip); Rect rect = Rect{pos.x - size.w / 2, pos.y - size.h / 2, size.w, size.h}; - if (IsPointInRect(GetMousePosition(), rect)) { + if (IsPointInRect(GetMousePositionMapped(), rect)) { Renderer::SetDrawColor(Color{1, 1, 1, 0.2}); Renderer::FillRect(rect); return IsLeftPressed(); diff --git a/src/game/stages/space.cpp b/src/game/stages/space.cpp index becb0e8..4e3a759 100644 --- a/src/game/stages/space.cpp +++ b/src/game/stages/space.cpp @@ -6,42 +6,11 @@ void SpaceScence::OnInit() { Entities.Clear(); Bullets.Clear(); - PlayerSpaceship = CreateFightShip(PlayerGroup); - Entities.Add(PlayerSpaceship); - PlayerSpaceship->Use()->position = Point{400, 400}; - - Entity* enemy = CreateFreightShip(Enemy1Group); - enemy->Add(FreightShipAI); - enemy->Use()->position = Point{100, 100}; - Entities.Add(enemy); - - enemy = CreateFreightShip(Enemy1Group); - enemy->Add(FreightShipAI); - enemy->Use()->position = Point{200, 100}; - Entities.Add(enemy); - - enemy = CreateFreightShip(Enemy1Group); - enemy->Add(FreightShipAI); - enemy->Use()->position = Point{100, 200}; - Entities.Add(enemy); - - // Entity* enemy = CreateFightShip(Enemy1Group); - // enemy->Add(FightShipAI); - // enemy->Use()->position = Point{100, 100}; - // Entities.Add(enemy); - - // enemy = CreateFightShip(Enemy1Group); - // enemy->Add(FightShipAI); - // enemy->Use()->position = Point{200, 100}; - // Entities.Add(enemy); - - // enemy = CreateFightShip(Enemy1Group); - // enemy->Add(FightShipAI); - // enemy->Use()->position = Point{100, 200}; - // Entities.Add(enemy); - - fightController_.reset(new FightShipController(PlayerSpaceship)); + initEnemies(); + initPlayer(); + calcGroupHps(); + lookAtEntity_ = PlayerSpaceship; gameCamera_.SetAnchor(GameWindowSize / 2); SystemMgr.Clear(); @@ -62,10 +31,89 @@ void SpaceScence::OnInit() { } } +void SpaceScence::calcGroupHps() { + for (int i = 0; i < InitInfo.groupNum; i++) { + for (auto& entity : Groups[i]) { + if (entity->Has()) { + groupHps[i] += entity->Get()->hp; + } + } + } +} + +void SpaceScence::initPlayer() { + if (PlayerSpaceship && PlayerSpaceship->IsAlive()) { + ECSContext.DestroyEntity(PlayerSpaceship); + } + if (InitInfo.planeType == FightShip) { + PlayerSpaceship = CreateFightShip(PlayerGroup); + controller_.reset(new FightShipController(PlayerSpaceship)); + } else if (InitInfo.planeType == FreightShip) { + PlayerSpaceship = CreateFreightShip(PlayerGroup); + controller_.reset(new FreightShipController(PlayerSpaceship)); + } + Entities.Add(PlayerSpaceship); + Groups[PlayerGroup].Add(PlayerSpaceship); + PlayerSpaceship->Use()->position = Point{0, 0}; +} + +void SpaceScence::initEnemies() { + generateEnemiesAt(PlayerGroup, Point{0, 0}, InitInfo.planeNum - 1); + if (InitInfo.groupNum == 2) { + generateEnemiesAt(Enemy1Group, Point{0, -720 * 4}, InitInfo.planeNum); + } else if (InitInfo.groupNum == 3) { + generateEnemiesAt(Enemy1Group, Point{-720 * 4, -720 * 4}, InitInfo.planeNum); + generateEnemiesAt(Enemy2Group, Point{720 * 4, -720 * 4}, InitInfo.planeNum); + } else if (InitInfo.groupNum == 4) { + generateEnemiesAt(Enemy1Group, Point{0, -720 * 4}, InitInfo.planeNum); + generateEnemiesAt(Enemy2Group, Point{720 * 4, 0}, InitInfo.planeNum); + generateEnemiesAt(Enemy3Group, Point{720 * 4, -720 * 4}, InitInfo.planeNum); + } else { + Log("group num invalid"); + } +} + +void SpaceScence::generateEnemiesAt(int group, const Point& p, int num) { + for (int i = 0; i < num; i++) { + Entity* enemy = CreateFreightShip(group); + enemy->Add(FreightShipAI); + // Entity* enemy = CreateFightShip(group); + // enemy->Add(FightShipAI); + enemy->Use()->position += p + Point{Random(-400, 400), Random(-100, 100)}; + Entities.Add(enemy); + Groups[group].Add(enemy); + } +} + void SpaceScence::OnUpdate(float dt) { - fightController_->Update(dt); + controller_->Update(dt); SystemMgr.Update(dt); - gameCamera_.MoveTo(PlayerSpaceship->Get()->position); + + if (lookAtEntity_ && lookAtEntity_->IsAlive()) { + gameCamera_.MoveTo(lookAtEntity_->Get()->position); + } else { + if (!Groups[PlayerGroup].Empty()) { + lookAtEntity_ = *Groups[PlayerGroup].begin(); + } + } + + if (!PlayerSpaceship || !PlayerSpaceship->IsAlive()) { + if (IsKeyPressing(GLFW_KEY_SPACE)) { + PlayerSpaceship = lookAtEntity_; + if (PlayerSpaceship->Has()) { + PlayerSpaceship->Remove(); + } + attachController(); + } + } +} + +void SpaceScence::attachController() { + if (PlayerSpaceship->Has()) { + controller_.reset(new FreightShipController(PlayerSpaceship)); + } else { + controller_.reset(new FightShipController(PlayerSpaceship)); + } } void SpaceScence::OnRender() { @@ -100,19 +148,46 @@ void SpaceScence::renderBackground() { void SpaceScence::renderGUI() { Renderer::SetCamera(guiCamera_); - auto life = PlayerSpaceship->Get()->hp; + int life = 0; + if (PlayerSpaceship && PlayerSpaceship->IsAlive()) { + life = PlayerSpaceship->Get()->hp; + } float xOffset = 16 * life; for (int i = 0; i < life; i++) { - Renderer::DrawTile(GameTileSheet->GetTile(1, 1), + Renderer::DrawTile(GameTileSheet->GetTile(5, 0), Point{GameWindowSize.w - xOffset + i * 16, 8}); } renderMiniMap(); - if (PlayerSpaceship->Has()) { - renderWeapons(PlayerSpaceship->Get()->weapon, nullptr); - } else { - auto fightShip = PlayerSpaceship->Get(); - renderWeapons(fightShip->weapon1, fightShip->weapon2); + if (PlayerSpaceship && PlayerSpaceship->IsAlive()) { + if (PlayerSpaceship->Has()) { + renderWeapons(PlayerSpaceship->Get()->weapon, nullptr); + } else { + auto fightShip = PlayerSpaceship->Get(); + renderWeapons(fightShip->weapon1, fightShip->weapon2); + } + } + + drawGroupHp(); +} + +void SpaceScence::drawGroupHp() { + static Color colors[4] = {Color{1, 0, 0, 1}, + Color{0, 1, 0, 1}, + Color{0, 0, 1, 1}, + Color{1, 1, 0, 1}}; + + for (int i = 0; i < InitInfo.groupNum; i++) { + int hp = 0; + for (auto& entity : Groups[i]) { + if (entity->Has()) { + hp += entity->Get()->hp; + } + } + Renderer::SetDrawColor(colors[i]); + Renderer::FillRect(Rect{150, GameWindowSize.h - 20 * (i + 1), hp / float(groupHps[i]) * 500, 20}); + Renderer::SetDrawColor(Color{1, 1, 1, 1}); + Renderer::DrawRect(Rect{150, GameWindowSize.h - 20 * (i + 1), 500, 20}); } } @@ -125,6 +200,10 @@ void SpaceScence::renderMiniMap() { Renderer::SetDrawColor(Color{255, 255, 255, 255}); Renderer::DrawRect(mapRect); + if (!PlayerSpaceship || !PlayerSpaceship->IsAlive()) { + return; + } + for (auto& entity: Entities) { if (entity != PlayerSpaceship) { const auto& pos = entity->Get()->position; @@ -183,16 +262,6 @@ void SpaceScence::renderWeapons(SpaceshipWeaponCmpt* weapon1, SpaceshipWeaponCmp } offset.y += 20; } - - // font.Render("ENERGY", - // 20, - // Point{weaponInfoRect.x, weaponInfoRect.y} + offset, - // Color{0.9, 0.3, 0.83, 1}); - // std::string energyAmount = std::to_string(PlayerCore->Get()->amount); - // font.Render(energyAmount, - // 20, - // Point{weaponInfoRect.x + weaponInfoRect.w - 20 - 20 * energyAmount.size(), weaponInfoRect.y} + offset, - // Color{0.9, 0.5, 0.8, 1}); } void SpaceScence::OnQuit() { diff --git a/src/game/stages/welcome.cpp b/src/game/stages/welcome.cpp index 9374588..d589863 100644 --- a/src/game/stages/welcome.cpp +++ b/src/game/stages/welcome.cpp @@ -29,7 +29,7 @@ void WelcomeScence::OnRender() { Point{(GameWindowSize.w - title.size() * pt) / 2, 200}, Color{0.8, 0.8, 1, 1}); - title = "HTTPS://GITEE.COM/VISUALGMQ/SPACE-SECTOR.GIT"; + title = "HTTPS://GITEE.COM/VISUALGMQ/SPACE-WAR.GIT"; pt = 10; font.Render(title, pt, Point{(GameWindowSize.w - title.size() * pt) / 2, 710}, diff --git a/src/game/system.cpp b/src/game/system.cpp index 496f932..041e787 100644 --- a/src/game/system.cpp +++ b/src/game/system.cpp @@ -56,13 +56,13 @@ void MissileUpdateSystem::updateMissile(float dt, bullet.target = nullptr; } else { Point v = bullet.target->Get()->position - move.position; - float cross = Cross(motion.speed, v); + float cross = Cross(Rotate(Point{0, -1}, bullet.rotation), v); if (cross > 0) { - bullet.rotation -= MissileRotateDegree * dt; - } else { bullet.rotation += MissileRotateDegree * dt; + } else { + bullet.rotation -= MissileRotateDegree * dt; } - Point dir = Rotate(Point{0, -1}, -bullet.rotation); + Point dir = Rotate(Point{0, -1}, bullet.rotation); motion.speed = dir * Len(motion.speed); } } @@ -98,6 +98,7 @@ void CollideSystem::Update(float dt) { entity->Get()->rect)) { if (entity->Has()) { entity->Use()->hp -= bullet->Get()->damage; + Sounds["hurt"]->Play(); } bullet->Use()->alive = false; } @@ -111,20 +112,33 @@ void CleanupSystem::Update(float dt) { ECSContext.DestroyEntity(entity); }; + for (int i = 0; i < InitInfo.groupNum; i++) { + Groups[i].RemoveAll([](const EntityPtr& entity){ + if (entity->Has() && + entity->Get()->hp <= 0) { + return true; + } else { + return false; + } + }); + } + Bullets.RemoveAll([](const EntityPtr& entity){ return !entity->Get()->alive || !IsPointInRect(MapGlobal2PlayerCoord(entity->Get()->position), BulletRefreshArea); }, destroyFunc); - Entities.RemoveAll([](const EntityPtr& entity){ + Entities.RemoveAll([&](const EntityPtr& entity){ if (entity->Has() && entity->Get()->hp <= 0) { + Sounds["explosion"]->Play(); return true; } else { return false; } }, destroyFunc); + } void WeaponCooldownSystem::Update(float dt) { @@ -154,8 +168,12 @@ void RenderEntitySystem::Render() { if (entity->Has()) { rotation = entity->Get()->degree; } - renderEntity(entity, *entity->Get(), rotation); - renderCollideBox(entity); + Color color = {1, 1, 1, 1}; + if (entity->Has()) { + color = GroupSpecColor[entity->Get()->groupIdx]; + } + renderEntity(entity, *entity->Get(), rotation, color); + // renderCollideBox(entity); } } @@ -164,8 +182,8 @@ void RenderEntitySystem::Render() { if (bullet->Get()->type == BulletCmpt::Missile) { rotation = bullet->Get()->rotation; } - renderEntity(bullet, *bullet->Get(), rotation); - renderCollideBox(bullet); + renderEntity(bullet, *bullet->Get(), rotation, Color{1, 1, 1, 1}); + // renderCollideBox(bullet); } } @@ -176,7 +194,10 @@ void RenderEntitySystem::renderCollideBox(Entity* entity) { } } -void RenderEntitySystem::renderEntity(Entity* entity, const RenderCmpt& renderCmpt, float rotation) { +void RenderEntitySystem::renderEntity(Entity* entity, + const RenderCmpt& renderCmpt, + float rotation, + const Color& color) { if (entity->Has()) { auto& pos = entity->Get()->position; if (renderCmpt.type == RenderCmpt::TypeTexture) { @@ -184,12 +205,16 @@ void RenderEntitySystem::renderEntity(Entity* entity, const RenderCmpt& renderCm nullptr, pos, Size{EntityRenderSize, EntityRenderSize}, - rotation); + rotation, + Renderer::NoFlip, + color); } else { Renderer::DrawTile(renderCmpt.tile, pos, Size{EntityRenderSize, EntityRenderSize}, - rotation); + rotation, + Renderer::NoFlip, + color); } } } diff --git a/src/tinyengine/event.cpp b/src/tinyengine/event.cpp index c65650d..5a6bb9a 100644 --- a/src/tinyengine/event.cpp +++ b/src/tinyengine/event.cpp @@ -64,6 +64,12 @@ bool IsRightPressed() { } Point GetMousePosition() { + double x, y; + glfwGetCursorPos(engine.GetWindow(), &x, &y); + return Point{float(x), float(y)}; +} + +Point GetMousePositionMapped() { double x, y; glfwGetCursorPos(engine.GetWindow(), &x, &y); return Point{float(x) * WindowInitSize.w / engine.GetWindowSize().w, diff --git a/src/tinyengine/renderer.cpp b/src/tinyengine/renderer.cpp index 0e1b808..4c09227 100644 --- a/src/tinyengine/renderer.cpp +++ b/src/tinyengine/renderer.cpp @@ -133,11 +133,12 @@ void Renderer::DrawTile(const Tile& tile, const Point& pos, const Size& size, float degree, - Renderer::FlipFlag flip) { + Renderer::FlipFlag flip, + const Color& color) { if (size.w == 0 && size.h == 0) { - DrawTexture(tile.texture, &tile.rect, pos, tile.size, degree, flip); + DrawTexture(tile.texture, &tile.rect, pos, tile.size, degree, flip, color); } else { - DrawTexture(tile.texture, &tile.rect, pos, size, degree, flip); + DrawTexture(tile.texture, &tile.rect, pos, size, degree, flip, color); } } @@ -146,7 +147,8 @@ void Renderer::DrawTexture(const Texture* texture, const Point& pos, const Size& size, float degree, - FlipFlag flip) { + FlipFlag flip, + const Color& color) { if (texture) { auto scale = size; if (size.w == 0 && size.h == 0) { @@ -158,7 +160,7 @@ void Renderer::DrawTexture(const Texture* texture, if (flip & Horizontal) { scale.w *= -1; } - DrawTexture(texture, srcrect, CreateSRT(pos, scale, degree)); + DrawTexture(texture, srcrect, CreateSRT(pos, scale, degree), color); } }