fixed fight ship ai bug; improved freight ship
This commit is contained in:
parent
559cfda2da
commit
945ee99e41
|
@ -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进行加速和减速(不能向后倒着飞),鼠标左键使用炮弹,鼠标右键发射导弹(导弹有数量限制)。
|
||||
|
||||
切换飞机:
|
||||
|
||||
当你控制的飞机死亡后,视角会转到我方阵营的另一架飞机上,此时可以选择按空格键操控这辆飞机。
|
||||
|
||||
胜利条件:
|
||||
|
||||
全灭其他所有阵营获得胜利
|
||||
|
12
ReadMe.md
12
ReadMe.md
|
@ -24,3 +24,15 @@ pack.sh
|
|||
```
|
||||
|
||||
最终的结果在`output`文件夹下。
|
||||
|
||||
## 游戏截图
|
||||
|
||||
![welcome](./snapshot/welcome.png)
|
||||
|
||||
![select](./snapshot/select_ship.png)
|
||||
|
||||
![gaming](./snapshot/gaming.png)
|
||||
|
||||
## 游戏操作
|
||||
|
||||
[游戏操作](./HowToPlay.md)
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.0 KiB |
|
@ -228,8 +228,10 @@ public:
|
|||
|
||||
void Init(AIFunc func) {
|
||||
this->func = func;
|
||||
target = nullptr;
|
||||
}
|
||||
void Release() {}
|
||||
|
||||
AIFunc func;
|
||||
Entity* target;
|
||||
};
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
|
|
@ -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<T>::const_iterator;
|
||||
|
||||
const_iterator begin() const { return datas_.begin(); }
|
||||
|
|
|
@ -16,15 +16,23 @@ public:
|
|||
void OnQuit() override;
|
||||
|
||||
private:
|
||||
Unique<FightShipController> fightController_;
|
||||
Unique<Controller> controller_;
|
||||
|
||||
Camera guiCamera_;
|
||||
Camera gameCamera_;
|
||||
Entity* lookAtEntity_;
|
||||
|
||||
std::vector<Point> stars_;
|
||||
int groupHps[4] = {0};
|
||||
|
||||
void renderBackground();
|
||||
void renderGUI();
|
||||
void renderMiniMap();
|
||||
void renderWeapons(SpaceshipWeaponCmpt* weapon1, SpaceshipWeaponCmpt* weapon2);
|
||||
|
||||
Camera guiCamera_;
|
||||
Camera gameCamera_;
|
||||
|
||||
std::vector<Point> stars_;
|
||||
void initEnemies();
|
||||
void attachController();
|
||||
void generateEnemiesAt(int group, const Point& p, int num);
|
||||
void initPlayer();
|
||||
void calcGroupHps();
|
||||
void drawGroupHp();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ bool IsRightPressing();
|
|||
bool IsLeftPressed();
|
||||
bool IsRightPressed();
|
||||
Point GetMousePosition();
|
||||
Point GetMousePositionMapped();
|
||||
|
||||
void EventUpdate();
|
||||
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
|
|
2
pack.sh
2
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
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 90 KiB |
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
Binary file not shown.
After Width: | Height: | Size: 94 KiB |
|
@ -5,8 +5,6 @@ void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir) {
|
|||
return;
|
||||
}
|
||||
|
||||
Point playerCenterPos = weapon.owner->Get<MoveCmpt>()->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<BulletCmpt>()->rotation = Degrees(std::acos(-Normalize(dir).y));
|
||||
bullet->Use<BulletCmpt>()->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;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,27 @@
|
|||
#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) {
|
||||
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 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<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 dir = pmove->position - smove->position;
|
||||
|
||||
auto motion = self->Use<MotionCmpt>();
|
||||
auto ship = self->Use<FightShipCmpt>();
|
||||
|
||||
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<FightShipCmpt>()->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);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -23,5 +23,6 @@ Entity* SpaceshipWeaponCmpt::ShootMissile(const Point& dir, Entity* target) {
|
|||
}
|
||||
bullet->Use<MotionCmpt>()->speed = Normalize(dir) * shootSpeed;
|
||||
bullet->Use<MoveCmpt>()->position = owner->Get<MoveCmpt>()->position;
|
||||
Sounds["missile"]->Play();
|
||||
return bullet;
|
||||
}
|
||||
|
|
|
@ -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<MotionCmpt>();
|
||||
auto ship = entity_->Use<FightShipCmpt>();
|
||||
|
@ -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<MoveCmpt>();
|
||||
|
||||
|
@ -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<FightShipCmpt>()->degree);
|
||||
dir = Rotate(Point{0, -1}, entity_->Get<FightShipCmpt>()->degree);
|
||||
} else {
|
||||
dir = GetMousePosition() - entity_->Get<MoveCmpt>()->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<CollisionCmpt>()->rect)) {
|
||||
IsPointInRect(MapPlayerCoord2Global(GetMousePositionMapped()), entity->Get<CollisionCmpt>()->rect)) {
|
||||
target = entity;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -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<MotionCmpt>();
|
||||
if (IsKeyPressing(GLFW_KEY_A)) {
|
||||
|
@ -29,7 +33,7 @@ void FreightShipController::Update(float dt) {
|
|||
Rotate(Point{0, -1}, entity_->Get<FightShipCmpt>()->degree));
|
||||
} else {
|
||||
Shoot(*weapon,
|
||||
GetMousePosition() - entity_->Get<MoveCmpt>()->position);
|
||||
GetMousePosition() - GameWindowSize / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ Entity* CreateFreightShip(int group) {
|
|||
LazerDamage,
|
||||
LazerShooterSpeed,
|
||||
LazerShooterMaxSpeed,
|
||||
LazerShooterCooldown + 1);
|
||||
LazerShooterCooldown + FreightShipLazerDelay);
|
||||
entity->Add<CollisionCmpt>(Size{EntityCollisionSize, EntityCollisionSize});
|
||||
entity->Add<LifeCmpt>(FreightShipLife);
|
||||
entity->Add<FreightShipCmpt>(weapon);
|
||||
|
@ -56,7 +56,7 @@ Entity* CreateBullet(int group, int damage, Entity* owner, float maxSpeed) {
|
|||
Entity* entity = ECSContext.CreateEntity();
|
||||
entity->Add<MoveCmpt>(Point{0, 0});
|
||||
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<CollisionCmpt>(Size{8, 8});
|
||||
entity->Add<GroupCmpt>(group);
|
||||
|
@ -67,7 +67,7 @@ Entity* CreateMissile(int group, int damage, Entity* owner, float maxSpeed, Enti
|
|||
Entity* entity = ECSContext.CreateEntity();
|
||||
entity->Add<MoveCmpt>(Point{0, 0});
|
||||
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<CollisionCmpt>(Size{10, 10});
|
||||
entity->Add<GroupCmpt>(group);
|
||||
|
|
|
@ -15,11 +15,14 @@ GameInitInfo InitInfo;
|
|||
std::array<QuickList<Entity*>, 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<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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -6,42 +6,11 @@ void SpaceScence::OnInit() {
|
|||
Entities.Clear();
|
||||
Bullets.Clear();
|
||||
|
||||
PlayerSpaceship = CreateFightShip(PlayerGroup);
|
||||
Entities.Add(PlayerSpaceship);
|
||||
PlayerSpaceship->Use<MoveCmpt>()->position = Point{400, 400};
|
||||
|
||||
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));
|
||||
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<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) {
|
||||
fightController_->Update(dt);
|
||||
controller_->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() {
|
||||
|
@ -100,19 +148,46 @@ void SpaceScence::renderBackground() {
|
|||
void SpaceScence::renderGUI() {
|
||||
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;
|
||||
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<FreightShipCmpt>()) {
|
||||
renderWeapons(PlayerSpaceship->Get<FreightShipCmpt>()->weapon, nullptr);
|
||||
} else {
|
||||
auto fightShip = PlayerSpaceship->Get<FightShipCmpt>();
|
||||
renderWeapons(fightShip->weapon1, fightShip->weapon2);
|
||||
if (PlayerSpaceship && PlayerSpaceship->IsAlive()) {
|
||||
if (PlayerSpaceship->Has<FreightShipCmpt>()) {
|
||||
renderWeapons(PlayerSpaceship->Get<FreightShipCmpt>()->weapon, nullptr);
|
||||
} else {
|
||||
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::DrawRect(mapRect);
|
||||
|
||||
if (!PlayerSpaceship || !PlayerSpaceship->IsAlive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& entity: Entities) {
|
||||
if (entity != PlayerSpaceship) {
|
||||
const auto& pos = entity->Get<MoveCmpt>()->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<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() {
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -56,13 +56,13 @@ void MissileUpdateSystem::updateMissile(float dt,
|
|||
bullet.target = nullptr;
|
||||
} else {
|
||||
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) {
|
||||
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<CollisionCmpt>()->rect)) {
|
||||
if (entity->Has<LifeCmpt>()) {
|
||||
entity->Use<LifeCmpt>()->hp -= bullet->Get<BulletCmpt>()->damage;
|
||||
Sounds["hurt"]->Play();
|
||||
}
|
||||
bullet->Use<BulletCmpt>()->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<LifeCmpt>() &&
|
||||
entity->Get<LifeCmpt>()->hp <= 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Bullets.RemoveAll([](const EntityPtr& entity){
|
||||
return !entity->Get<BulletCmpt>()->alive ||
|
||||
!IsPointInRect(MapGlobal2PlayerCoord(entity->Get<MoveCmpt>()->position),
|
||||
BulletRefreshArea);
|
||||
}, destroyFunc);
|
||||
|
||||
Entities.RemoveAll([](const EntityPtr& entity){
|
||||
Entities.RemoveAll([&](const EntityPtr& entity){
|
||||
if (entity->Has<LifeCmpt>() &&
|
||||
entity->Get<LifeCmpt>()->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<FightShipCmpt>()) {
|
||||
rotation = entity->Get<FightShipCmpt>()->degree;
|
||||
}
|
||||
renderEntity(entity, *entity->Get<RenderCmpt>(), rotation);
|
||||
renderCollideBox(entity);
|
||||
Color color = {1, 1, 1, 1};
|
||||
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) {
|
||||
rotation = bullet->Get<BulletCmpt>()->rotation;
|
||||
}
|
||||
renderEntity(bullet, *bullet->Get<RenderCmpt>(), rotation);
|
||||
renderCollideBox(bullet);
|
||||
renderEntity(bullet, *bullet->Get<RenderCmpt>(), 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<MoveCmpt>()) {
|
||||
auto& pos = entity->Get<MoveCmpt>()->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Reference in New Issue