fixed fight ship ai bug; improved freight ship

This commit is contained in:
VisualGMQ 2022-02-17 15:12:24 +08:00
parent 559cfda2da
commit 945ee99e41
31 changed files with 345 additions and 124 deletions

42
HowToPlay.md Normal file
View File

@ -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进行加速和减速不能向后倒着飞鼠标左键使用炮弹鼠标右键发射导弹导弹有数量限制
切换飞机:
当你控制的飞机死亡后,视角会转到我方阵营的另一架飞机上,此时可以选择按空格键操控这辆飞机。
胜利条件:
全灭其他所有阵营获得胜利

View File

@ -24,3 +24,15 @@ pack.sh
``` ```
最终的结果在`output`文件夹下。 最终的结果在`output`文件夹下。
## 游戏截图
![welcome](./snapshot/welcome.png)
![select](./snapshot/select_ship.png)
![gaming](./snapshot/gaming.png)
## 游戏操作
[游戏操作](./HowToPlay.md)

BIN
assets/explose.wav Normal file

Binary file not shown.

BIN
assets/hurt.wav Normal file

Binary file not shown.

BIN
assets/missile.wav Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -228,8 +228,10 @@ public:
void Init(AIFunc func) { void Init(AIFunc func) {
this->func = func; this->func = func;
target = nullptr;
} }
void Release() {} void Release() {}
AIFunc func; AIFunc func;
Entity* target;
}; };

View File

@ -7,9 +7,10 @@ constexpr int FightShipLife = 10;
constexpr float FightShipRotationDegree = 6; constexpr float FightShipRotationDegree = 6;
constexpr float FightShipAccelration = 200; constexpr float FightShipAccelration = 200;
constexpr float FreightShipMaxSpeed = 100; constexpr float FreightShipMaxSpeed = 200;
constexpr int FreightShipLife = 15; constexpr int FreightShipLife = 20;
constexpr float FreightShipAccelerate = 100; constexpr float FreightShipAccelerate = 100;
constexpr float FreightShipLazerDelay = 0.3;
constexpr float LazerDamage = 3.4; constexpr float LazerDamage = 3.4;
constexpr float LazerShooterSpeed = 800; constexpr float LazerShooterSpeed = 800;
@ -34,3 +35,10 @@ constexpr int Enemy3Group = 3;
constexpr float EntityRenderSize = 20; constexpr float EntityRenderSize = 20;
constexpr float EntityCollisionSize = 16; 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}
};

View File

@ -12,6 +12,8 @@ public:
datas_.push_back(elem); datas_.push_back(elem);
} }
bool Empty() const { return datas_.empty(); }
void RemoveAll(condition_func findFunc, void RemoveAll(condition_func findFunc,
destroy_func destroyFunc = nullptr) { destroy_func destroyFunc = nullptr) {
std::size_t idx = 0; std::size_t idx = 0;
@ -48,6 +50,11 @@ public:
printf("\n"); printf("\n");
} }
size_t Size() const { return datas_.size(); }
T& Get(size_t idx) { return datas_[idx]; }
using const_iterator = typename std::vector<T>::const_iterator; using const_iterator = typename std::vector<T>::const_iterator;
const_iterator begin() const { return datas_.begin(); } const_iterator begin() const { return datas_.begin(); }

View File

@ -16,15 +16,23 @@ public:
void OnQuit() override; void OnQuit() override;
private: private:
Unique<FightShipController> fightController_; Unique<Controller> controller_;
Camera guiCamera_;
Camera gameCamera_;
Entity* lookAtEntity_;
std::vector<Point> stars_;
int groupHps[4] = {0};
void renderBackground(); void renderBackground();
void renderGUI(); void renderGUI();
void renderMiniMap(); void renderMiniMap();
void renderWeapons(SpaceshipWeaponCmpt* weapon1, SpaceshipWeaponCmpt* weapon2); void renderWeapons(SpaceshipWeaponCmpt* weapon1, SpaceshipWeaponCmpt* weapon2);
void initEnemies();
Camera guiCamera_; void attachController();
Camera gameCamera_; void generateEnemiesAt(int group, const Point& p, int num);
void initPlayer();
std::vector<Point> stars_; void calcGroupHps();
void drawGroupHp();
}; };

View File

@ -53,7 +53,7 @@ public:
void Render() override; void Render() override;
private: private:
void renderEntity(Entity* entity, const RenderCmpt&, float rotation); void renderEntity(Entity* entity, const RenderCmpt&, float rotation, const Color&);
void renderCollideBox(Entity* entity); void renderCollideBox(Entity* entity);
}; };

View File

@ -11,6 +11,7 @@ bool IsRightPressing();
bool IsLeftPressed(); bool IsLeftPressed();
bool IsRightPressed(); bool IsRightPressed();
Point GetMousePosition(); Point GetMousePosition();
Point GetMousePositionMapped();
void EventUpdate(); void EventUpdate();

View File

@ -195,8 +195,8 @@ inline Mat44 CreateSRT(const Point& pos, const Point& scale, float degree) {
float sinTheta = std::sin(theta), float sinTheta = std::sin(theta),
cosTheta = std::cos(theta); cosTheta = std::cos(theta);
return Mat44({ return Mat44({
scale.x * cosTheta, scale.y * sinTheta, 0, pos.x, scale.x * cosTheta,-scale.y * sinTheta, 0, pos.x,
-scale.x * sinTheta, scale.y * cosTheta, 0, pos.y, scale.x * sinTheta, scale.y * cosTheta, 0, pos.y,
0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1, 0, 0, 0, 1,
}); });

View File

@ -31,15 +31,17 @@ public:
static void FillRect(const Rect& rect); static void FillRect(const Rect& rect);
static void DrawTile(const Tile& tile, static void DrawTile(const Tile& tile,
const Point& pos, const Point& pos,
const Size& size = {0, 0}, const Size& = {0, 0},
float degree = 0, float degree = 0,
FlipFlag flip = NoFlip); FlipFlag = NoFlip,
const Color& = {1, 1, 1, 1});
static void DrawTexture(const Texture* texture, static void DrawTexture(const Texture* texture,
const Rect* srcrect, const Rect* srcrect,
const Point& pos, const Point& pos,
const Size& size = Size{0, 0}, const Size& = Size{0, 0},
float degree = 0, float degree = 0,
FlipFlag flip = NoFlip); FlipFlag = NoFlip,
const Color& = {1, 1, 1, 1});
static void DrawTexture(const Texture* texture, static void DrawTexture(const Texture* texture,
const Rect* rect, const Rect* rect,
const Mat44& transform, const Mat44& transform,

View File

@ -8,3 +8,5 @@ mkdir output
cp ./build/SpaceSector output cp ./build/SpaceSector output
cp -r ./assets output cp -r ./assets output
rm -rf ./output/assets/test rm -rf ./output/assets/test
cp ./HowToPlay.md output/
cp -r ./snapshot output

BIN
snapshot/gaming.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
snapshot/select_ship.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
snapshot/welcome.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@ -5,8 +5,6 @@ void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir) {
return; return;
} }
Point playerCenterPos = weapon.owner->Get<MoveCmpt>()->position;
Entity* bullet; Entity* bullet;
bullet = weapon.ShootBullet(dir); bullet = weapon.ShootBullet(dir);
if (bullet) { if (bullet) {
@ -26,8 +24,7 @@ void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir, Entity* target) {
Entity* bullet; Entity* bullet;
bullet = weapon.ShootMissile(dir, target); bullet = weapon.ShootMissile(dir, target);
if (bullet) { if (bullet) {
// FIXME the rotation have some bugs bullet->Use<BulletCmpt>()->rotation = Sign(dir.x) * Degrees(std::acos(-Normalize(dir).y));
bullet->Use<BulletCmpt>()->rotation = Degrees(std::acos(-Normalize(dir).y));
Bullets.Add(bullet); Bullets.Add(bullet);
weapon.coolDown = weapon.shootDuration; weapon.coolDown = weapon.shootDuration;
Sounds["shoot"]->Play(); Sounds["shoot"]->Play();
@ -51,19 +48,19 @@ void MoveDown(MotionCmpt& motion) {
} }
void SpeedUp(MotionCmpt& motion, FightShipCmpt& ship) { void SpeedUp(MotionCmpt& motion, FightShipCmpt& ship) {
motion.acceleration = Rotate(Point{0, FightShipAccelration}, motion.acceleration = Rotate(Point{0, -FightShipAccelration},
-ship.degree); ship.degree);
} }
void SpeedDown(MotionCmpt& motion, FightShipCmpt& ship) { void SpeedDown(MotionCmpt& motion, FightShipCmpt& ship) {
motion.acceleration = Rotate(Point{0, -FightShipAccelration}, motion.acceleration = Rotate(Point{0, FightShipAccelration},
-ship.degree); ship.degree);
} }
void TurnLeft(FightShipCmpt& ship) { void TurnLeft(FightShipCmpt& ship) {
ship.degree += FightShipRotationDegree; ship.degree -= FightShipRotationDegree;
} }
void TurnRight(FightShipCmpt& ship) { void TurnRight(FightShipCmpt& ship) {
ship.degree -= FightShipRotationDegree; ship.degree += FightShipRotationDegree;
} }

View File

@ -1,7 +1,27 @@
#include "game/ai.hpp" #include "game/ai.hpp"
Entity* findRandomEntity(Entity* self) {
int groupIdx = Random<int>(0, 3);
if (groupIdx == self->Get<GroupCmpt>()->groupIdx) {
groupIdx ++;
if (groupIdx >= 4) {
groupIdx = 0;
}
}
auto& group = Groups[groupIdx];
if (group.Empty())
return nullptr;
return group.Get(Random<int>(1, group.Size()) - 1);
}
void FreightShipAI(Entity* self) { void FreightShipAI(Entity* self) {
auto pmove = PlayerSpaceship->Get<MoveCmpt>(); auto ai = self->Use<AICmpt>();
if (!ai->target || !ai->target->IsAlive()) {
ai->target = findRandomEntity(self);
}
if (!ai->target) return;
auto pmove = ai->target->Get<MoveCmpt>();
auto smove = self->Get<MoveCmpt>(); auto smove = self->Get<MoveCmpt>();
auto dir = pmove->position - smove->position; auto dir = pmove->position - smove->position;
if (Len2(dir) > 250000) { if (Len2(dir) > 250000) {
@ -22,29 +42,35 @@ void FreightShipAI(Entity* self) {
} }
void FightShipAI(Entity* self) { void FightShipAI(Entity* self) {
auto pmove = PlayerSpaceship->Get<MoveCmpt>(); auto ai = self->Use<AICmpt>();
if (!ai->target || !ai->target->IsAlive()) {
ai->target = findRandomEntity(self);
}
if (!ai->target) return;
auto pmove = ai->target->Get<MoveCmpt>();
auto smove = self->Get<MoveCmpt>(); auto smove = self->Get<MoveCmpt>();
auto dir = pmove->position - smove->position; auto dir = pmove->position - smove->position;
auto motion = self->Use<MotionCmpt>(); auto motion = self->Use<MotionCmpt>();
auto ship = self->Use<FightShipCmpt>(); auto ship = self->Use<FightShipCmpt>();
auto nspd = Normalize(motion->speed), auto ndir = Normalize(dir);
ndir = Normalize(dir);
SpeedUp(*motion, *ship); SpeedUp(*motion, *ship);
auto cross = Cross(nspd, ndir); auto shipDir = Rotate(Point{0, -1}, self->Get<FightShipCmpt>()->degree);
if (cross > std::sin(Radians(80))) { auto cross = Cross(shipDir, ndir);
TurnLeft(*ship); if (cross > 0) {
} else if (cross < std::sin(Radians(10))) {
TurnRight(*ship); 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);
// }
// }
} }

View File

@ -23,5 +23,6 @@ Entity* SpaceshipWeaponCmpt::ShootMissile(const Point& dir, Entity* target) {
} }
bullet->Use<MotionCmpt>()->speed = Normalize(dir) * shootSpeed; bullet->Use<MotionCmpt>()->speed = Normalize(dir) * shootSpeed;
bullet->Use<MoveCmpt>()->position = owner->Get<MoveCmpt>()->position; bullet->Use<MoveCmpt>()->position = owner->Get<MoveCmpt>()->position;
Sounds["missile"]->Play();
return bullet; return bullet;
} }

View File

@ -5,6 +5,10 @@ FightShipController::FightShipController(Entity* entity)
: entity_(entity) {} : entity_(entity) {}
void FightShipController::Update(float dt) { void FightShipController::Update(float dt) {
if (!entity_ || !entity_->IsAlive()) {
return;
}
const float spd = 100; const float spd = 100;
auto motionCmpt = entity_->Use<MotionCmpt>(); auto motionCmpt = entity_->Use<MotionCmpt>();
auto ship = entity_->Use<FightShipCmpt>(); auto ship = entity_->Use<FightShipCmpt>();
@ -15,14 +19,14 @@ void FightShipController::Update(float dt) {
TurnRight(*ship); TurnRight(*ship);
} }
if (IsKeyPressing(GLFW_KEY_S)) { if (IsKeyPressing(GLFW_KEY_S)) {
SpeedUp(*motionCmpt, *ship); SpeedDown(*motionCmpt, *ship);
} }
if (IsKeyPressing(GLFW_KEY_W)) { if (IsKeyPressing(GLFW_KEY_W)) {
SpeedDown(*motionCmpt, *ship); SpeedUp(*motionCmpt, *ship);
} }
motionCmpt->speed = Rotate(Point{0, -1} * Len(motionCmpt->speed), motionCmpt->speed = Rotate(Point{0, -1} * Len(motionCmpt->speed),
-ship->degree); ship->degree);
auto moveCmpt = entity_->Get<MoveCmpt>(); auto moveCmpt = entity_->Get<MoveCmpt>();
@ -46,9 +50,9 @@ void FightShipController::weaponShoot(SpaceshipWeaponCmpt* weapon, const MoveCmp
if (!weapon) return; if (!weapon) return;
Point dir; Point dir;
if (weapon->type == SpaceshipWeaponCmpt::Orientation) { if (weapon->type == SpaceshipWeaponCmpt::Orientation) {
dir = Rotate(Point{0, -1}, -entity_->Get<FightShipCmpt>()->degree); dir = Rotate(Point{0, -1}, entity_->Get<FightShipCmpt>()->degree);
} else { } else {
dir = GetMousePosition() - entity_->Get<MoveCmpt>()->position; dir = GetMousePosition() - GameWindowSize / 2;
} }
if (weapon->bulletType == BulletCmpt::Bullet) { if (weapon->bulletType == BulletCmpt::Bullet) {
@ -57,7 +61,7 @@ void FightShipController::weaponShoot(SpaceshipWeaponCmpt* weapon, const MoveCmp
Entity* target = nullptr; Entity* target = nullptr;
for (auto& entity : Entities) { for (auto& entity : Entities) {
if (entity != entity_ && if (entity != entity_ &&
IsPointInRect(MapPlayerCoord2Global(GetMousePosition()), entity->Get<CollisionCmpt>()->rect)) { IsPointInRect(MapPlayerCoord2Global(GetMousePositionMapped()), entity->Get<CollisionCmpt>()->rect)) {
target = entity; target = entity;
break; break;
} }

View File

@ -5,6 +5,10 @@ FreightShipController::FreightShipController(Entity* entity)
: entity_(entity) {} : entity_(entity) {}
void FreightShipController::Update(float dt) { void FreightShipController::Update(float dt) {
if (!entity_ || !entity_->IsAlive()) {
return;
}
const float spd = 100; const float spd = 100;
auto motionCmpt = entity_->Use<MotionCmpt>(); auto motionCmpt = entity_->Use<MotionCmpt>();
if (IsKeyPressing(GLFW_KEY_A)) { if (IsKeyPressing(GLFW_KEY_A)) {
@ -29,7 +33,7 @@ void FreightShipController::Update(float dt) {
Rotate(Point{0, -1}, entity_->Get<FightShipCmpt>()->degree)); Rotate(Point{0, -1}, entity_->Get<FightShipCmpt>()->degree));
} else { } else {
Shoot(*weapon, Shoot(*weapon,
GetMousePosition() - entity_->Get<MoveCmpt>()->position); GetMousePosition() - GameWindowSize / 2);
} }
} }
} }

View File

@ -13,7 +13,7 @@ Entity* CreateFreightShip(int group) {
LazerDamage, LazerDamage,
LazerShooterSpeed, LazerShooterSpeed,
LazerShooterMaxSpeed, LazerShooterMaxSpeed,
LazerShooterCooldown + 1); LazerShooterCooldown + FreightShipLazerDelay);
entity->Add<CollisionCmpt>(Size{EntityCollisionSize, EntityCollisionSize}); entity->Add<CollisionCmpt>(Size{EntityCollisionSize, EntityCollisionSize});
entity->Add<LifeCmpt>(FreightShipLife); entity->Add<LifeCmpt>(FreightShipLife);
entity->Add<FreightShipCmpt>(weapon); entity->Add<FreightShipCmpt>(weapon);
@ -56,7 +56,7 @@ Entity* CreateBullet(int group, int damage, Entity* owner, float maxSpeed) {
Entity* entity = ECSContext.CreateEntity(); Entity* entity = ECSContext.CreateEntity();
entity->Add<MoveCmpt>(Point{0, 0}); entity->Add<MoveCmpt>(Point{0, 0});
entity->Add<MotionCmpt>(Point{0, 0}, maxSpeed); entity->Add<MotionCmpt>(Point{0, 0}, maxSpeed);
entity->Add<RenderCmpt>(GameTileSheet->GetTile(0, 1)); entity->Add<RenderCmpt>(GameTileSheet->GetTile(4, 0));
entity->Add<BulletCmpt>(BulletCmpt::Bullet, damage, owner); entity->Add<BulletCmpt>(BulletCmpt::Bullet, damage, owner);
entity->Add<CollisionCmpt>(Size{8, 8}); entity->Add<CollisionCmpt>(Size{8, 8});
entity->Add<GroupCmpt>(group); entity->Add<GroupCmpt>(group);
@ -67,7 +67,7 @@ Entity* CreateMissile(int group, int damage, Entity* owner, float maxSpeed, Enti
Entity* entity = ECSContext.CreateEntity(); Entity* entity = ECSContext.CreateEntity();
entity->Add<MoveCmpt>(Point{0, 0}); entity->Add<MoveCmpt>(Point{0, 0});
entity->Add<MotionCmpt>(Point{0, 0}, maxSpeed); entity->Add<MotionCmpt>(Point{0, 0}, maxSpeed);
entity->Add<RenderCmpt>(GameTileSheet->GetTile(2, 1)); entity->Add<RenderCmpt>(GameTileSheet->GetTile(6, 0));
entity->Add<BulletCmpt>(BulletCmpt::Missile, damage, owner, target); entity->Add<BulletCmpt>(BulletCmpt::Missile, damage, owner, target);
entity->Add<CollisionCmpt>(Size{10, 10}); entity->Add<CollisionCmpt>(Size{10, 10});
entity->Add<GroupCmpt>(group); entity->Add<GroupCmpt>(group);

View File

@ -15,11 +15,14 @@ GameInitInfo InitInfo;
std::array<QuickList<Entity*>, 4> Groups; std::array<QuickList<Entity*>, 4> Groups;
void loadImages() { void loadImages() {
GameTileSheet.reset(new TileSheet("assets/tilesheet.png", 8, 8)); GameTileSheet.reset(new TileSheet("assets/tilesheet.png", 7, 1));
} }
void loadSounds() { void loadSounds() {
Sounds["shoot"] = std::make_unique<Sound>("assets/shoot.wav"); Sounds["shoot"] = std::make_unique<Sound>("assets/shoot.wav");
Sounds["hurt"] = std::make_unique<Sound>("assets/hurt.wav");
Sounds["explosion"] = std::make_unique<Sound>("assets/explose.wav");
Sounds["missile"] = std::make_unique<Sound>("assets/missile.wav");
} }
void LoadResources() { void LoadResources() {

View File

@ -4,7 +4,7 @@
bool Button(Texture* texture, const Point& pos, const Size& size, bool hflip) { 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); 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}; 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::SetDrawColor(Color{1, 1, 1, 0.2});
Renderer::FillRect(rect); Renderer::FillRect(rect);
return IsLeftPressed(); return IsLeftPressed();

View File

@ -6,42 +6,11 @@ void SpaceScence::OnInit() {
Entities.Clear(); Entities.Clear();
Bullets.Clear(); Bullets.Clear();
PlayerSpaceship = CreateFightShip(PlayerGroup); initEnemies();
Entities.Add(PlayerSpaceship); initPlayer();
PlayerSpaceship->Use<MoveCmpt>()->position = Point{400, 400}; calcGroupHps();
Entity* enemy = CreateFreightShip(Enemy1Group);
enemy->Add<AICmpt>(FreightShipAI);
enemy->Use<MoveCmpt>()->position = Point{100, 100};
Entities.Add(enemy);
enemy = CreateFreightShip(Enemy1Group);
enemy->Add<AICmpt>(FreightShipAI);
enemy->Use<MoveCmpt>()->position = Point{200, 100};
Entities.Add(enemy);
enemy = CreateFreightShip(Enemy1Group);
enemy->Add<AICmpt>(FreightShipAI);
enemy->Use<MoveCmpt>()->position = Point{100, 200};
Entities.Add(enemy);
// Entity* enemy = CreateFightShip(Enemy1Group);
// enemy->Add<AICmpt>(FightShipAI);
// enemy->Use<MoveCmpt>()->position = Point{100, 100};
// Entities.Add(enemy);
// enemy = CreateFightShip(Enemy1Group);
// enemy->Add<AICmpt>(FightShipAI);
// enemy->Use<MoveCmpt>()->position = Point{200, 100};
// Entities.Add(enemy);
// enemy = CreateFightShip(Enemy1Group);
// enemy->Add<AICmpt>(FightShipAI);
// enemy->Use<MoveCmpt>()->position = Point{100, 200};
// Entities.Add(enemy);
fightController_.reset(new FightShipController(PlayerSpaceship));
lookAtEntity_ = PlayerSpaceship;
gameCamera_.SetAnchor(GameWindowSize / 2); gameCamera_.SetAnchor(GameWindowSize / 2);
SystemMgr.Clear(); 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<LifeCmpt>()) {
groupHps[i] += entity->Get<LifeCmpt>()->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<MoveCmpt>()->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<AICmpt>(FreightShipAI);
// Entity* enemy = CreateFightShip(group);
// enemy->Add<AICmpt>(FightShipAI);
enemy->Use<MoveCmpt>()->position += p + Point{Random<float>(-400, 400), Random<float>(-100, 100)};
Entities.Add(enemy);
Groups[group].Add(enemy);
}
}
void SpaceScence::OnUpdate(float dt) { void SpaceScence::OnUpdate(float dt) {
fightController_->Update(dt); controller_->Update(dt);
SystemMgr.Update(dt); SystemMgr.Update(dt);
gameCamera_.MoveTo(PlayerSpaceship->Get<MoveCmpt>()->position);
if (lookAtEntity_ && lookAtEntity_->IsAlive()) {
gameCamera_.MoveTo(lookAtEntity_->Get<MoveCmpt>()->position);
} else {
if (!Groups[PlayerGroup].Empty()) {
lookAtEntity_ = *Groups[PlayerGroup].begin();
}
}
if (!PlayerSpaceship || !PlayerSpaceship->IsAlive()) {
if (IsKeyPressing(GLFW_KEY_SPACE)) {
PlayerSpaceship = lookAtEntity_;
if (PlayerSpaceship->Has<AICmpt>()) {
PlayerSpaceship->Remove<AICmpt>();
}
attachController();
}
}
}
void SpaceScence::attachController() {
if (PlayerSpaceship->Has<FreightShipCmpt>()) {
controller_.reset(new FreightShipController(PlayerSpaceship));
} else {
controller_.reset(new FightShipController(PlayerSpaceship));
}
} }
void SpaceScence::OnRender() { void SpaceScence::OnRender() {
@ -100,19 +148,46 @@ void SpaceScence::renderBackground() {
void SpaceScence::renderGUI() { void SpaceScence::renderGUI() {
Renderer::SetCamera(guiCamera_); Renderer::SetCamera(guiCamera_);
auto life = PlayerSpaceship->Get<LifeCmpt>()->hp; int life = 0;
if (PlayerSpaceship && PlayerSpaceship->IsAlive()) {
life = PlayerSpaceship->Get<LifeCmpt>()->hp;
}
float xOffset = 16 * life; float xOffset = 16 * life;
for (int i = 0; i < life; i++) { 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}); Point{GameWindowSize.w - xOffset + i * 16, 8});
} }
renderMiniMap(); renderMiniMap();
if (PlayerSpaceship->Has<FreightShipCmpt>()) { if (PlayerSpaceship && PlayerSpaceship->IsAlive()) {
renderWeapons(PlayerSpaceship->Get<FreightShipCmpt>()->weapon, nullptr); if (PlayerSpaceship->Has<FreightShipCmpt>()) {
} else { renderWeapons(PlayerSpaceship->Get<FreightShipCmpt>()->weapon, nullptr);
auto fightShip = PlayerSpaceship->Get<FightShipCmpt>(); } else {
renderWeapons(fightShip->weapon1, fightShip->weapon2); auto fightShip = PlayerSpaceship->Get<FightShipCmpt>();
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<LifeCmpt>()) {
hp += entity->Get<LifeCmpt>()->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::SetDrawColor(Color{255, 255, 255, 255});
Renderer::DrawRect(mapRect); Renderer::DrawRect(mapRect);
if (!PlayerSpaceship || !PlayerSpaceship->IsAlive()) {
return;
}
for (auto& entity: Entities) { for (auto& entity: Entities) {
if (entity != PlayerSpaceship) { if (entity != PlayerSpaceship) {
const auto& pos = entity->Get<MoveCmpt>()->position; const auto& pos = entity->Get<MoveCmpt>()->position;
@ -183,16 +262,6 @@ void SpaceScence::renderWeapons(SpaceshipWeaponCmpt* weapon1, SpaceshipWeaponCmp
} }
offset.y += 20; 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<EnergyProductCmpt>()->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() { void SpaceScence::OnQuit() {

View File

@ -29,7 +29,7 @@ void WelcomeScence::OnRender() {
Point{(GameWindowSize.w - title.size() * pt) / 2, 200}, Point{(GameWindowSize.w - title.size() * pt) / 2, 200},
Color{0.8, 0.8, 1, 1}); 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; pt = 10;
font.Render(title, pt, font.Render(title, pt,
Point{(GameWindowSize.w - title.size() * pt) / 2, 710}, Point{(GameWindowSize.w - title.size() * pt) / 2, 710},

View File

@ -56,13 +56,13 @@ void MissileUpdateSystem::updateMissile(float dt,
bullet.target = nullptr; bullet.target = nullptr;
} else { } else {
Point v = bullet.target->Get<MoveCmpt>()->position - move.position; Point v = bullet.target->Get<MoveCmpt>()->position - move.position;
float cross = Cross(motion.speed, v); float cross = Cross(Rotate(Point{0, -1}, bullet.rotation), v);
if (cross > 0) { if (cross > 0) {
bullet.rotation -= MissileRotateDegree * dt;
} else {
bullet.rotation += MissileRotateDegree * dt; 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); motion.speed = dir * Len(motion.speed);
} }
} }
@ -98,6 +98,7 @@ void CollideSystem::Update(float dt) {
entity->Get<CollisionCmpt>()->rect)) { entity->Get<CollisionCmpt>()->rect)) {
if (entity->Has<LifeCmpt>()) { if (entity->Has<LifeCmpt>()) {
entity->Use<LifeCmpt>()->hp -= bullet->Get<BulletCmpt>()->damage; entity->Use<LifeCmpt>()->hp -= bullet->Get<BulletCmpt>()->damage;
Sounds["hurt"]->Play();
} }
bullet->Use<BulletCmpt>()->alive = false; bullet->Use<BulletCmpt>()->alive = false;
} }
@ -111,20 +112,33 @@ void CleanupSystem::Update(float dt) {
ECSContext.DestroyEntity(entity); ECSContext.DestroyEntity(entity);
}; };
for (int i = 0; i < InitInfo.groupNum; i++) {
Groups[i].RemoveAll([](const EntityPtr& entity){
if (entity->Has<LifeCmpt>() &&
entity->Get<LifeCmpt>()->hp <= 0) {
return true;
} else {
return false;
}
});
}
Bullets.RemoveAll([](const EntityPtr& entity){ Bullets.RemoveAll([](const EntityPtr& entity){
return !entity->Get<BulletCmpt>()->alive || return !entity->Get<BulletCmpt>()->alive ||
!IsPointInRect(MapGlobal2PlayerCoord(entity->Get<MoveCmpt>()->position), !IsPointInRect(MapGlobal2PlayerCoord(entity->Get<MoveCmpt>()->position),
BulletRefreshArea); BulletRefreshArea);
}, destroyFunc); }, destroyFunc);
Entities.RemoveAll([](const EntityPtr& entity){ Entities.RemoveAll([&](const EntityPtr& entity){
if (entity->Has<LifeCmpt>() && if (entity->Has<LifeCmpt>() &&
entity->Get<LifeCmpt>()->hp <= 0) { entity->Get<LifeCmpt>()->hp <= 0) {
Sounds["explosion"]->Play();
return true; return true;
} else { } else {
return false; return false;
} }
}, destroyFunc); }, destroyFunc);
} }
void WeaponCooldownSystem::Update(float dt) { void WeaponCooldownSystem::Update(float dt) {
@ -154,8 +168,12 @@ void RenderEntitySystem::Render() {
if (entity->Has<FightShipCmpt>()) { if (entity->Has<FightShipCmpt>()) {
rotation = entity->Get<FightShipCmpt>()->degree; rotation = entity->Get<FightShipCmpt>()->degree;
} }
renderEntity(entity, *entity->Get<RenderCmpt>(), rotation); Color color = {1, 1, 1, 1};
renderCollideBox(entity); if (entity->Has<GroupCmpt>()) {
color = GroupSpecColor[entity->Get<GroupCmpt>()->groupIdx];
}
renderEntity(entity, *entity->Get<RenderCmpt>(), rotation, color);
// renderCollideBox(entity);
} }
} }
@ -164,8 +182,8 @@ void RenderEntitySystem::Render() {
if (bullet->Get<BulletCmpt>()->type == BulletCmpt::Missile) { if (bullet->Get<BulletCmpt>()->type == BulletCmpt::Missile) {
rotation = bullet->Get<BulletCmpt>()->rotation; rotation = bullet->Get<BulletCmpt>()->rotation;
} }
renderEntity(bullet, *bullet->Get<RenderCmpt>(), rotation); renderEntity(bullet, *bullet->Get<RenderCmpt>(), rotation, Color{1, 1, 1, 1});
renderCollideBox(bullet); // 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<MoveCmpt>()) { if (entity->Has<MoveCmpt>()) {
auto& pos = entity->Get<MoveCmpt>()->position; auto& pos = entity->Get<MoveCmpt>()->position;
if (renderCmpt.type == RenderCmpt::TypeTexture) { if (renderCmpt.type == RenderCmpt::TypeTexture) {
@ -184,12 +205,16 @@ void RenderEntitySystem::renderEntity(Entity* entity, const RenderCmpt& renderCm
nullptr, nullptr,
pos, pos,
Size{EntityRenderSize, EntityRenderSize}, Size{EntityRenderSize, EntityRenderSize},
rotation); rotation,
Renderer::NoFlip,
color);
} else { } else {
Renderer::DrawTile(renderCmpt.tile, Renderer::DrawTile(renderCmpt.tile,
pos, pos,
Size{EntityRenderSize, EntityRenderSize}, Size{EntityRenderSize, EntityRenderSize},
rotation); rotation,
Renderer::NoFlip,
color);
} }
} }
} }

View File

@ -64,6 +64,12 @@ bool IsRightPressed() {
} }
Point GetMousePosition() { Point GetMousePosition() {
double x, y;
glfwGetCursorPos(engine.GetWindow(), &x, &y);
return Point{float(x), float(y)};
}
Point GetMousePositionMapped() {
double x, y; double x, y;
glfwGetCursorPos(engine.GetWindow(), &x, &y); glfwGetCursorPos(engine.GetWindow(), &x, &y);
return Point{float(x) * WindowInitSize.w / engine.GetWindowSize().w, return Point{float(x) * WindowInitSize.w / engine.GetWindowSize().w,

View File

@ -133,11 +133,12 @@ void Renderer::DrawTile(const Tile& tile,
const Point& pos, const Point& pos,
const Size& size, const Size& size,
float degree, float degree,
Renderer::FlipFlag flip) { Renderer::FlipFlag flip,
const Color& color) {
if (size.w == 0 && size.h == 0) { 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 { } 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 Point& pos,
const Size& size, const Size& size,
float degree, float degree,
FlipFlag flip) { FlipFlag flip,
const Color& color) {
if (texture) { if (texture) {
auto scale = size; auto scale = size;
if (size.w == 0 && size.h == 0) { if (size.w == 0 && size.h == 0) {
@ -158,7 +160,7 @@ void Renderer::DrawTexture(const Texture* texture,
if (flip & Horizontal) { if (flip & Horizontal) {
scale.w *= -1; scale.w *= -1;
} }
DrawTexture(texture, srcrect, CreateSRT(pos, scale, degree)); DrawTexture(texture, srcrect, CreateSRT(pos, scale, degree), color);
} }
} }