Commit 136fa6bc authored by louiz’'s avatar louiz’

Implement attack animations

And fix a few related things in Tasks and Works
parent 440cb7bc
...@@ -353,6 +353,7 @@ void GameClient::on_entity_task_changed(const Entity* entity, const Task* task) ...@@ -353,6 +353,7 @@ void GameClient::on_entity_task_changed(const Entity* entity, const Task* task)
this->sounds_handler.play(SoundType::Dash, false, 100.f); this->sounds_handler.play(SoundType::Dash, false, 100.f);
break; break;
} }
this->camera.on_entity_task_changed(entity, task);
} }
void GameClient::on_entity_deleted(const Entity* entity) void GameClient::on_entity_deleted(const Entity* entity)
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <world/layer.hpp> #include <world/layer.hpp>
#include <world/entity.hpp> #include <world/entity.hpp>
#include <world/team.hpp> #include <world/team.hpp>
#include <world/task.hpp>
#include <gui/utils.hpp> #include <gui/utils.hpp>
#include <game/game_client.hpp> #include <game/game_client.hpp>
#include <climits> #include <climits>
...@@ -727,6 +728,43 @@ void Camera::draw_energy_bar(sf::Vector2f screen_position, const EnergyBar& bar_ ...@@ -727,6 +728,43 @@ void Camera::draw_energy_bar(sf::Vector2f screen_position, const EnergyBar& bar_
} }
} }
void Camera::draw_vertical_bar(sf::Vector2f screen_position, const EnergyBar& bar_specs,
const std::size_t max_val, int current_val)
{
sf::RectangleShape rect;
rect.setSize(bar_specs.size);
rect.setOutlineColor(sf::Color::Black);
rect.setOutlineThickness(1);
rect.setFillColor({25, 25, 25, 200});
screen_position.x -= bar_specs.size.x/2;
screen_position.y -= bar_specs.size.y/2;
rect.setPosition(screen_position);
float grad_width = bar_specs.size.x / (max_val / bar_specs.little_graduation);
this->draw(rect);
rect.setOutlineThickness(1);
float grad_height = bar_specs.size.y / (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);
rect.setSize({bar_specs.size.x, grad_height});
while (current_val > 0)
{
if (current_val >= bar_specs.little_graduation)
rect.setFillColor(color);
else
rect.setFillColor(color * sf::Color(255, 255, 255, 100));
rect.setPosition(screen_position);
this->draw(rect);
current_val -= bar_specs.little_graduation;
screen_position.y += grad_height;
}
}
void Camera::on_new_entity(const Entity* entity) void Camera::on_new_entity(const Entity* entity)
{ {
if (entity->get_type() == 0) if (entity->get_type() == 0)
...@@ -756,6 +794,19 @@ void Camera::on_entity_deleted(const Entity* entity) ...@@ -756,6 +794,19 @@ void Camera::on_entity_deleted(const Entity* entity)
} }
} }
void Camera::on_entity_task_changed(const Entity* entity, const Task* task)
{
// Look for an EntitySprite using this entity pointer
auto it = std::find_if(this->sprites.begin(),
this->sprites.end(),
[entity](const auto& s)
{
return s->get_entity() == entity;
});
assert(it != this->sprites.end());
(*it)->set_task(task);
}
const sf::Vector2u Camera::get_win_size() const const sf::Vector2u Camera::get_win_size() const
{ {
return this->win().getSize(); return this->win().getSize();
......
...@@ -36,6 +36,7 @@ class WorldSprite; ...@@ -36,6 +36,7 @@ class WorldSprite;
class GameClient; class GameClient;
class Entity; class Entity;
class EntitySprite; class EntitySprite;
class Task;
class Camera: public ScreenElement class Camera: public ScreenElement
{ {
...@@ -58,6 +59,9 @@ public: ...@@ -58,6 +59,9 @@ public:
*/ */
void draw_energy_bar(sf::Vector2f screen_position, const EnergyBar& bar, void draw_energy_bar(sf::Vector2f screen_position, const EnergyBar& bar,
const std::size_t max_val, int current_val); const std::size_t max_val, int current_val);
void draw_vertical_bar(sf::Vector2f screen_position, const EnergyBar& bar_specs,
const std::size_t max_val, int current_val);
/** /**
* Draw an indicator, centered around `center`, the width is the diameter. * Draw an indicator, centered around `center`, the width is the diameter.
*/ */
...@@ -150,6 +154,7 @@ public: ...@@ -150,6 +154,7 @@ public:
void draw(const sf::Drawable&, const sf::RenderStates& states = sf::RenderStates::Default); void draw(const sf::Drawable&, const sf::RenderStates& states = sf::RenderStates::Default);
void on_new_entity(const Entity*); void on_new_entity(const Entity*);
void on_entity_deleted(const Entity*); void on_entity_deleted(const Entity*);
void on_entity_task_changed(const Entity* entity, const Task* task);
void graphical_tick(); void graphical_tick();
const sf::Vector2u get_win_size() const; const sf::Vector2u get_win_size() const;
......
#ifndef ANIMATIONS_HPP_INCLUDED
#define ANIMATIONS_HPP_INCLUDED
#include <gui/sprites/energy_bar.hpp>
struct AttackAnimation
{
/**
* The total duration of the frontswing
*/
std::size_t fs;
/**
* The total duration of the backswing
*/
std::size_t bs;
};
#endif /* ANIMATIONS_HPP_INCLUDED */
#include <gui/sprites/entity_sprite.hpp> #include <gui/sprites/entity_sprite.hpp>
#include <world/entity.hpp> #include <world/entity.hpp>
#include <world/task.hpp>
#include <world/location.hpp> #include <world/location.hpp>
#include <logging/logging.hpp>
sf::Texture EntitySprite::shadow_texture; sf::Texture EntitySprite::shadow_texture;
bool EntitySprite::init = false; bool EntitySprite::init = false;
const std::vector<sf::Color> EntitySprite::team_colors = {sf::Color::White, const std::vector<sf::Color> EntitySprite::team_colors = {sf::Color::White,
...@@ -10,7 +13,8 @@ const std::vector<sf::Color> EntitySprite::team_colors = {sf::Color::White, ...@@ -10,7 +13,8 @@ const std::vector<sf::Color> EntitySprite::team_colors = {sf::Color::White,
sf::Color::Blue}; sf::Color::Blue};
EntitySprite::EntitySprite(const Entity* const entity): EntitySprite::EntitySprite(const Entity* const entity):
entity(entity) entity(entity),
task_type(TaskType::None)
{ {
if (EntitySprite::init == false) if (EntitySprite::init == false)
{ {
...@@ -64,3 +68,11 @@ bool EntitySprite::is_mouse_over(const Camera* camera) const ...@@ -64,3 +68,11 @@ bool EntitySprite::is_mouse_over(const Camera* camera) const
mouse_pos.y > ent_pos.y - 80 && mouse_pos.y > ent_pos.y - 80 &&
mouse_pos.y < ent_pos.y + 20); 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()));
this->task_type = task->get_type();
this->on_task_changed(task);
}
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <vector> #include <vector>
enum class TaskType;
class Task;
class Entity; class Entity;
class EntitySprite: public WorldSprite class EntitySprite: public WorldSprite
...@@ -16,12 +18,20 @@ public: ...@@ -16,12 +18,20 @@ public:
const Entity* get_entity() const; const Entity* get_entity() const;
Position get_world_pos() const override final; Position get_world_pos() const override final;
bool is_mouse_over(const Camera* camera) const; 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
* draw (until the task is changed) is the move animation, if any.
*/
void set_task(const Task* task);
protected: protected:
const Entity* const entity; const Entity* const entity;
void draw_shadow(Camera& camera, const sf::Color color) const; void draw_shadow(Camera& camera, const sf::Color color) const;
virtual void on_task_changed(const Task*) {}
static const std::vector<sf::Color> team_colors; static const std::vector<sf::Color> team_colors;
TaskType task_type;
private: private:
static bool init; static bool init;
......
...@@ -6,10 +6,12 @@ ...@@ -6,10 +6,12 @@
#include <world/manapool.hpp> #include <world/manapool.hpp>
#include <world/team.hpp> #include <world/team.hpp>
#include <world/location.hpp> #include <world/location.hpp>
#include <world/tasks/attack_task.hpp>
PicpicSprite::PicpicSprite(const Entity* const entity): PicpicSprite::PicpicSprite(const Entity* const entity):
EntitySprite(entity), EntitySprite(entity),
float_direction(-0.0002) float_direction(-0.0002),
animation(PicpicSprite::Animation::Idle)
{ {
if (PicpicSprite::init == false) if (PicpicSprite::init == false)
{ {
...@@ -50,7 +52,7 @@ void PicpicSprite::draw(GameClient* game) const ...@@ -50,7 +52,7 @@ void PicpicSprite::draw(GameClient* game) const
EnergyBar bar = this->standard_health_bar; EnergyBar bar = this->standard_health_bar;
Health* entity_health = entity->get<Health>(); Health* entity_health = this->entity->get<Health>();
if (entity_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_debug_hud().add_debug_line("Entity health: " + std::to_string(entity_health->get()) + "/" +std::to_string(entity_health->get_max()));
...@@ -64,6 +66,16 @@ void PicpicSprite::draw(GameClient* game) const ...@@ -64,6 +66,16 @@ void PicpicSprite::draw(GameClient* game) const
game->get_camera().draw_energy_bar({x, y - 80}, mana_bar, entity_mana->get_max().to_int(), entity_mana->get().to_int()); game->get_camera().draw_energy_bar({x, y - 80}, mana_bar, entity_mana->get_max().to_int(), entity_mana->get().to_int());
} }
switch (this->animation)
{
case Animation::Idle:
return;
case Animation::Move:
// TODO
break;
case Animation::Attack:
this->draw_attack_animation(this->entity->get_task<AttackTask>(), game, {x - 80, y});
}
} }
void PicpicSprite::tick() void PicpicSprite::tick()
...@@ -73,6 +85,62 @@ void PicpicSprite::tick() ...@@ -73,6 +85,62 @@ void PicpicSprite::tick()
this->height += this->float_direction; this->height += this->float_direction;
} }
void PicpicSprite::on_task_changed(const Task* task)
{
log_debug("on task change (init): " << static_cast<int>(task->get_type()));
switch (task->get_type())
{
case TaskType::None:
this->animation = PicpicSprite::Animation::Idle;
break;
case TaskType::Attack:
this->animation = PicpicSprite::Animation::Attack;
this->init_attack_animation(static_cast<const AttackTask*>(task));
break;
case TaskType::Follow:
case TaskType::Path:
this->animation = PicpicSprite::Animation::Move;
break;
}
}
void PicpicSprite::init_attack_animation(const AttackTask* task)
{
log_debug("Init task anim with: fs=" << task->get_remaining_frontswing_duration() <<
" and bs=" << task->get_remaining_backswing_duration());
this->attack_animation = {task->get_remaining_frontswing_duration(),
task->get_remaining_backswing_duration()};
}
void PicpicSprite::draw_attack_animation(const AttackTask* task, GameClient* game, sf::Vector2f pos) const
{
std::size_t current_fs;
std::size_t current_bs;
if (task)
{
current_fs = task->get_remaining_frontswing_duration();
current_bs = task->get_remaining_backswing_duration();
}
else
{
current_fs = 0;
current_bs = this->attack_animation.bs;
}
auto current_value = (current_fs > 0 ? this->attack_animation.fs - current_fs: current_bs);
int max = (current_fs > 0 ? this->attack_animation.fs : this->attack_animation.bs);
EnergyBar bar = {
sf::Color::Red,
sf::Color::Red,
{8, 100},
2,
0
};
game->get_camera().draw_vertical_bar(pos, bar, max, current_value);
}
bool PicpicSprite::init = false; bool PicpicSprite::init = false;
sf::Texture PicpicSprite::body_texture; sf::Texture PicpicSprite::body_texture;
sf::Texture PicpicSprite::eye_texture; sf::Texture PicpicSprite::eye_texture;
...@@ -2,9 +2,20 @@ ...@@ -2,9 +2,20 @@
# define __PICPIC_SPRITE_HPP__ # define __PICPIC_SPRITE_HPP__
#include <gui/sprites/entity_sprite.hpp> #include <gui/sprites/entity_sprite.hpp>
#include <gui/sprites/animations.hpp>
class AttackTask;
class PicpicSprite: public EntitySprite class PicpicSprite: public EntitySprite
{ {
enum class Animation
{
Idle,
Move,
Attack,
count
};
public: public:
PicpicSprite(const Entity* const); PicpicSprite(const Entity* const);
...@@ -15,6 +26,13 @@ public: ...@@ -15,6 +26,13 @@ public:
private: private:
float height; float height;
float float_direction; float float_direction;
Animation animation;
AttackAnimation attack_animation;
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;
PicpicSprite(const PicpicSprite&); PicpicSprite(const PicpicSprite&);
PicpicSprite& operator=(const PicpicSprite&); PicpicSprite& operator=(const PicpicSprite&);
......
...@@ -21,16 +21,6 @@ void Abilities::add(const std::size_t index, ...@@ -21,16 +21,6 @@ void Abilities::add(const std::size_t index,
this->abilities[index] = std::move(ability); this->abilities[index] = std::move(ability);
} }
Ability* Abilities::find(const AbilityType& type) const
{
for (auto& ability: this->abilities)
{
if (ability->get_type() == type)
return ability.get();
}
return nullptr;
}
template <typename T> template <typename T>
T* get_ability(Entity* entity) T* get_ability(Entity* entity)
{ {
......
...@@ -19,9 +19,9 @@ public: ...@@ -19,9 +19,9 @@ public:
static const ComponentType component_type = ComponentType::Abilities; static const ComponentType component_type = ComponentType::Abilities;
Abilities(const std::size_t size, Abilities(const std::size_t size,
const std::size_t fs, const std::size_t bs): const std::size_t fs, const std::size_t bs):
abilities(size),
cast_frontswing(fs), cast_frontswing(fs),
cast_backswing(bs) cast_backswing(bs),
abilities(size)
{} {}
~Abilities() = default; ~Abilities() = default;
void tick(Entity* entity, World* world) override final void tick(Entity* entity, World* world) override final
...@@ -39,7 +39,16 @@ public: ...@@ -39,7 +39,16 @@ public:
/** /**
* Look for an Ability with that type. * Look for an Ability with that type.
*/ */
Ability* find(const AbilityType& type) const; template <typename Type = Ability>
Type* find(const AbilityType& type) const
{
for (auto& ability: this->abilities)
{
if (ability->get_type() == type)
return static_cast<Type*>(ability.get());
}
return nullptr;
}
/** /**
* The duration, in ticks, of the two phases of a casted ability * The duration, in ticks, of the two phases of a casted ability
......
...@@ -20,20 +20,20 @@ Attack::Attack(const utils::Duration fs_duration, const utils::Duration bs_durat ...@@ -20,20 +20,20 @@ Attack::Attack(const utils::Duration fs_duration, const utils::Duration bs_durat
{ {
} }
void Attack::cast(Entity* entity, World*, const Position& pos, const bool queue) void Attack::cast(Entity* entity, World* world, const Position& pos, const bool queue)
{ {
log_debug("Attacking with entity " << entity->get_id() << " until position " << pos); log_debug("Attacking with entity " << entity->get_id() << " until position " << pos);
auto work = std::make_unique<AttackWork>(entity, pos, this->range); auto work = std::make_unique<AttackWork>(world, entity, pos, this->range);
if (queue) if (queue)
entity->queue_work(std::move(work)); entity->queue_work(std::move(work));
else else
entity->set_work(std::move(work)); entity->set_work(std::move(work));
} }
void Attack::cast(Entity* entity, World *, const std::shared_ptr<Entity>& target, const bool queue) void Attack::cast(Entity* entity, World* world, const std::shared_ptr<Entity>& target, const bool queue)
{ {
log_debug("Attacking with entity " << entity->get_id() << " the target " << target->get_id()); log_debug("Attacking with entity " << entity->get_id() << " the target " << target->get_id());
auto work = std::make_unique<AttackWork>(entity, target, this->range); auto work = std::make_unique<AttackWork>(world, entity, target, this->range);
if (queue) if (queue)
entity->queue_work(std::move(work)); entity->queue_work(std::move(work));
else else
...@@ -49,3 +49,8 @@ std::size_t Attack::get_backswing_duration() const ...@@ -49,3 +49,8 @@ std::size_t Attack::get_backswing_duration() const
{ {
return this->backswing_duration; return this->backswing_duration;
} }
Fix16 Attack::get_range() const
{
return this->range;
}
...@@ -16,6 +16,8 @@ public: ...@@ -16,6 +16,8 @@ public:
std::size_t get_frontswing_duration() const; std::size_t get_frontswing_duration() const;
std::size_t get_backswing_duration() const; std::size_t get_backswing_duration() const;
Fix16 get_range() const;
private: private:
std::size_t frontswing_duration; std::size_t frontswing_duration;
std::size_t backswing_duration; std::size_t backswing_duration;
......
...@@ -17,11 +17,11 @@ Blink::Blink(): ...@@ -17,11 +17,11 @@ Blink::Blink():
{ {
} }
void Blink::cast(Entity* entity, World*, const Position& position, const bool queue) void Blink::cast(Entity* entity, World* world, const Position& position, const bool queue)
{ {
// Check mana, cooldown etc etc // Check mana, cooldown etc etc
log_debug("CASTING blink for entity" << entity->get_id() << " to pos " << position); log_debug("CASTING blink for entity" << entity->get_id() << " to pos " << position);
auto work = std::make_unique<BlinkWork>(entity, position); auto work = std::make_unique<BlinkWork>(world, entity, position);
if (queue) if (queue)
entity->queue_work(std::move(work)); entity->queue_work(std::move(work));
else else
......
...@@ -19,6 +19,6 @@ void Concentrate::cast(Entity* entity, World* world, const bool queue) ...@@ -19,6 +19,6 @@ void Concentrate::cast(Entity* entity, World* world, const bool queue)
{ {
log_debug("Concentrate::cast. Starting concentrate task"); log_debug("Concentrate::cast. Starting concentrate task");
// TODO queue, or disable queue alltogether // TODO queue, or disable queue alltogether
auto work = std::make_unique<ConcentrateWork>(entity, world); auto work = std::make_unique<ConcentrateWork>(world, entity);
entity->set_work(std::move(work)); entity->set_work(std::move(work));
} }
...@@ -57,7 +57,7 @@ void Dash::cast(Entity* entity, World* world, const Position& pos, const bool qu ...@@ -57,7 +57,7 @@ void Dash::cast(Entity* entity, World* world, const Position& pos, const bool qu
world->callbacks->impact(entity, impacted_entity); world->callbacks->impact(entity, impacted_entity);
health->add(-concentrate_value); health->add(-concentrate_value);
}; };
auto work = std::make_unique<DashWork>(entity, world, pos, 50, this->max_distance, 50, auto work = std::make_unique<DashWork>(world, entity, pos, 50, this->max_distance, 50,
on_impact, nullptr); on_impact, nullptr);
entity->set_work(std::move(work)); entity->set_work(std::move(work));
} }
......
...@@ -26,6 +26,6 @@ void Emp::cast(Entity* entity, World* world, const Position& position, const boo ...@@ -26,6 +26,6 @@ void Emp::cast(Entity* entity, World* world, const Position& position, const boo
return; return;
auto emp = world->do_new_entity(2, position, team->get()); auto emp = world->do_new_entity(2, position, team->get());
emp->set_work(std::make_unique<EmpWork>(emp, world)); emp->set_work(std::make_unique<EmpWork>(world, emp));
world->callbacks->ability_casted(entity, AbilityType::Emp, nullptr, position); world->callbacks->ability_casted(entity, AbilityType::Emp, nullptr, position);
} }
...@@ -4,17 +4,11 @@ ...@@ -4,17 +4,11 @@
#include <world/entity.hpp> #include <world/entity.hpp>
#include <world/world.hpp> #include <world/world.hpp>
#include <world/work.hpp> #include <world/work.hpp>
#include <world/tasks/idle_task.hpp>
#include <world/world_callbacks.hpp>
EntityId Entity::current_id = 0; EntityId Entity::current_id = 0;