added missile; drawed weaons

This commit is contained in:
VisualGMQ 2022-02-09 22:33:06 +08:00
parent a9f94b0df3
commit 5dcf222a0a
20 changed files with 309 additions and 84 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 809 B

After

Width:  |  Height:  |  Size: 920 B

View File

@ -5,3 +5,4 @@
#include "game/entity.hpp"
void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir);
void Shoot(SpaceshipWeaponCmpt& weapon, const Point& dir, Entity* target);

View File

@ -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;
};

View File

@ -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};

View File

@ -13,4 +13,6 @@ public:
private:
Entity* entity_;
void weaponShoot(SpaceshipWeaponCmpt* weapon, const MoveCmpt& move);
};

View File

@ -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);

View File

@ -15,3 +15,4 @@ extern Entity* PlayerSpaceship;
void LoadResources();
Point MapGlobal2PlayerCoord(const Point& pos);
Point MapPlayerCoord2Global(const Point& pos);

View File

@ -20,6 +20,7 @@ private:
void renderGUI();
void renderMiniMap();
void renderWeapons(SpaceshipWeaponCmpt* weapon1, SpaceshipWeaponCmpt* weapon2);
Camera guiCamera_;
Camera gameCamera_;

View File

@ -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);
};

View File

@ -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;
}

View File

@ -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<MoveCmpt>()->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<MoveCmpt>()->position;
Entity* bullet;
bullet = weapon.ShootMissile(dir, target);
// FIXME the rotation have some bugs
bullet->Use<BulletCmpt>()->rotation = Degrees(std::acos(-Normalize(dir).y));
Bullets.Add(bullet);
weapon.coolDown = weapon.shootDuration;
Sounds["shoot"]->Play();
}

View File

@ -7,3 +7,13 @@ Entity* SpaceshipWeaponCmpt::ShootBullet(const Point& dir) {
bullet->Use<MoveCmpt>()->position = owner->Get<MoveCmpt>()->position;
return bullet;
}
Entity* SpaceshipWeaponCmpt::ShootMissile(const Point& dir, Entity* target) {
Entity* bullet = CreateMissile(damage, owner, maxSpeed, target);
if (target) {
bullet->Use<BulletCmpt>()->rotation = Degrees(std::acos(Dot(dir, Normalize(target->Get<MoveCmpt>()->position - owner->Get<MoveCmpt>()->position))));
}
bullet->Use<MotionCmpt>()->speed = Normalize(dir) * shootSpeed;
bullet->Use<MoveCmpt>()->position = owner->Get<MoveCmpt>()->position;
return bullet;
}

View File

@ -24,16 +24,39 @@ void FightShipController::Update(float dt) {
motionCmpt->speed = Rotate(Point{0, -1} * Len(motionCmpt->speed),
-rotation);
auto fightShip = entity_->Use<FightShipCmpt>();
auto weapon1 = fightShip->weapon1,
weapon2 = fightShip->weapon2;
auto moveCmpt = entity_->Get<MoveCmpt>();
if (IsLeftPressing()) {
if (entity_->Has<SpaceshipWeaponCmpt>()) {
auto weapon = entity_->Use<SpaceshipWeaponCmpt>();
if (weapon->type == SpaceshipWeaponCmpt::Orientation) {
Shoot(*weapon,
Rotate(Point{0, -1}, -entity_->Get<FightShipCmpt>()->degree));
} else {
Shoot(*weapon,
GetMousePosition() - entity_->Get<MoveCmpt>()->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<FightShipCmpt>()->degree);
} else {
dir = GetMousePosition() - entity_->Get<MoveCmpt>()->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<CollisionCmpt>()->rect)) {
target = entity;
break;
}
}
Shoot(*weapon, dir, target);
}
}

View File

@ -8,30 +8,22 @@ void FreightShipController::Update(float dt) {
const float spd = 100;
auto motionCmpt = entity_->Use<MotionCmpt>();
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<SpaceshipWeaponCmpt>()) {
auto weapon = entity_->Use<FreightShipCmpt>()->weapon;
if (weapon) {
// FIXME duplicated codes in here and fightship_controller.cpp
auto weapon = entity_->Use<SpaceshipWeaponCmpt>();
if (weapon->type == SpaceshipWeaponCmpt::Orientation) {
Shoot(*weapon,
Rotate(Point{0, -1}, entity_->Get<FightShipCmpt>()->degree));

View File

@ -6,7 +6,9 @@ Entity* CreateFreightShip() {
entity->Add<MoveCmpt>(Point{0, 0});
entity->Add<MotionCmpt>(Point{0, 0}, FreightShipMaxSpeed);
entity->Add<RenderCmpt>(GameTileSheet->GetTile(0, 0));
entity->Add<SpaceshipWeaponCmpt>(SpaceshipWeaponCmpt::FreeRotation,
auto weapon = ECSContext.CreateComponent<SpaceshipWeaponCmpt>("BULLET",
SpaceshipWeaponCmpt::FreeRotation,
BulletCmpt::Bullet,
entity,
LazerDamage,
LazerShooterSpeed,
@ -14,7 +16,7 @@ Entity* CreateFreightShip() {
LazerShooterCooldown);
entity->Add<CollisionCmpt>(Size{16, 16});
entity->Add<LifeCmpt>(FreightLife);
entity->Add<FreightShipCmpt>();
entity->Add<FreightShipCmpt>(weapon);
return entity;
}
@ -23,15 +25,27 @@ Entity* CreateFightShip() {
entity->Add<MoveCmpt>(Point{0, 0});
entity->Add<MotionCmpt>(Point{0, 0}, FightShipMaxSpeed);
entity->Add<RenderCmpt>(GameTileSheet->GetTile(1, 0));
entity->Add<SpaceshipWeaponCmpt>(SpaceshipWeaponCmpt::Orientation,
auto weapon1 = ECSContext.CreateComponent<SpaceshipWeaponCmpt>("BULLET",
SpaceshipWeaponCmpt::Orientation,
BulletCmpt::Bullet,
entity,
LazerDamage,
LazerShooterSpeed,
LazerShooterMaxSpeed,
LazerShooterCooldown);
auto weapon2 = ECSContext.CreateComponent<SpaceshipWeaponCmpt>("MISSILE",
SpaceshipWeaponCmpt::Orientation,
BulletCmpt::Missile,
entity,
LazerDamage,
LazerShooterSpeed,
LazerShooterMaxSpeed,
LazerShooterCooldown);
entity->Add<CollisionCmpt>(Size{16, 16});
entity->Add<LifeCmpt>(FreightLife);
entity->Add<FightShipCmpt>(0);
entity->Add<FightShipCmpt>(weapon1, weapon2);
return entity;
}
@ -40,7 +54,17 @@ Entity* CreateBullet(int damage, Entity* owner, float maxSpeed) {
entity->Add<MoveCmpt>(Point{0, 0});
entity->Add<MotionCmpt>(Point{0, 0}, maxSpeed);
entity->Add<RenderCmpt>(GameTileSheet->GetTile(0, 1));
entity->Add<BulletCmpt>(damage, owner);
entity->Add<BulletCmpt>(BulletCmpt::Bullet, damage, owner);
entity->Add<CollisionCmpt>(Size{8, 8});
return entity;
}
Entity* CreateMissile(int damage, Entity* owner, float maxSpeed, Entity* target) {
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<BulletCmpt>(BulletCmpt::Missile, damage, owner, target);
entity->Add<CollisionCmpt>(Size{10, 10});
return entity;
}

View File

@ -31,3 +31,11 @@ Point MapGlobal2PlayerCoord(const Point& pos) {
return pos;
}
}
Point MapPlayerCoord2Global(const Point& pos) {
if (PlayerSpaceship && PlayerSpaceship->Has<MoveCmpt>()) {
return pos + PlayerSpaceship->Get<MoveCmpt>()->position - GameWindowSize / 2;
} else {
return pos;
}
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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<FreightShipCmpt>()) {
renderWeapons(PlayerSpaceship->Get<FreightShipCmpt>()->weapon, nullptr);
} else {
auto fightShip = PlayerSpaceship->Get<FightShipCmpt>();
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() {
}

View File

@ -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<BulletCmpt>()->type == BulletCmpt::Missile) {
updateMissile(dt,
*bullet->Use<BulletCmpt>(),
*bullet->Use<MoveCmpt>(),
*bullet->Use<MotionCmpt>());
}
}
}
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<MoveCmpt>()->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<CollisionCmpt, MoveCmpt>()) {
@ -89,7 +121,8 @@ void CleanupSystem::Update(float dt) {
if (entity->Has<LifeCmpt>() &&
entity->Get<LifeCmpt>()->hp <= 0 ||
entity->Has<MoveCmpt>() &&
!IsPointInRect(MapGlobal2PlayerCoord(entity->Get<MoveCmpt>()->position), SpaceshipRefreshArea)) {
!IsPointInRect(MapGlobal2PlayerCoord(entity->Get<MoveCmpt>()->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<SpaceshipWeaponCmpt>()) {
auto weapon = entity->Use<SpaceshipWeaponCmpt>();
if (weapon->coolDown >= 0) {
weapon->coolDown -= dt;
if (entity->Has<FreightShipCmpt>()) {
auto weapon = entity->Use<FreightShipCmpt>()->weapon;
coolDown(*weapon, dt);
}
if (entity->Has<FightShipCmpt>()) {
auto fightShip = entity->Use<FightShipCmpt>();
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<RenderCmpt>()) {
renderEntity(entity, *entity->Get<RenderCmpt>());
float rotation = 0;
if (entity->Has<FightShipCmpt>()) {
rotation = entity->Get<FightShipCmpt>()->degree;
}
renderEntity(entity, *entity->Get<RenderCmpt>(), rotation);
renderCollideBox(entity);
}
}
for (auto& bullet: Bullets) {
renderEntity(bullet, *bullet->Get<RenderCmpt>());
float rotation = 0;
if (bullet->Get<BulletCmpt>()->type == BulletCmpt::Missile) {
rotation = bullet->Get<BulletCmpt>()->rotation;
}
renderEntity(bullet, *bullet->Get<RenderCmpt>(), 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<MoveCmpt>()) {
auto& pos = entity->Get<MoveCmpt>()->position;
float degree = 0;
if (entity->Has<FightShipCmpt>()) {
degree = entity->Get<FightShipCmpt>()->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);
}
}
}