summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2017-12-16 19:06:43 +0100
committerPaweł Redman <pawel.redman@gmail.com>2017-12-16 19:06:43 +0100
commit820e2e9d428c273e065cfe18b48c183a5cbedd75 (patch)
treee20a60780ecb4d7dbc53a641bdd86d3407c29577
parentc341559390ce52b47d056226fc102287dc41b304 (diff)
Major refactor of game's entity code.
-rw-r--r--src/common.hpp14
-rw-r--r--src/game/effects.cpp10
-rw-r--r--src/game/game.cpp137
-rw-r--r--src/game/game.hpp80
-rw-r--r--src/game/units.cpp114
-rw-r--r--src/math.hpp10
-rw-r--r--src/world.cpp9
7 files changed, 194 insertions, 180 deletions
diff --git a/src/common.hpp b/src/common.hpp
index f543ca5..eaed590 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -129,7 +129,6 @@ namespace world {
};
class entity_t {
- world_t *parent_world;
std::vector<sector_t*> parents;
void link_to_sector(sector_t *sector);
@@ -139,12 +138,14 @@ namespace world {
size_t cookie = 0;
public:
+ world_t *world = 0;
int type;
cmodel_t cmodel;
rectf_t render_bounds;
int render_layer = 0;
entity_t(int type_);
+ ~entity_t(void) {};
void link(world_t *world);
void unlink();
@@ -189,6 +190,7 @@ namespace interface {
namespace game {
bool load_assets(void);
+ class entity_t;
class unit_t;
class effect_t;
@@ -203,11 +205,11 @@ namespace game {
};
class state_t {
- std::unordered_set<unit_t*> units;
- std::unordered_set<unit_t*> selected_units;
- std::unordered_set<unit_t*> awake_units;
+ protected:
+ friend entity_t;
- std::unordered_set<effect_t*> effects;
+ std::unordered_set<entity_t*> awake_entities;
+ std::unordered_set<unit_t*> selected_units;
procgen::prng_t dice_prng;
public:
@@ -225,7 +227,7 @@ namespace game {
size_t roll(roll_params_t *P);
- void add_effect(effect_t *effect);
+ void wake_everything(v2f_t x, float range);
};
}
diff --git a/src/game/effects.cpp b/src/game/effects.cpp
index d9215e3..8e7d2d7 100644
--- a/src/game/effects.cpp
+++ b/src/game/effects.cpp
@@ -2,9 +2,15 @@
namespace game {
-effect_t::effect_t(state_t *game_) : world::entity_t(ET_EFFECT)
+effect_t::effect_t(state_t *game_) : game::entity_t(game_, ET_EFFECT)
{
- game = game_;
+ always_awake = true;
+}
+
+void effect_t::on_think(void)
+{
+ if (game->now >= ttl)
+ destroy();
}
fx_tracer_t::fx_tracer_t(state_t *game_, v2f_t x0_, v2f_t x1_) : effect_t(game_)
diff --git a/src/game/game.cpp b/src/game/game.cpp
index 993f450..35cb90c 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -4,6 +4,59 @@ namespace game {
size_t selection_cookie = 1;
+entity_t::entity_t(game::state_t *game_, int type_) : world::entity_t(type_)
+{
+ game = game_;
+}
+
+void entity_t::destroy(void)
+{
+ unlink();
+ game->awake_entities.erase(this);
+ delete this;
+}
+
+void entity_t::place(world::world_t *world_)
+{
+ bool do_spawn = false;
+
+ if (!world)
+ do_spawn = true;
+
+ link(world_);
+
+ if (do_spawn)
+ on_spawn();
+
+ if (always_awake)
+ wake();
+}
+
+void entity_t::place(world::world_t *world, v2f_t x_)
+{
+ x = x_;
+ cmodel.bounds = size + x;
+ render_bounds = render_size + x;
+
+ place(world);
+}
+
+void entity_t::wake(void)
+{
+ awake = true;
+ wake_time = game->now;
+ game->awake_entities.insert(this);
+
+ if (!always_awake)
+ on_wake();
+}
+
+void entity_t::sleep(void)
+{
+ awake = false;
+ game->awake_entities.erase(this);
+}
+
void state_t::start(void)
{
human_t *human;
@@ -14,13 +67,10 @@ void state_t::start(void)
human = new human_t(this);
human->place(&world, v2f_t(0.5, 0.5));
- units.insert(human);
human = new human_t(this);
human->place(&world, v2f_t(1.5, 0.5));
- units.insert(human);
human = new human_t(this);
human->place(&world, v2f_t(2.5, 0.5));
- units.insert(human);
alien = new alien_t(this);
alien->place(&world, v2f_t(15.5, -2.5));
@@ -32,11 +82,6 @@ void state_t::start(void)
void state_t::stop(void)
{
- // FIXME
- /*
- for (unit_t *unit : units)
- delete unit;
- */
}
void state_t::select(rectf_t x)
@@ -83,12 +128,6 @@ void state_t::command(v2f_t x)
}
}
-void state_t::add_effect(effect_t *effect)
-{
- effects.insert(effect);
- effect->link(&world);
-}
-
void state_t::tick(double now_, double dt_)
{
union {
@@ -105,61 +144,33 @@ void state_t::tick(double now_, double dt_)
u.d = dt;
dice_prng.seed(dice_prng.next() ^ u.i);
- for (unit_t *unit : units) {
- rectf_t wake_range;
-
- if (unit->dead)
- continue;
-
- wake_range[0] = unit->x - v2f_t(10, 10);
- wake_range[1] = unit->x + v2f_t(10, 10);
-
- for (world::entity_t *ent : world.get_entities(wake_range, -1)) {
- unit_t *enemy;
-
- if (ent->type != ET_UNIT)
- continue;
-
- enemy = (unit_t*)ent;
-
- if (enemy->dead)
- continue;
-
- enemy->wake_time = now;
+ // NOTE: on_think can erase the entity from awake_entities.
+ for (auto i = awake_entities.begin(); i != awake_entities.end(); ) {
+ auto next = i;
+ next++;
+ (*i)->on_think();
+ i = next;
+ }
+}
- if (enemy->awake)
- continue;
+void state_t::wake_everything(v2f_t x, float range)
+{
+ rectf_t wake_range;
- if (enemy->type == unit_t::UNIT_HUMAN)
- continue;
+ wake_range[0] = x - v2f_t(range, range);
+ wake_range[1] = x + v2f_t(range, range);
- enemy->awake = true;
- awake_units.insert(enemy);
- enemy->wake(unit);
- }
+ for (world::entity_t *went : world.get_entities(wake_range, -1)) {
+ auto ent = dynamic_cast<game::entity_t*>(went);
- unit->think();
- }
+ // WTF?
+ if (!ent)
+ continue;
- for (auto i = std::begin(awake_units); i != std::end(awake_units);) {
- if (now - (*i)->wake_time >= 5.0) {
- (*i)->awake = false;
- (*i)->sleep();
- i = awake_units.erase(i);
- } else {
- if (!(*i)->dead)
- (*i)->think();
- i++;
- }
- }
+ if (ent->always_awake || ent->awake)
+ continue;
- for (auto i = std::begin(effects); i != std::end(effects);) {
- if (now > (*i)->ttl) {
- (*i)->unlink();
- delete *i;
- i = effects.erase(i);
- } else
- i++;
+ ent->wake();
}
}
diff --git a/src/game/game.hpp b/src/game/game.hpp
index 4cc1077..b9a426b 100644
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -55,21 +55,36 @@ namespace game {
void load(void);
}
- class unit_t : public world::entity_t {
- protected:
- game::state_t *game;
- world::world_t *world;
+ class entity_t : public world::entity_t {
+ public:
+ game::state_t *game = 0;
+ v2f_t x;
+ rectf_t size, render_size;
+
+ entity_t(game::state_t *game, int type_);
+ ~entity_t(void) {};
+ void destroy(void);
- world::cmodel_t make_cmodel(v2f_t at);
- void compute_bounds();
+ void place(world::world_t *world);
+ void place(world::world_t *world, v2f_t x_);
+ bool always_awake = false;
+ bool awake = false;
+ double wake_time = -INFINITY;
+ void wake(void);
+ void sleep(void);
+
+ virtual void on_think(void) = 0;
+ virtual void on_spawn(void) = 0;
+ virtual void on_wake(void) = 0;
+ };
+
+ class unit_t : public entity_t {
+ protected:
double next_targetting = -INFINITY;
double last_attack = -INFINITY;
public:
- v2f_t x;
- rectf_t size, render_size;
- world::cflags_t cflags;
size_t selected = 0;
typedef enum {
@@ -82,8 +97,6 @@ namespace game {
unit_t(game::state_t *game_, type_t type_);
- virtual void think(void) = 0;
-
struct {
bool moving = false;
v2f_t dst;
@@ -96,15 +109,9 @@ namespace game {
float next_attempt;
} move;
- void place(world::world_t *world_, v2f_t x_);
bool keep_moving(double speed);
bool start_moving(v2f_t dst, world::cflags_t cflags);
- bool awake = false;
- double wake_time = -INFINITY;
- virtual void wake(unit_t *by_whom) = 0;
- virtual void sleep(void) = 0;
-
struct {
size_t armor_class;
roll_params_t hit_roll;
@@ -116,13 +123,13 @@ namespace game {
int health = 1, max_health = 1;
void damage(int points, unit_t *attacker);
void try_attack(unit_t *target);
- virtual void die() = 0;
+ void die(unit_t *killer);
+ virtual void on_death() = 0;
std::string say_text;
double say_time = -INFINITY;
void say(std::string str);
-
void render_to(render::state_t *render);
};
@@ -133,34 +140,37 @@ namespace game {
public:
human_t(game::state_t *game_);
+ ~human_t(void) {};
void render_to(render::state_t *render);
- void wake(unit_t *by_whom);
- void sleep(void);
- void think(void);
- void die(void);
+ void on_think(void);
+ void on_spawn(void) {};
+ void on_wake(void) {};
+ void on_death(void);
};
class alien_t : public unit_t {
- double next_targetting = -INFINITY;
-
public:
alien_t(game::state_t *game_);
+ ~alien_t(void) {};
void render_to(render::state_t *render);
- void wake(unit_t *by_whom);
- void sleep(void);
- void think(void);
- void die(void);
+ void on_think(void);
+ void on_spawn(void) {};
+ void on_wake(void);
+ void on_death(void);
};
- class effect_t : public world::entity_t {
+ class effect_t : public game::entity_t {
public:
- game::state_t *game;
-
double ttl = +INFINITY;
+
effect_t(game::state_t *game_);
virtual ~effect_t() {};
+
+ void on_think(void);
+ void on_spawn(void) {};
+ void on_wake(void) {};
};
class fx_tracer_t : public effect_t {
@@ -168,7 +178,8 @@ namespace game {
public:
fx_tracer_t(game::state_t *game_, v2f_t x0_, v2f_t x1_);
- ~fx_tracer_t(void) = default;
+ ~fx_tracer_t(void) {};
+
void render_to(render::state_t *render);
};
@@ -178,7 +189,8 @@ namespace game {
public:
fx_blood_t(game::state_t *game_, v2f_t x_, bool alien_);
- ~fx_blood_t(void) = default;
+ ~fx_blood_t(void) {};
+
void render_to(render::state_t *render);
};
diff --git a/src/game/units.cpp b/src/game/units.cpp
index 73e1cf0..8eb11c7 100644
--- a/src/game/units.cpp
+++ b/src/game/units.cpp
@@ -2,27 +2,9 @@
namespace game {
-world::cmodel_t unit_t::make_cmodel(v2f_t at)
-{
- world::cmodel_t cmodel;
-
- cmodel.bounds[0] = at + size[0];
- cmodel.bounds[1] = at + size[1];
- cmodel.cflags = cflags;
-
- return cmodel;
-}
-
-void unit_t::compute_bounds()
-{
- render_bounds[0] = x + render_size[0];
- render_bounds[1] = x + render_size[1];
-}
-
-unit_t::unit_t(game::state_t *game_, unit_t::type_t type_) : entity_t(ET_UNIT)
+unit_t::unit_t(game::state_t *game_, unit_t::type_t type_) : game::entity_t(game_, ET_UNIT)
{
type = type_;
- game = game_;
}
void unit_t::render_to(render::state_t *render)
@@ -78,18 +60,6 @@ void unit_t::say(std::string str)
game->interface->print(name + ": " + str);
}
-void unit_t::place(world::world_t *world_, v2f_t x_)
-{
- world = world_;
- x = x_;
- move.moving = false;
-
- unlink();
- cmodel = make_cmodel(x);
- compute_bounds();
- link(world);
-}
-
bool unit_t::keep_moving(double speed)
{
float time;
@@ -127,7 +97,8 @@ bool unit_t::keep_moving(double speed)
move.path.pop_front();
}
- cmodel_next = make_cmodel(x_new);
+ cmodel_next.bounds = size + x_new;
+ cmodel_next.cflags = cmodel.cflags;
if (!world->test_rect(&cmodel_next, this)) {
x = x_new;
cmodel = cmodel_next;
@@ -146,9 +117,7 @@ bool unit_t::keep_moving(double speed)
break;
}
- unlink();
- compute_bounds();
- link(world);
+ place(world, x);
return rv;
}
@@ -185,16 +154,20 @@ void unit_t::damage(int points, unit_t *attacker)
fx_blood_t *blood;
blood = new fx_blood_t(game, x, type == UNIT_ALIEN);
- game->add_effect(blood);
+ blood->place(&game->world);
health -= points;
- if (health < 0) {
- game->interface->print(name + " " + text::get(text::UNIT_DEATH) + ".");
- dead = true;
- death_time = game->now;
- cflags = 0;
- die();
- }
+ if (health < 0)
+ die(attacker);
+}
+
+void unit_t::die(unit_t *killer)
+{
+ game->interface->print(name + " " + text::get(text::UNIT_DEATH) + ".");
+ dead = true;
+ death_time = game->now;
+ cmodel.cflags = 0;
+ on_death();
}
void unit_t::try_attack(unit_t *target)
@@ -266,7 +239,9 @@ static unit_t *find_target(world::world_t *world, v2f_t x, float r,
human_t::human_t(game::state_t *game) : unit_t(game, UNIT_HUMAN)
{
- cflags = CF_BODY;
+ always_awake = true;
+
+ cmodel.cflags = CF_BODY;
health = max_health = 20;
size[0] = v2f_t(-0.4f, -0.4f);
size[1] = v2f_t(+0.4f, +0.4f);
@@ -279,16 +254,13 @@ human_t::human_t(game::state_t *game) : unit_t(game, UNIT_HUMAN)
cs.damage_roll = roll_params_t(4);
}
-void human_t::wake(unit_t *by_whom)
+void human_t::on_think(void)
{
-}
+ if (dead)
+ return;
-void human_t::sleep(void)
-{
-}
+ game->wake_everything(x, 10);
-void human_t::think(void)
-{
if (game->now > next_targetting) {
unit_t *target;
@@ -304,7 +276,7 @@ void human_t::think(void)
trace = world->trace(x, target->x, CF_SOLID);
if (!trace.hit) {
tracer = new fx_tracer_t(game, x, target->x);
- game->add_effect(tracer);
+ tracer->place(&game->world);
last_attack = game->now;
try_attack(target);
@@ -321,15 +293,13 @@ void human_t::think(void)
say(text::get(text::SAY_BLOCKED));
}
-void human_t::die(void)
+void human_t::on_death(void)
{
render_size[0] = v2f_t(-0.75f, -0.5f);
render_size[1] = v2f_t(+0.75f, +0.5f);
render_layer = -1;
cmodel.cflags = CF_BACKGROUND;
- unlink();
- compute_bounds();
- link(world);
+ place(world, x);
}
void human_t::render_to(render::state_t *render)
@@ -367,7 +337,7 @@ void human_t::render_to(render::state_t *render)
alien_t::alien_t(game::state_t *game) : unit_t(game, UNIT_ALIEN)
{
- cflags = CF_BODY_SMALL;
+ cmodel.cflags = CF_BODY_SMALL;
health = max_health = 4;
size[0] = v2f_t(-0.2f, -0.3f);
size[1] = v2f_t(+0.2f, +0.3f);
@@ -380,24 +350,11 @@ alien_t::alien_t(game::state_t *game) : unit_t(game, UNIT_ALIEN)
cs.damage_roll = roll_params_t(3, 6, 1);
}
-void alien_t::wake(unit_t *by_whom)
-{
- start_moving(by_whom->x, CF_SOLID | CF_WATER);
- next_targetting = game->now + 0.2;
-}
-
-void alien_t::sleep(void)
-{
-}
-
-void alien_t::die(void)
+void alien_t::on_think(void)
{
- render_layer = -1;
- cmodel.cflags = CF_BACKGROUND;
-}
+ if (dead)
+ return;
-void alien_t::think(void)
-{
if (game->now > next_targetting) {
unit_t *target;
@@ -424,6 +381,17 @@ void alien_t::think(void)
keep_moving(7.0);
}
+void alien_t::on_wake(void)
+{
+ next_targetting = game->now;
+}
+
+void alien_t::on_death(void)
+{
+ render_layer = -1;
+ cmodel.cflags = CF_BACKGROUND;
+}
+
void alien_t::render_to(render::state_t *render)
{
bool moving;
diff --git a/src/math.hpp b/src/math.hpp
index 5e117fd..e393015 100644
--- a/src/math.hpp
+++ b/src/math.hpp
@@ -352,6 +352,16 @@ public:
return r;
}
+ friend rect_t<T, N> operator+(const rect_t<T, N> &a, const vec_t<T, N> &b)
+ {
+ rect_t<T, N> r;
+
+ r[0] = a[0] + b;
+ r[1] = a[1] + b;
+
+ return r;
+ }
+
friend std::ostream& operator<<(std::ostream& stream, rect_t<T, N> r)
{
stream << "(" << r[0] << " x " << r[1] << ")";
diff --git a/src/world.cpp b/src/world.cpp
index 1975b4e..a5e8869 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -375,7 +375,7 @@ void entity_t::link_to_sector(sector_t *sector)
sector->ents.insert(this);
}
-void entity_t::link(world_t *world)
+void entity_t::link(world_t *world_)
{
rectf_t total_bounds;
float fx, fy;
@@ -383,6 +383,11 @@ void entity_t::link(world_t *world)
float xlip, ylip;
size_t xsecs, ysecs;
+ if (world)
+ unlink();
+
+ world = world_;
+
total_bounds = cmodel.bounds | render_bounds;
fx = floor(total_bounds[0][0]);
@@ -425,7 +430,7 @@ void entity_t::unlink(void)
}
parents.clear();
- parent_world = nullptr;
+ world = 0;
}
} // namespace world