From: Mikko Rasa Date: Sun, 27 Nov 2022 21:49:23 +0000 (+0200) Subject: Make asteroids take damage when shot and eventually be destroyed X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=cb4e8bbe06dc64aff932784541a29493723fc03e;p=libs%2Fgame.git Make asteroids take damage when shot and eventually be destroyed --- diff --git a/examples/bassteroids/source/asteroid.cpp b/examples/bassteroids/source/asteroid.cpp index 7e5bcd5..cb7f954 100644 --- a/examples/bassteroids/source/asteroid.cpp +++ b/examples/bassteroids/source/asteroid.cpp @@ -3,7 +3,7 @@ using namespace Msp; Asteroid::Asteroid(Game::Handle p, const AsteroidSetup &s): - PhysicalEntity(p, s.physical), + Hittable(p, s.hittable, s.physical), setup(s), mesh(*this, setup.mesh) { } diff --git a/examples/bassteroids/source/asteroid.h b/examples/bassteroids/source/asteroid.h index dcb64c3..b80cc65 100644 --- a/examples/bassteroids/source/asteroid.h +++ b/examples/bassteroids/source/asteroid.h @@ -3,15 +3,16 @@ #include #include -#include "physicalentity.h" +#include "hittable.h" struct AsteroidSetup { PhysicalSetup physical; + HittableSetup hittable; Msp::Game::MeshSourceSetup mesh; }; -class Asteroid: public PhysicalEntity +class Asteroid: public Hittable { public: using Setup = AsteroidSetup; diff --git a/examples/bassteroids/source/bassteroids.cpp b/examples/bassteroids/source/bassteroids.cpp index 317b694..d6f2556 100644 --- a/examples/bassteroids/source/bassteroids.cpp +++ b/examples/bassteroids/source/bassteroids.cpp @@ -4,6 +4,7 @@ #include #include #include "controls.h" +#include "damagedealer.h" #include "gamecontroller.h" #include "physics.h" #include "playercontroller.h" @@ -21,6 +22,7 @@ Bassteroids::Bassteroids(int, char **): { game_stage.add_system(); game_stage.add_system(); + game_stage.add_system(); game_stage.add_system(); player_controller = &game_stage.add_system(); diff --git a/examples/bassteroids/source/bullet.cpp b/examples/bassteroids/source/bullet.cpp index 957a039..e26b408 100644 --- a/examples/bassteroids/source/bullet.cpp +++ b/examples/bassteroids/source/bullet.cpp @@ -3,6 +3,6 @@ using namespace Msp; Bullet::Bullet(Game::Handle p, const Setup &s, const Game::TransformValues &tv): - PhysicalEntity(p, s.physical, tv), + Hittable(p, s.hittable, s.physical, tv), mesh(*this, s.mesh) { } diff --git a/examples/bassteroids/source/bullet.h b/examples/bassteroids/source/bullet.h index 44c9d80..de0804a 100644 --- a/examples/bassteroids/source/bullet.h +++ b/examples/bassteroids/source/bullet.h @@ -2,15 +2,16 @@ #define BULLET_H_ #include -#include "physicalentity.h" +#include "hittable.h" struct BulletSetup { PhysicalSetup physical; + HittableSetup hittable; Msp::Game::MeshSourceSetup mesh; }; -class Bullet: public PhysicalEntity +class Bullet: public Hittable { private: Msp::Game::Owned mesh; diff --git a/examples/bassteroids/source/damagedealer.cpp b/examples/bassteroids/source/damagedealer.cpp new file mode 100644 index 0000000..37be786 --- /dev/null +++ b/examples/bassteroids/source/damagedealer.cpp @@ -0,0 +1,37 @@ +#include "damagedealer.h" +#include +#include "collider.h" +#include "hittable.h" + +using namespace Msp; + +DamageDealer::DamageDealer(Game::Stage &s): + System(s), + observer(stage.get_event_bus()) +{ + observer.observe([this](auto &e){ collision(e); }); +} + +void DamageDealer::tick(Time::TimeDelta) +{ + for(DamagingCollision &c: collisions) + { + Game::Handle hits1 = c.entity1->get_hitpoints(); + Game::Handle damage1 = c.entity1->get_damage(); + Game::Handle hits2 = c.entity2->get_hitpoints(); + Game::Handle damage2 = c.entity2->get_damage(); + if(damage1 && hits2) + hits2->take_damage(damage1->get_amount(), damage1->get_type()); + if(damage2 && hits1) + hits1->take_damage(damage2->get_amount(), damage2->get_type()); + } + collisions.clear(); +} + +void DamageDealer::collision(const Events::Collision &e) +{ + Game::Handle hittable1 = dynamic_handle_cast(e.collider1->get_entity()); + Game::Handle hittable2 = dynamic_handle_cast(e.collider2->get_entity()); + if(hittable1 && hittable2) + collisions.emplace_back(hittable1, hittable2); +} diff --git a/examples/bassteroids/source/damagedealer.h b/examples/bassteroids/source/damagedealer.h new file mode 100644 index 0000000..fe171de --- /dev/null +++ b/examples/bassteroids/source/damagedealer.h @@ -0,0 +1,33 @@ +#ifndef DAMAGEDEALER_H_ +#define DAMAGEDEALER_H_ + +#include +#include +#include +#include "events.h" + +class Collider; +class Hittable; + +class DamageDealer: public Msp::Game::System +{ +private: + struct DamagingCollision + { + Msp::Game::Handle entity1; + Msp::Game::Handle entity2; + }; + + Msp::Game::EventObserver observer; + std::vector collisions; + +public: + DamageDealer(Msp::Game::Stage &); + + void tick(Msp::Time::TimeDelta) override; + +private: + void collision(const Events::Collision &); +}; + +#endif diff --git a/examples/bassteroids/source/damagesource.cpp b/examples/bassteroids/source/damagesource.cpp new file mode 100644 index 0000000..a513879 --- /dev/null +++ b/examples/bassteroids/source/damagesource.cpp @@ -0,0 +1,8 @@ +#include "damagesource.h" + +using namespace Msp; + +DamageSource::DamageSource(Game::Handle p, const Setup &s): + Component(p), + setup(s) +{ } diff --git a/examples/bassteroids/source/damagesource.h b/examples/bassteroids/source/damagesource.h new file mode 100644 index 0000000..41a2755 --- /dev/null +++ b/examples/bassteroids/source/damagesource.h @@ -0,0 +1,27 @@ +#ifndef DAMAGESOURCE_H_ +#define DAMAGESOURCE_H_ + +#include + +struct DamageSourceSetup +{ + unsigned amount = 1; + unsigned type = 0; +}; + +class DamageSource: public Msp::Game::Component +{ +public: + using Setup = DamageSourceSetup; + +private: + const Setup &setup; + +public: + DamageSource(Msp::Game::Handle, const Setup &); + + unsigned get_amount() const { return setup.amount; } + unsigned get_type() const { return setup.type; } +}; + +#endif diff --git a/examples/bassteroids/source/gamecontroller.cpp b/examples/bassteroids/source/gamecontroller.cpp index b564033..97701e3 100644 --- a/examples/bassteroids/source/gamecontroller.cpp +++ b/examples/bassteroids/source/gamecontroller.cpp @@ -9,6 +9,7 @@ using namespace Msp; GameController::GameController(Game::Stage &s): System(s), asteroid_setup{ .physical={ .body={ .mass=200, .moment_of_inertia=2160 }, .collider={ .type=ColliderType::CIRCLE, .radius=3.0f } }, + .hittable={ .damaging=true, .hits={ .max_hits=3, .vulnerable_to=1 }, .damage={ .amount=10, .type=1 }}, .mesh={ .object_name="Asteroid 1.object" }} { } @@ -37,3 +38,9 @@ void GameController::tick(Time::TimeDelta) throw logic_error("Unimplemented state"); } } + +void GameController::deferred_tick() +{ + System::deferred_tick(); + erase_if(asteroids, [](Game::Handle a){ return !a->get_hitpoints()->is_alive(); }); +} diff --git a/examples/bassteroids/source/gamecontroller.h b/examples/bassteroids/source/gamecontroller.h index 1f0d3cf..1215444 100644 --- a/examples/bassteroids/source/gamecontroller.h +++ b/examples/bassteroids/source/gamecontroller.h @@ -24,6 +24,7 @@ public: GameController(Msp::Game::Stage &); void tick(Msp::Time::TimeDelta) override; + void deferred_tick() override; }; #endif diff --git a/examples/bassteroids/source/hitpoints.cpp b/examples/bassteroids/source/hitpoints.cpp new file mode 100644 index 0000000..ccd0441 --- /dev/null +++ b/examples/bassteroids/source/hitpoints.cpp @@ -0,0 +1,17 @@ +#include "hitpoints.h" + +using namespace Msp; + +HitPoints::HitPoints(Game::Handle e, const Setup &s): + Component(e), + setup(s), + remaining_hits(setup.max_hits) +{ } + +void HitPoints::take_damage(unsigned amount, unsigned type) +{ + if(!(setup.vulnerable_to&(1< + +struct HitPointsSetup +{ + /*class Loader: public Msp::DataFile::ObjectLoader + { + };*/ + + unsigned max_hits = 1; + unsigned vulnerable_to = ~0U; +}; + +class HitPoints: public Msp::Game::Component +{ +public: + using Setup = HitPointsSetup; + +private: + const Setup &setup; + unsigned remaining_hits; + +public: + HitPoints(Msp::Game::Handle, const Setup &); + + void take_damage(unsigned, unsigned); + + bool is_alive() const { return remaining_hits; } +}; + +#endif diff --git a/examples/bassteroids/source/hittable.cpp b/examples/bassteroids/source/hittable.cpp new file mode 100644 index 0000000..08355f1 --- /dev/null +++ b/examples/bassteroids/source/hittable.cpp @@ -0,0 +1,12 @@ +#include "hittable.h" + +using namespace Msp; + +Hittable::Hittable(Game::Handle p, const Setup &setup, const PhysicalSetup &ps, const Game::TransformValues &tv): + PhysicalEntity(p, ps, tv) +{ + if(!setup.immortal) + hits = Game::Owned(*this, setup.hits); + if(setup.damaging) + damage = Game::Owned(*this, setup.damage); +} diff --git a/examples/bassteroids/source/hittable.h b/examples/bassteroids/source/hittable.h new file mode 100644 index 0000000..b548a38 --- /dev/null +++ b/examples/bassteroids/source/hittable.h @@ -0,0 +1,34 @@ +#ifndef HITTABLE_H_ +#define HITTABLE_H_ + +#include +#include "damagesource.h" +#include "hitpoints.h" +#include "physicalentity.h" + +struct HittableSetup +{ + bool immortal = false; + bool damaging = false; + HitPointsSetup hits; + DamageSourceSetup damage; +}; + +class Hittable: public PhysicalEntity +{ +public: + using Setup = HittableSetup; + +private: + Msp::Game::Owned hits; + Msp::Game::Owned damage; + +public: + Hittable(Msp::Game::Handle, const Setup &, const PhysicalSetup &, + const Msp::Game::TransformValues & = Msp::Game::TransformValues()); + + Msp::Game::Handle get_hitpoints() { return hits; } + Msp::Game::Handle get_damage() { return damage; } +}; + +#endif diff --git a/examples/bassteroids/source/playercontroller.cpp b/examples/bassteroids/source/playercontroller.cpp index 066b5f2..46f9c1f 100644 --- a/examples/bassteroids/source/playercontroller.cpp +++ b/examples/bassteroids/source/playercontroller.cpp @@ -12,6 +12,7 @@ PlayerController::PlayerController(Game::Stage &s): .mesh={ .object_name="Bass guitar.object" }, .speed=12.0f, .turn_rate=4.71f }, bullet_setup{ .physical={ .body={ .mass=0.05f, .moment_of_inertia=0.04f }, .collider={ .type=ColliderType::CIRCLE, .radius=0.2f }}, + .hittable={ .damaging=true, .hits={ .max_hits=1 }, .damage={ .amount=1, .type=0 }}, .mesh={ .object_name="Quaver.object" }} { } @@ -55,6 +56,12 @@ void PlayerController::tick(Time::TimeDelta dt) controls->reset_edges(); } +void PlayerController::deferred_tick() +{ + System::deferred_tick(); + erase_if(bullets, [](Game::Handle b){ return !b->get_hitpoints()->is_alive(); }); +} + void PlayerController::fire() { Game::Handle player_tf = player_ship->get_transform(); diff --git a/examples/bassteroids/source/playercontroller.h b/examples/bassteroids/source/playercontroller.h index d29b2d6..a4e35d4 100644 --- a/examples/bassteroids/source/playercontroller.h +++ b/examples/bassteroids/source/playercontroller.h @@ -24,6 +24,7 @@ public: void set_controls(Controls *); void tick(Msp::Time::TimeDelta) override; + void deferred_tick() override; private: void fire(); };