diff --git a/assets/tilesheet.png b/assets/tilesheet.png index e57a39e..aa495d4 100644 Binary files a/assets/tilesheet.png and b/assets/tilesheet.png differ diff --git a/include/game/action.hpp b/include/game/action.hpp index 9d90719..bc17258 100644 --- a/include/game/action.hpp +++ b/include/game/action.hpp @@ -5,3 +5,4 @@ #include "game/entity.hpp" void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir); +void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir, Entity* target); diff --git a/include/game/component.hpp b/include/game/component.hpp index ae30970..b60f5b9 100644 --- a/include/game/component.hpp +++ b/include/game/component.hpp @@ -2,6 +2,7 @@ #include "tinyengine/tinyengine.hpp" #include "game/constants.hpp" +#include "game/global.hpp" class MoveCmpt: public Component { public: @@ -35,21 +36,32 @@ public: Rect rect; }; -class FightShipCmpt: public Component { +class BulletCmpt: public Component { public: - void Init(float degree) { - this->degree = degree; + enum Type { + Bullet = 1, + Missile, + }; + + inline void Init(Type type, int damage, Entity* owner, Entity* target = nullptr) { + this->owner = owner; + this->damage = damage; + this->target = target; + this->type = type; + rotation = 0; + alive = true; } - void Release() {} + inline void Release() override {} - float degree; + Type type; + int damage; + Entity* owner; + Entity* target; + float rotation; + bool alive; }; -class FreightShipCmpt: public Component { -public: - void Init() {} - void Release() {} -}; + class SpaceshipWeaponCmpt: public Component { public: @@ -58,25 +70,33 @@ public: FreeRotation = 0x02, }; - void Init(Type type, + void Init(const std::string& name, + Type type, + BulletCmpt::Type bulletType, Entity* owner, int damage, float shootSpeed, float maxSpeed, float duration) { + this->name = name; this->type = type; + this->bulletType = bulletType; this->owner = owner; this->damage = damage; this->shootSpeed = shootSpeed; this->shootDuration = duration; + this->coolDown = 0; this->maxSpeed = maxSpeed; } void Release() {} bool IsCoolDowning() const { return coolDown >= 0; } Entity* ShootBullet(const Point& dir); + Entity* ShootMissile(const Point& dir, Entity* target); Type type; + BulletCmpt::Type bulletType; + std::string name; int damage; float shootSpeed; float shootDuration; @@ -96,6 +116,34 @@ public: float recoverDuration; }; +class FreightShipCmpt: public Component { +public: + void Init(SpaceshipWeaponCmpt* weapon) { + this->weapon = weapon; + } + void Release() { ECSContext.DestroyComponent(weapon); } + + SpaceshipWeaponCmpt* weapon; +}; + + +class FightShipCmpt: public Component { +public: + void Init(SpaceshipWeaponCmpt* weapon1, SpaceshipWeaponCmpt* weapon2) { + this->degree = 0; + this->weapon1 = weapon1; + this->weapon2 = weapon2; + } + void Release() { + ECSContext.DestroyComponent(weapon1); + ECSContext.DestroyComponent(weapon2); + } + + float degree; + SpaceshipWeaponCmpt* weapon1; + SpaceshipWeaponCmpt* weapon2; +}; + class LifeCmpt: public Component { public: void Init(int hp) { this->hp = hp; } @@ -128,16 +176,3 @@ public: }; }; -class BulletCmpt: public Component { -public: - inline void Init(int damage, Entity* owner) { - this->owner = owner; - this->damage = damage; - alive = true; - } - inline void Release() override {} - - int damage; - Entity* owner; - bool alive; -}; diff --git a/include/game/constants.hpp b/include/game/constants.hpp index ee3fcc4..bd2017c 100644 --- a/include/game/constants.hpp +++ b/include/game/constants.hpp @@ -9,8 +9,9 @@ constexpr float LazerDamage = 2; constexpr float LazerShooterSpeed = 500; constexpr float LazerShooterMaxSpeed = 1000; constexpr float LazerShooterCooldown = 0.3; +constexpr float MissileRotateDegree = 150; constexpr Size GameWindowSize = {1024, 720}; constexpr Rect BulletRefreshArea{-100, -100, 1124, 820}; -constexpr Rect SpaceshipRefreshArea{-1024 * 3, -720 * 3, 1024 * 4, 720 * 4}; +constexpr Rect SpaceshipRefreshArea{-1024 * 3, -720 * 3, 1024 * 7, 720 * 7}; diff --git a/include/game/controllers/fightship_controller.hpp b/include/game/controllers/fightship_controller.hpp index c860a47..084711b 100644 --- a/include/game/controllers/fightship_controller.hpp +++ b/include/game/controllers/fightship_controller.hpp @@ -13,4 +13,6 @@ public: private: Entity* entity_; + + void weaponShoot(SpaceshipWeaponCmpt* weapon, const MoveCmpt& move); }; diff --git a/include/game/entity.hpp b/include/game/entity.hpp index 853fc00..64d09b8 100644 --- a/include/game/entity.hpp +++ b/include/game/entity.hpp @@ -6,4 +6,5 @@ Entity* CreateFreightShip(); Entity* CreateFightShip(); -Entity* CreateBullet(int damage, Entity* owner, float maxSpeedß); +Entity* CreateBullet(int damage, Entity* owner, float maxSpeed); +Entity* CreateMissile(int damage, Entity* owner, float maxSpeed, Entity* target); diff --git a/include/game/global.hpp b/include/game/global.hpp index 0e38b9a..f7b61ca 100644 --- a/include/game/global.hpp +++ b/include/game/global.hpp @@ -15,3 +15,4 @@ extern Entity* PlayerSpaceship; void LoadResources(); Point MapGlobal2PlayerCoord(const Point& pos); +Point MapPlayerCoord2Global(const Point& pos); diff --git a/include/game/stages/space.hpp b/include/game/stages/space.hpp index c44cb3b..c5b3267 100644 --- a/include/game/stages/space.hpp +++ b/include/game/stages/space.hpp @@ -20,6 +20,7 @@ private: void renderGUI(); void renderMiniMap(); + void renderWeapons(SpaceshipWeaponCmpt* weapon1, SpaceshipWeaponCmpt* weapon2); Camera guiCamera_; Camera gameCamera_; diff --git a/include/game/system.hpp b/include/game/system.hpp index 195a9ae..ff3638d 100644 --- a/include/game/system.hpp +++ b/include/game/system.hpp @@ -14,6 +14,14 @@ private: void physicalStep(Entity* entity, float dt, MoveCmpt&, MotionCmpt&); }; +class MissileUpdateSystem: public UpdateSystem { +public: + void Update(float dt) override; + +private: + void updateMissile(float dt, BulletCmpt&, MoveCmpt&, MotionCmpt&); +}; + class ColliRectCorrectSystem: public UpdateSystem { public: void Update(float dt) override; @@ -32,9 +40,12 @@ public: void Update(float dt) override; }; -class BulletCooldownSystem: public UpdateSystem { +class WeaponCooldownSystem: public UpdateSystem { public: void Update(float dt) override; + +private: + void coolDown(SpaceshipWeaponCmpt& weapon, float dt); }; class RenderEntitySystem: public RenderSystem { @@ -42,6 +53,6 @@ public: void Render() override; private: - void renderEntity(Entity* entity, const RenderCmpt&); + void renderEntity(Entity* entity, const RenderCmpt&, float rotation); void renderCollideBox(Entity* entity); }; diff --git a/include/tinyengine/libmath.hpp b/include/tinyengine/libmath.hpp index 481c3ee..e20a076 100644 --- a/include/tinyengine/libmath.hpp +++ b/include/tinyengine/libmath.hpp @@ -125,11 +125,15 @@ inline double Radians(double degree) { return degree * M_PI / 180.0; } -inline double Degress(double radians) { +inline double Degrees(double radians) { return radians * 180.0 / M_PI; } -inline double Cross2D(const Point& v1, const Point& v2) { +inline double Dot(const Point& v1, const Point& v2) { + return v1.x * v2.x + v1.y * v2.y; +} + +inline double Cross(const Point& v1, const Point& v2) { return v1.x * v2.y - v2.x * v1.y; } diff --git a/src/game/action.cpp b/src/game/action.cpp index 3665e26..ccc269d 100644 --- a/src/game/action.cpp +++ b/src/game/action.cpp @@ -1,7 +1,9 @@ #include "game/action.hpp" void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir) { - if (weapon.IsCoolDowning()) return; + if (weapon.IsCoolDowning()) { + return; + } Point playerCenterPos = weapon.owner->Get()->position; @@ -13,3 +15,24 @@ void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir) { Sounds["shoot"]->Play(); } + +void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir, Entity* target) { + if (weapon.IsCoolDowning()) { + return; + } + + Point playerCenterPos = weapon.owner->Get()->position; + + Entity* bullet; + bullet = weapon.ShootMissile(dir, target); + + // FIXME the rotation have some bugs + bullet->Use()->rotation = Degrees(std::acos(-Normalize(dir).y)); + + Bullets.Add(bullet); + + weapon.coolDown = weapon.shootDuration; + + Sounds["shoot"]->Play(); +} + diff --git a/src/game/component.cpp b/src/game/component.cpp index 48d01f0..a354e64 100644 --- a/src/game/component.cpp +++ b/src/game/component.cpp @@ -7,3 +7,13 @@ Entity* SpaceshipWeaponCmpt::ShootBullet(const Point& dir) { bullet->Use()->position = owner->Get()->position; return bullet; } + +Entity* SpaceshipWeaponCmpt::ShootMissile(const Point& dir, Entity* target) { + Entity* bullet = CreateMissile(damage, owner, maxSpeed, target); + if (target) { + bullet->Use()->rotation = Degrees(std::acos(Dot(dir, Normalize(target->Get()->position - owner->Get()->position)))); + } + bullet->Use()->speed = Normalize(dir) * shootSpeed; + bullet->Use()->position = owner->Get()->position; + return bullet; +} diff --git a/src/game/controllers/fightship_controller.cpp b/src/game/controllers/fightship_controller.cpp index 511cec7..e0a2e2f 100644 --- a/src/game/controllers/fightship_controller.cpp +++ b/src/game/controllers/fightship_controller.cpp @@ -24,16 +24,39 @@ void FightShipController::Update(float dt) { motionCmpt->speed = Rotate(Point{0, -1} * Len(motionCmpt->speed), -rotation); + auto fightShip = entity_->Use(); + auto weapon1 = fightShip->weapon1, + weapon2 = fightShip->weapon2; + auto moveCmpt = entity_->Get(); + if (IsLeftPressing()) { - if (entity_->Has()) { - auto weapon = entity_->Use(); - if (weapon->type == SpaceshipWeaponCmpt::Orientation) { - Shoot(*weapon, - Rotate(Point{0, -1}, -entity_->Get()->degree)); - } else { - Shoot(*weapon, - GetMousePosition() - entity_->Get()->position); - } - } + weaponShoot(weapon1, *moveCmpt); + } + if (IsRightPressing()) { + weaponShoot(weapon2, *moveCmpt); + } +} + +void FightShipController::weaponShoot(SpaceshipWeaponCmpt* weapon, const MoveCmpt& move) { + if (!weapon) return; + Point dir; + if (weapon->type == SpaceshipWeaponCmpt::Orientation) { + dir = Rotate(Point{0, -1}, -entity_->Get()->degree); + } else { + dir = GetMousePosition() - entity_->Get()->position; + } + + if (weapon->bulletType == BulletCmpt::Bullet) { + Shoot(*weapon, dir); + } else { + Entity* target = nullptr; + for (auto& entity : Entities) { + if (entity != entity_ && + IsPointInRect(MapPlayerCoord2Global(GetMousePosition()), entity->Get()->rect)) { + target = entity; + break; + } + } + Shoot(*weapon, dir, target); } } diff --git a/src/game/controllers/freightship_controller.cpp b/src/game/controllers/freightship_controller.cpp index 583703b..b0ba880 100644 --- a/src/game/controllers/freightship_controller.cpp +++ b/src/game/controllers/freightship_controller.cpp @@ -8,30 +8,22 @@ void FreightShipController::Update(float dt) { const float spd = 100; auto motionCmpt = entity_->Use(); if (IsKeyPressing(GLFW_KEY_A)) { - // motionCmpt->speed += Point{-spd, 0}; motionCmpt->acceleration += Point{-spd, 0}; - // motionCmpt->speed.x = -spd; } if (IsKeyPressing(GLFW_KEY_D)) { - // motionCmpt->speed += Point{spd, 0}; motionCmpt->acceleration += Point{spd, 0}; - // motionCmpt->speed.x = spd; } if (IsKeyPressing(GLFW_KEY_S)) { - // motionCmpt->speed += Point{0, spd}; motionCmpt->acceleration += Point{0, spd}; - // motionCmpt->speed.y = spd; } if (IsKeyPressing(GLFW_KEY_W)) { - // motionCmpt->speed += Point{0, -spd}; motionCmpt->acceleration += Point{0, -spd}; - // motionCmpt->speed.y = -spd; } if (IsLeftPressing()) { - if (entity_->Has()) { + auto weapon = entity_->Use()->weapon; + if (weapon) { // FIXME duplicated codes in here and fightship_controller.cpp - auto weapon = entity_->Use(); if (weapon->type == SpaceshipWeaponCmpt::Orientation) { Shoot(*weapon, Rotate(Point{0, -1}, entity_->Get()->degree)); diff --git a/src/game/entity.cpp b/src/game/entity.cpp index ccb248f..0b2924b 100644 --- a/src/game/entity.cpp +++ b/src/game/entity.cpp @@ -6,15 +6,17 @@ Entity* CreateFreightShip() { entity->Add(Point{0, 0}); entity->Add(Point{0, 0}, FreightShipMaxSpeed); entity->Add(GameTileSheet->GetTile(0, 0)); - entity->Add(SpaceshipWeaponCmpt::FreeRotation, - entity, - LazerDamage, - LazerShooterSpeed, - LazerShooterMaxSpeed, - LazerShooterCooldown); + auto weapon = ECSContext.CreateComponent("BULLET", + SpaceshipWeaponCmpt::FreeRotation, + BulletCmpt::Bullet, + entity, + LazerDamage, + LazerShooterSpeed, + LazerShooterMaxSpeed, + LazerShooterCooldown); entity->Add(Size{16, 16}); entity->Add(FreightLife); - entity->Add(); + entity->Add(weapon); return entity; } @@ -23,15 +25,27 @@ Entity* CreateFightShip() { entity->Add(Point{0, 0}); entity->Add(Point{0, 0}, FightShipMaxSpeed); entity->Add(GameTileSheet->GetTile(1, 0)); - entity->Add(SpaceshipWeaponCmpt::Orientation, - entity, - LazerDamage, - LazerShooterSpeed, - LazerShooterMaxSpeed, - LazerShooterCooldown); + + auto weapon1 = ECSContext.CreateComponent("BULLET", + SpaceshipWeaponCmpt::Orientation, + BulletCmpt::Bullet, + entity, + LazerDamage, + LazerShooterSpeed, + LazerShooterMaxSpeed, + LazerShooterCooldown); + auto weapon2 = ECSContext.CreateComponent("MISSILE", + SpaceshipWeaponCmpt::Orientation, + BulletCmpt::Missile, + entity, + LazerDamage, + LazerShooterSpeed, + LazerShooterMaxSpeed, + LazerShooterCooldown); + entity->Add(Size{16, 16}); entity->Add(FreightLife); - entity->Add(0); + entity->Add(weapon1, weapon2); return entity; } @@ -40,7 +54,17 @@ Entity* CreateBullet(int damage, Entity* owner, float maxSpeed) { entity->Add(Point{0, 0}); entity->Add(Point{0, 0}, maxSpeed); entity->Add(GameTileSheet->GetTile(0, 1)); - entity->Add(damage, owner); + entity->Add(BulletCmpt::Bullet, damage, owner); entity->Add(Size{8, 8}); return entity; } + +Entity* CreateMissile(int damage, Entity* owner, float maxSpeed, Entity* target) { + Entity* entity = ECSContext.CreateEntity(); + entity->Add(Point{0, 0}); + entity->Add(Point{0, 0}, maxSpeed); + entity->Add(GameTileSheet->GetTile(2, 1)); + entity->Add(BulletCmpt::Missile, damage, owner, target); + entity->Add(Size{10, 10}); + return entity; +} diff --git a/src/game/global.cpp b/src/game/global.cpp index ebd357c..950b5de 100644 --- a/src/game/global.cpp +++ b/src/game/global.cpp @@ -31,3 +31,11 @@ Point MapGlobal2PlayerCoord(const Point& pos) { return pos; } } + +Point MapPlayerCoord2Global(const Point& pos) { + if (PlayerSpaceship && PlayerSpaceship->Has()) { + return pos + PlayerSpaceship->Get()->position - GameWindowSize / 2; + } else { + return pos; + } +} diff --git a/src/game/main.cpp b/src/game/main.cpp index 901e4a9..8a27ade 100644 --- a/src/game/main.cpp +++ b/src/game/main.cpp @@ -3,3 +3,4 @@ #include "game/constants.hpp" RUN_WINDOW("Space Sector", GameWindowSize.w, GameWindowSize.h, SpaceScence) +// RUN_WINDOW("Space Sector", GameWindowSize.w, GameWindowSize.h, GameLogoScence) diff --git a/src/game/stages/gamelogo.cpp b/src/game/stages/gamelogo.cpp index 31937aa..30e4f7a 100644 --- a/src/game/stages/gamelogo.cpp +++ b/src/game/stages/gamelogo.cpp @@ -1,4 +1,5 @@ #include "game/stages/gamelogo.hpp" +#include "game/stages/space.hpp" constexpr float TitlePixel = 40.0f; constexpr float AuthorInfoPixel = 20.0f; @@ -38,4 +39,8 @@ void GameLogoScence::OnRender() { Size{AuthorInfoPixel * strlen(AuthorInfo), AuthorInfoPixel}), Color{0.5, 0.5, 0.5, 1}); } + + if (duration > 4) { + engine.ChangeScence(new SpaceScence); + } } diff --git a/src/game/stages/space.cpp b/src/game/stages/space.cpp index 66aba08..f92d45b 100644 --- a/src/game/stages/space.cpp +++ b/src/game/stages/space.cpp @@ -29,7 +29,8 @@ void SpaceScence::OnInit() { gameCamera_.SetAnchor(GameWindowSize / 2); SystemMgr.Clear(); - SystemMgr.AddUpdateSystem(new BulletCooldownSystem); + SystemMgr.AddUpdateSystem(new WeaponCooldownSystem); + SystemMgr.AddUpdateSystem(new MissileUpdateSystem); SystemMgr.AddUpdateSystem(new PhysicalSystem); SystemMgr.AddUpdateSystem(new ColliRectCorrectSystem); SystemMgr.AddUpdateSystem(new CollideSystem); @@ -62,6 +63,12 @@ void SpaceScence::renderGUI() { } renderMiniMap(); + if (PlayerSpaceship->Has()) { + renderWeapons(PlayerSpaceship->Get()->weapon, nullptr); + } else { + auto fightShip = PlayerSpaceship->Get(); + renderWeapons(fightShip->weapon1, fightShip->weapon2); + } } void SpaceScence::renderMiniMap() { @@ -90,6 +97,35 @@ void SpaceScence::renderMiniMap() { } } +void SpaceScence::renderWeapons(SpaceshipWeaponCmpt* weapon1, SpaceshipWeaponCmpt* weapon2) { + Rect mapRect = {0, 0, 200, 100}; + mapRect.y = GameWindowSize.h - mapRect.h; + mapRect.x = GameWindowSize.w - mapRect.w - 1; + + Renderer::SetDrawColor(Color{0, 0, 0, 255}); + Renderer::FillRect(mapRect); + Renderer::SetDrawColor(Color{255, 255, 255, 255}); + Renderer::DrawRect(mapRect); + + Point offset = {10, 10}; + auto& font = engine.GetInnerBmpFont(); + + if (weapon1) { + font.Render(weapon1->name, + 20, + Point{mapRect.x, mapRect.y} + offset, + Color{0, 200, 0, 255}); + offset.y += 20; + } + if (weapon2) { + font.Render(weapon2->name, + 20, + Point{mapRect.x, mapRect.y} + offset, + Color{0, 50, 0, 255}); + } + +} + void SpaceScence::OnQuit() { } diff --git a/src/game/system.cpp b/src/game/system.cpp index f045f00..a583ca2 100644 --- a/src/game/system.cpp +++ b/src/game/system.cpp @@ -37,6 +37,38 @@ void PhysicalSystem::physicalStep(Entity* entity, motionCmpt.acceleration = Point{0, 0}; } +void MissileUpdateSystem::Update(float dt) { + for (auto& bullet : Bullets) { + if (bullet->Get()->type == BulletCmpt::Missile) { + updateMissile(dt, + *bullet->Use(), + *bullet->Use(), + *bullet->Use()); + } + } +} + +void MissileUpdateSystem::updateMissile(float dt, + BulletCmpt& bullet, + MoveCmpt& move, + MotionCmpt& motion) { + if (bullet.target) { + if (!bullet.target->IsAlive()) { + bullet.target = nullptr; + } else { + Point v = bullet.target->Get()->position - move.position; + float cross = Cross(motion.speed, v); + if (cross > 0) { + bullet.rotation -= MissileRotateDegree * dt; + } else { + bullet.rotation += MissileRotateDegree * dt; + } + Point dir = Rotate(Point{0, -1}, -bullet.rotation); + motion.speed = dir * Len(motion.speed); + } + } +} + void ColliRectCorrectSystem::Update(float dt) { for (auto& entity: Entities) { if (entity->Has()) { @@ -89,7 +121,8 @@ void CleanupSystem::Update(float dt) { if (entity->Has() && entity->Get()->hp <= 0 || entity->Has() && - !IsPointInRect(MapGlobal2PlayerCoord(entity->Get()->position), SpaceshipRefreshArea)) { + !IsPointInRect(MapGlobal2PlayerCoord(entity->Get()->position), + SpaceshipRefreshArea)) { return true; } else { return false; @@ -97,27 +130,44 @@ void CleanupSystem::Update(float dt) { }, destroyFunc); } -void BulletCooldownSystem::Update(float dt) { +void WeaponCooldownSystem::Update(float dt) { for (auto& entity : Entities) { - if (entity->Has()) { - auto weapon = entity->Use(); - if (weapon->coolDown >= 0) { - weapon->coolDown -= dt; - } + if (entity->Has()) { + auto weapon = entity->Use()->weapon; + coolDown(*weapon, dt); } + if (entity->Has()) { + auto fightShip = entity->Use(); + coolDown(*fightShip->weapon1, dt); + coolDown(*fightShip->weapon2, dt); + } + } +} + +void WeaponCooldownSystem::coolDown(SpaceshipWeaponCmpt& weapon, float dt) { + if (weapon.coolDown >= 0) { + weapon.coolDown -= dt; } } void RenderEntitySystem::Render() { for (auto& entity: Entities) { if (entity->Has()) { - renderEntity(entity, *entity->Get()); + float rotation = 0; + if (entity->Has()) { + rotation = entity->Get()->degree; + } + renderEntity(entity, *entity->Get(), rotation); renderCollideBox(entity); } } - + for (auto& bullet: Bullets) { - renderEntity(bullet, *bullet->Get()); + float rotation = 0; + if (bullet->Get()->type == BulletCmpt::Missile) { + rotation = bullet->Get()->rotation; + } + renderEntity(bullet, *bullet->Get(), rotation); renderCollideBox(bullet); } } @@ -129,24 +179,20 @@ void RenderEntitySystem::renderCollideBox(Entity* entity) { } } -void RenderEntitySystem::renderEntity(Entity* entity, const RenderCmpt& renderCmpt) { +void RenderEntitySystem::renderEntity(Entity* entity, const RenderCmpt& renderCmpt, float rotation) { if (entity->Has()) { auto& pos = entity->Get()->position; - float degree = 0; - if (entity->Has()) { - degree = entity->Get()->degree; - } if (renderCmpt.type == RenderCmpt::TypeTexture) { Renderer::DrawTexture(renderCmpt.texture, nullptr, pos, Size{0, 0}, - degree); + rotation); } else { Renderer::DrawTile(renderCmpt.tile, pos, Size{0, 0}, - degree); + rotation); } } }