Commit 80afc91f authored by louiz’'s avatar louiz’

Simplify how EntitySprites draw themselves

They do not need to know anything about the Camera or any of their screen
position, they just draw themselves around the 0:0 coordinates, and they use
the given sf::RenderStates (which contains the translation to draw the
Sprite at the correct screen position).
parent 496df4fe
......@@ -341,34 +341,51 @@ void Camera::draw()
// the top
y -= LEVEL_HEIGHT;
}
// Display all the sprites that are on this row
for (const auto& sprite: this->sprites)
{
Position sprite_world_position = sprite->get_world_pos();
unsigned short x;
unsigned short y;
std::tie(x, y) = this->world().get_cell_at_position(sprite_world_position);
if (y == row &&
unsigned short x_cell;
unsigned short y_cell;
std::tie(x_cell, y_cell) = this->world().get_cell_at_position(sprite_world_position);
if (y_cell == row &&
this->world().can_be_seen_by_team(sprite_world_position, this->game->get_self_team()))
{
const Entity* entity = sprite->get_entity();
Team* team = entity->get<Team>();
const auto entpos = this->world_to_camera_position(sprite_world_position);
if (entity->is_manipulable() &&
this->mouse_selection.contains(this->get_mouse_position(),
this->world_to_camera_position(sprite_world_position))
)
{
this->draw_hover_indicator(
this->world_to_camera_position(sprite_world_position),
80);
}
(this->mouse_selection.contains(this->get_mouse_position(), entpos)))
this->draw_hover_indicator(entpos, 80);
if (this->get_game_client()->is_entity_selected(sprite->get_entity()))
this->draw_selected_indicator(this->world_to_camera_position(sprite_world_position), 80);
sprite->draw(this->game);
this->draw_selected_indicator(entpos, 80);
// The sprites draw themselves around the 0:0 coordinates. We
// just pass a RenderStates object to them, translating the
// whole drawing to the correct camera position. This way the
// sprites class does not need to know anything about the
// world or camera coordinates.
sf::Transform transform;
transform.translate(entpos.x - this->x,
entpos.y - this->y);
sprite->draw(this->win(), transform);
auto health = entity->get<Health>();
auto team = entity->get<Team>();
if (health)
{
auto bar = WorldSprite::standard_health_bar;
if (team && team->get() == 1)
bar.max_color = sf::Color::Blue;
this->draw_energy_bar(bar, health->get_max().to_int(),
health->get().to_int(), transform);
}
}
}
this->win().setView(this->win().getDefaultView());
}
this->draw_mouse_selection();
......@@ -683,35 +700,53 @@ const Entity* Camera::get_entity_under_mouse() const
for (auto it = this->sprites.crbegin(); it != this->sprites.crend(); ++it)
{
EntitySprite* sprite = it->get();
if (sprite->is_mouse_over(this) == true)
if (this->is_mouse_over(sprite) == true)
return sprite->get_entity();
}
return nullptr;
}
bool Camera::is_mouse_over(const EntitySprite* sprite) const
{
auto location = sprite->get_entity()->get<Location>();
if (!location)
return false;
const auto pos = this->get_mouse_position();
Position mouse_pos = this->camera_to_world_position(pos.x,
pos.y);
Position ent_pos = location->position();
// TODO, use different values depending on the sprite's size
return (mouse_pos.x > ent_pos.x - 50 &&
mouse_pos.x < ent_pos.x + 50 &&
mouse_pos.y > ent_pos.y - 80 &&
mouse_pos.y < ent_pos.y + 20);
}
void Camera::draw(const sf::Drawable& drawable, const sf::RenderStates& states)
{
this->win().draw(drawable, states);
}
void Camera::draw_energy_bar(sf::Vector2f screen_position, const EnergyBar& bar_specs,
const std::size_t max_val, int current_val)
void Camera::draw_energy_bar(const EnergyBar& bar_specs, const std::size_t max_val,
int current_val, const sf::RenderStates& states)
{
sf::RectangleShape rect;
rect.setSize(bar_specs.size);
rect.setOrigin(bar_specs.size.x/2, bar_specs.size.y/2);
rect.setOutlineColor(sf::Color::Black);
rect.setOutlineThickness(1);
rect.setFillColor({25, 25, 25, 200});
screen_position.x -= bar_specs.size.x/2;
rect.setPosition(screen_position);
rect.setPosition(0, -70);
this->draw(rect);
this->draw(rect, states);
rect.setOutlineThickness(1);
float grad_width = bar_specs.size.x / (max_val / bar_specs.little_graduation);
sf::Color color = mix(bar_specs.min_color, bar_specs.max_color,
static_cast<float>(current_val) / max_val);
0.3 + (static_cast<float>(current_val) / max_val) * 0.7);
rect.setSize({grad_width, bar_specs.size.y});
while (current_val > 0)
......@@ -720,11 +755,10 @@ void Camera::draw_energy_bar(sf::Vector2f screen_position, const EnergyBar& bar_
rect.setFillColor(color);
else
rect.setFillColor(color * sf::Color(255, 255, 255, 100));
rect.setPosition(screen_position);
this->draw(rect);
this->draw(rect, states);
rect.move(grad_width, 0);
current_val -= bar_specs.little_graduation;
screen_position.x += grad_width;
}
}
......
......@@ -32,7 +32,6 @@
class Minimap;
class Screen;
class WorldSprite;
class GameClient;
class Entity;
class EntitySprite;
......@@ -57,11 +56,11 @@ public:
/**
* Draw an energy bar, centered at the given screen position.
*/
void draw_energy_bar(sf::Vector2f screen_position, const EnergyBar& bar,
const std::size_t max_val, int current_val);
void draw_energy_bar(const EnergyBar& bar, const std::size_t max_val,
int current_val, const sf::RenderStates& states);
void draw_vertical_bar(sf::Vector2f screen_position, const EnergyBar& bar_specs,
const std::size_t max_val, int current_val);
bool is_mouse_over(const EntitySprite* sprite) const;
/**
* Draw an indicator, centered around `center`, the width is the diameter.
*/
......
......@@ -55,9 +55,10 @@ cursor::type draw_dash_concentrate_cursor(const sf::Vector2i& mouse_position, Ga
if (task)
current_val = std::min(task->value().to_int(), dash->get_max_concentration().to_int());
}
game->get_camera().draw_energy_bar(
{static_cast<float>(mouse_position.x - 8),
static_cast<float>(mouse_position.y - 75)},
bar, dash->get_max_concentration().to_int(), current_val);
sf::Transform transform;
transform.translate(mouse_position.x,
mouse_position.y);
game->get_camera().draw_energy_bar(bar, dash->get_max_concentration().to_int(), current_val,
transform);
return cursor::Build;
}
......@@ -2,7 +2,6 @@
#include <world/location.hpp>
#include <world/mobility.hpp>
#include <world/entity.hpp>
#include <game/game_client.hpp>
bool BulletSprite::init = false;
sf::Texture BulletSprite::texture;
......@@ -19,24 +18,16 @@ BulletSprite::BulletSprite(const Entity* const entity):
}
}
void BulletSprite::draw(GameClient* game) const
void BulletSprite::draw(sf::RenderTarget& surface, const sf::RenderStates& states) const
{
sf::Sprite sprite(this->texture);
sprite.setOrigin(32, 32);
sprite.setOrigin(this->texture.getSize().x/2, this->texture.getSize().y/2);
sprite.setScale({0.4, 0.4});
Mobility* mobility = this->entity->get<Mobility>();
assert(mobility);
sprite.setRotation(mobility->get_angle().to_double());
Location* location = this->entity->get<Location>();
assert(location);
const auto entpos = game->get_camera().world_to_camera_position(location->position());
const float x = entpos.x - game->get_camera().x;
const float y = entpos.y - game->get_camera().y;
sprite.setPosition(x, y);
game->get_camera().draw(sprite);
surface.draw(sprite, states);
}
void BulletSprite::tick()
......
......@@ -8,7 +8,7 @@ class BulletSprite: public EntitySprite
public:
BulletSprite(const Entity* const);
~BulletSprite() = default;
void draw(GameClient* game) const override final;
void draw(sf::RenderTarget& surface, const sf::RenderStates& states) const override final;
void tick() override final;
static bool init;
......
#include <gui/sprites/emp_sprite.hpp>
#include <world/location.hpp>
#include <world/entity.hpp>
#include <game/game_client.hpp>
constexpr unsigned int emp_radius = 300;
......@@ -14,16 +13,10 @@ EmpSprite::EmpSprite(const Entity* const entity):
this->circle.setFillColor({255, 0, 255, 123});
}
void EmpSprite::draw(GameClient* game) const
void EmpSprite::draw(sf::RenderTarget& surface, const sf::RenderStates& states) const
{
Location* location = this->entity->get<Location>();
assert(location);
const auto entpos = game->get_camera().world_to_camera_position(location->position());
const float x = entpos.x - game->get_camera().x;
const float y = entpos.y - game->get_camera().y;
this->circle.setPosition(x, y);
game->get_camera().draw(this->circle);
this->circle.setPosition(0, 0);
surface.draw(this->circle, states);
}
void EmpSprite::tick()
......
......@@ -8,7 +8,7 @@ class EmpSprite: public EntitySprite
public:
EmpSprite(const Entity* const);
~EmpSprite() = default;
void draw(GameClient* game) const override final;
void draw(sf::RenderTarget& surface, const sf::RenderStates& states) const override final;
void tick() override final;
private:
......
......@@ -24,19 +24,12 @@ EntitySprite::EntitySprite(const Entity* const entity):
}
}
void EntitySprite::draw_shadow(Camera& camera, const sf::Color color) const
void EntitySprite::draw_shadow(sf::RenderTarget& surface, const sf::RenderStates& states) const
{
Location* location = this->entity->get<Location>();
assert(location);
const auto entpos = camera.world_to_camera_position(location->position());
const int x = entpos.x - camera.x;
const int y = entpos.y - camera.y;
const sf::Vector2u size = EntitySprite::shadow_texture.getSize();
sf::Sprite sprite(EntitySprite::shadow_texture);
sprite.setPosition(x - size.x/2, y - size.y/2);
sprite.setColor(color);
camera.draw(sprite);
sprite.setOrigin(size.x/2, size.y/2);
surface.draw(sprite, states);
}
const Entity* EntitySprite::get_entity() const
......@@ -51,24 +44,6 @@ Position EntitySprite::get_world_pos() const
return location->position();
}
bool EntitySprite::is_mouse_over(const Camera* camera) const
{
Location* location = this->entity->get<Location>();
if (!location)
return false;
const auto pos = camera->get_mouse_position();
Position mouse_pos = camera->camera_to_world_position(pos.x,
pos.y);
Position ent_pos = location->position();
// TODO, use different values depending on the sprite's size
return (mouse_pos.x > ent_pos.x - 50 &&
mouse_pos.x < ent_pos.x + 50 &&
mouse_pos.y > ent_pos.y - 80 &&
mouse_pos.y < ent_pos.y + 20);
}
void EntitySprite::set_task(const Task* task)
{
log_debug("EntitySprite::set_task" << static_cast<int>(task->get_type()));
......
......@@ -2,7 +2,6 @@
# define __ENTITY_SPRITE_HPP__
#include <gui/sprites/world_sprite.hpp>
#include <gui/camera/camera.hpp>
#include <vector>
......@@ -17,7 +16,6 @@ public:
~EntitySprite() {}
const Entity* get_entity() const;
Position get_world_pos() const override final;
bool is_mouse_over(const Camera* camera) const;
/**
* Set our current animation based on the new task the entity is doing.
* For example if our new task is TaskType::Move, the current animation we
......@@ -27,7 +25,7 @@ public:
protected:
const Entity* const entity;
void draw_shadow(Camera& camera, const sf::Color color) const;
void draw_shadow(sf::RenderTarget& surface, const sf::RenderStates& states) const;
virtual void on_task_changed(const Task*) {}
static const std::vector<sf::Color> team_colors;
......
......@@ -26,45 +26,12 @@ PicpicSprite::PicpicSprite(const Entity* const entity):
this->height = -5 + (7 * random() / RAND_MAX);
}
void PicpicSprite::draw(GameClient* game) const
void PicpicSprite::draw(sf::RenderTarget& surface, const sf::RenderStates& states) const
{
Team* team = this->entity->get<Team>();
assert(team);
Location* location = this->entity->get<Location>();
assert(location);
this->draw_shadow(game->get_camera(), this->team_colors[team->get()]);
const auto entpos = game->get_camera().world_to_camera_position(location->position());
const float x = entpos.x - game->get_camera().x;
const float y = entpos.y - game->get_camera().y;
sf::Sprite sprite(PicpicSprite::body_texture);
const sf::Vector2u size = PicpicSprite::body_texture.getSize();
sprite.setPosition(x - size.x/2, y - size.y - this->height);
game->get_camera().draw(sprite);
sf::Sprite eye_sprite(PicpicSprite::eye_texture);
const sf::Vector2u eye_size = PicpicSprite::eye_texture.getSize();
eye_sprite.setPosition(x - 10 - eye_size.x/2, y - size.y / 5 * 3 - this->height - eye_size.y/2 + 5);
game->get_camera().draw(eye_sprite);
eye_sprite.setPosition(x + 10 - eye_size.x/2, y - size.y / 5 * 3 - this->height - eye_size.y/2 + 5);
game->get_camera().draw(eye_sprite);
EnergyBar bar = this->standard_health_bar;
Health* entity_health = this->entity->get<Health>();
if (entity_health)
{
game->get_debug_hud().add_debug_line("Entity health: " + std::to_string(entity_health->get()) + "/" +std::to_string(entity_health->get_max()));
game->get_camera().draw_energy_bar({x, y - 90}, bar, entity_health->get_max().to_int(), entity_health->get().to_int());
}
EnergyBar mana_bar = this->standard_mana_bar;
ManaPool* entity_mana = entity->get<ManaPool>();
if (entity_mana)
{
game->get_debug_hud().add_debug_line("Entity mana: " + std::to_string(entity_mana->get()) + "/" +std::to_string(entity_mana->get_max()));
game->get_camera().draw_energy_bar({x, y - 80}, mana_bar, entity_mana->get_max().to_int(), entity_mana->get().to_int());
}
sprite.setOrigin(size.x/2, size.y);
surface.draw(sprite, states);
switch (this->animation)
{
......@@ -74,7 +41,8 @@ void PicpicSprite::draw(GameClient* game) const
// TODO
break;
case Animation::Attack:
this->draw_attack_animation(this->entity->get_task<AttackTask>(), game, {x - 80, y});
this->draw_attack_animation(surface, this->entity->get_task<AttackTask>());
break;
}
}
......@@ -112,7 +80,7 @@ void PicpicSprite::init_attack_animation(const AttackTask* task)
task->get_remaining_backswing_duration()};
}
void PicpicSprite::draw_attack_animation(const AttackTask* task, GameClient* game, sf::Vector2f pos) const
void PicpicSprite::draw_attack_animation(sf::RenderTarget& surface, const AttackTask* task) const
{
std::size_t current_fs;
std::size_t current_bs;
......@@ -138,7 +106,7 @@ void PicpicSprite::draw_attack_animation(const AttackTask* task, GameClient* gam
2,
0
};
game->get_camera().draw_vertical_bar(pos, bar, max, current_value);
// game->get_camera().draw_vertical_bar({-80.f, 0.f}, bar, max, current_value);
}
bool PicpicSprite::init = false;
......
......@@ -19,7 +19,7 @@ class PicpicSprite: public EntitySprite
public:
PicpicSprite(const Entity* const);
void draw(GameClient* game) const override final;
void draw(sf::RenderTarget& surface, const sf::RenderStates& states) const override final;
void tick() override final;
static bool init;
......@@ -32,7 +32,7 @@ private:
void on_task_changed(const Task*) override final;
void init_attack_animation(const AttackTask*);
void draw_attack_animation(const AttackTask* task, GameClient* game, sf::Vector2f pos) const;
void draw_attack_animation(sf::RenderTarget& surface, const AttackTask* task) const;
PicpicSprite(const PicpicSprite&);
PicpicSprite& operator=(const PicpicSprite&);
......
......@@ -19,39 +19,12 @@ TourbillonSprite::TourbillonSprite(const Entity* const entity):
}
}
void TourbillonSprite::draw(GameClient* game) const
void TourbillonSprite::draw(sf::RenderTarget& surface, const sf::RenderStates& states) const
{
Team* team = this->entity->get<Team>();
assert(team);
Location* location = this->entity->get<Location>();
assert(location);
this->draw_shadow(game->get_camera(), this->team_colors[team->get()]);
const auto entpos = game->get_camera().world_to_camera_position(location->position());
const float x = entpos.x - game->get_camera().x;
const float y = entpos.y - game->get_camera().y;
sf::Sprite sprite(TourbillonSprite::body_texture);
const sf::Vector2u size = TourbillonSprite::body_texture.getSize();
sprite.setPosition(x - size.x/2, y - size.y);
game->get_camera().draw(sprite);
EnergyBar bar = this->standard_health_bar;
Health* entity_health = entity->get<Health>();
if (entity_health)
{
game->get_debug_hud().add_debug_line("Entity health: " + std::to_string(entity_health->get()) + "/" +std::to_string(entity_health->get_max()));
game->get_camera().draw_energy_bar({x, y - 90}, bar, entity_health->get_max().to_int(), entity_health->get().to_int());
}
EnergyBar mana_bar = this->standard_mana_bar;
ManaPool* entity_mana = entity->get<ManaPool>();
if (entity_mana)
{
game->get_debug_hud().add_debug_line("Entity mana: " + std::to_string(entity_mana->get()) + "/" +std::to_string(entity_mana->get_max()));
game->get_camera().draw_energy_bar({x, y - 80}, mana_bar, entity_mana->get_max().to_int(), entity_mana->get().to_int());
}
sprite.setOrigin(size.x/2, size.y);
surface.draw(sprite, states);
}
void TourbillonSprite::tick()
......
......@@ -7,7 +7,7 @@ class TourbillonSprite: public EntitySprite
{
public:
TourbillonSprite(const Entity* const);
void draw(GameClient* game) const override final;
void draw(sf::RenderTarget& surface, const sf::RenderStates& states) const override final;
void tick() override final;
~TourbillonSprite() = default;
......
......@@ -6,18 +6,15 @@
#include <world/position.hpp>
#include <gui/sprites/energy_bar.hpp>
class GameClient;
class WorldSprite
{
public:
WorldSprite() {}
virtual ~WorldSprite() {}
virtual void draw(GameClient* game) const = 0;
virtual void draw(sf::RenderTarget& surface, const sf::RenderStates& states) const = 0;
virtual void tick() = 0;
virtual Position get_world_pos() const = 0;
protected:
static const EnergyBar standard_health_bar;
static const EnergyBar standard_mana_bar;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment