diff --git a/TdGame/TdGame/TdGame.vcxproj b/TdGame/TdGame/TdGame.vcxproj index 8f1d853..234ca3b 100644 --- a/TdGame/TdGame/TdGame.vcxproj +++ b/TdGame/TdGame/TdGame.vcxproj @@ -138,7 +138,9 @@ + + @@ -148,9 +150,11 @@ + + @@ -162,6 +166,8 @@ + + diff --git a/TdGame/TdGame/TdGame.vcxproj.filters b/TdGame/TdGame/TdGame.vcxproj.filters index 0d784fb..30e52f7 100644 --- a/TdGame/TdGame/TdGame.vcxproj.filters +++ b/TdGame/TdGame/TdGame.vcxproj.filters @@ -25,6 +25,9 @@ {dbc74129-2d94-42c1-83b7-40d05f5b8aa2} + + {934287b6-3a61-4491-8b40-951a2d797c87} + @@ -119,5 +122,23 @@ 头文件\bullet + + 头文件\tower + + + 头文件\tower + + + 头文件 + + + 头文件\tower + + + 头文件\tower + + + 头文件\tower + \ No newline at end of file diff --git a/TdGame/TdGame/archer_tower.h b/TdGame/TdGame/archer_tower.h new file mode 100644 index 0000000..b991dbf --- /dev/null +++ b/TdGame/TdGame/archer_tower.h @@ -0,0 +1,47 @@ +#ifndef _ARCHER_TOWER_H_ +#define _ARCHER_TOWER_H_ + +#include "tower.h" +#include "resources_manager.h" + + +class ArcherTower : public Tower +{ +public: + ArcherTower() + { + static SDL_Texture* tex_archer = ResourcesManager::instance() + ->get_texture_pool().find(ResID::Tex_Archer)->second; + + static const std::vector idx_list_idle_up = { 3, 4 }; + static const std::vector idx_list_idle_down = { 0, 1 }; + static const std::vector idx_list_idle_left = { 6, 7 }; + static const std::vector idx_list_idle_right = { 9, 10 }; + static const std::vector idx_list_fire_up = { 15, 16, 17 }; + static const std::vector idx_list_fire_down = { 12, 13, 14 }; + static const std::vector idx_list_fire_left = {18, 19, 20}; + static const std::vector idx_list_fire_right = { 21, 22, 23 }; + + anim_idle_up.set_frame_data(tex_archer, 3, 8, idx_list_idle_up); + anim_idle_down.set_frame_data(tex_archer, 3, 8, idx_list_idle_down); + anim_idle_left.set_frame_data(tex_archer, 3, 8, idx_list_idle_left); + anim_idle_right.set_frame_data(tex_archer, 3, 8, idx_list_idle_right); + anim_fire_up.set_frame_data(tex_archer, 3, 8, idx_list_fire_up); + anim_fire_down.set_frame_data(tex_archer, 3, 8, idx_list_fire_down); + anim_fire_left.set_frame_data(tex_archer, 3, 8, idx_list_fire_left); + anim_fire_right.set_frame_data(tex_archer, 3, 8, idx_list_fire_right); + + size.x = 48, size.y = 48; + + tower_type = TowerType::Archer; + + fire_speed = 6; + bullet_type = BulletType::Arrow; + } + ~ArcherTower() = default; + +private: + +}; + +#endif // !_ARCHER_TOWER_H_ diff --git a/TdGame/TdGame/axeman_tower.h b/TdGame/TdGame/axeman_tower.h new file mode 100644 index 0000000..f68fb08 --- /dev/null +++ b/TdGame/TdGame/axeman_tower.h @@ -0,0 +1,46 @@ +#ifndef _AXEMAN_TOWER_H_ +#define _AXEMAN_TOWER_H_ + +#include "tower.h" +#include "resources_manager.h" + + +class AxemanTower : public Tower +{ +public: + AxemanTower() + { + static SDL_Texture* tex_axeman = ResourcesManager::instance() + ->get_texture_pool().find(ResID::Tex_Axeman)->second; + + static const std::vector idx_list_idle_up = { 3, 4 }; + static const std::vector idx_list_idle_down = { 0, 1 }; + static const std::vector idx_list_idle_left = { 9, 10 }; + static const std::vector idx_list_idle_right = { 6, 7 }; + static const std::vector idx_list_fire_up = { 15, 16, 17 }; + static const std::vector idx_list_fire_down = { 12, 13, 14 }; + static const std::vector idx_list_fire_left = { 21, 22, 23 }; + static const std::vector idx_list_fire_right = { 18, 19, 20 }; + + anim_idle_up.set_frame_data(tex_axeman, 3, 8, idx_list_idle_up); + anim_idle_down.set_frame_data(tex_axeman, 3, 8, idx_list_idle_down); + anim_idle_left.set_frame_data(tex_axeman, 3, 8, idx_list_idle_left); + anim_idle_right.set_frame_data(tex_axeman, 3, 8, idx_list_idle_right); + anim_fire_up.set_frame_data(tex_axeman, 3, 8, idx_list_fire_up); + anim_fire_down.set_frame_data(tex_axeman, 3, 8, idx_list_fire_down); + anim_fire_left.set_frame_data(tex_axeman, 3, 8, idx_list_fire_left); + anim_fire_right.set_frame_data(tex_axeman, 3, 8, idx_list_fire_right); + + size.x = 48, size.y = 48; + + tower_type = TowerType::Axeman; + + fire_speed = 5; + bullet_type = BulletType::Axe; + } + ~AxemanTower() = default; + +private: + +}; +#endif // !_AXEMAN_TOWER_H_ diff --git a/TdGame/TdGame/bullet.h b/TdGame/TdGame/bullet.h index b81ea0f..78a27c3 100644 --- a/TdGame/TdGame/bullet.h +++ b/TdGame/TdGame/bullet.h @@ -1,5 +1,5 @@ #ifndef _BULLET_H_ -#define_BULLET_H_ +#define _BULLET_H_ #include "vector2.h" #include "animation.h" @@ -110,6 +110,7 @@ public: is_valid = false; is_collisional = false; } + protected: Vector2 size; Vector2 velocity; diff --git a/TdGame/TdGame/enemy_manager.h b/TdGame/TdGame/enemy_manager.h index 1755f12..adc4ba3 100644 --- a/TdGame/TdGame/enemy_manager.h +++ b/TdGame/TdGame/enemy_manager.h @@ -123,6 +123,11 @@ public: return enemy_list.empty(); } + EnemyList& get_enemy_list() + { + return enemy_list; + } + protected: EnemyManager() = default; diff --git a/TdGame/TdGame/facing.h b/TdGame/TdGame/facing.h new file mode 100644 index 0000000..d85114e --- /dev/null +++ b/TdGame/TdGame/facing.h @@ -0,0 +1,12 @@ +#ifndef _FACING_H_ +#define _FACING_H_ + +enum Facing +{ + Left, + Right, + Up, + Down +}; +#endif // !_FACING_H_ + diff --git a/TdGame/TdGame/gunner_tower.h b/TdGame/TdGame/gunner_tower.h new file mode 100644 index 0000000..c91504c --- /dev/null +++ b/TdGame/TdGame/gunner_tower.h @@ -0,0 +1,47 @@ +#ifndef _GUNNER_TOWER_H_ +#define _GUNNER_TOWER_H_ + +#include "tower.h" +#include "resources_manager.h" + + +class GunnerTower : public Tower +{ +public: + GunnerTower() + { + static SDL_Texture* tex_gunner = ResourcesManager::instance() + ->get_texture_pool().find(ResID::Tex_Gunner)->second; + + static const std::vector idx_list_idle_up = { 4, 5 }; + static const std::vector idx_list_idle_down = { 0, 1 }; + static const std::vector idx_list_idle_left = { 12, 13 }; + static const std::vector idx_list_idle_right = { 8, 9 }; + static const std::vector idx_list_fire_up = { 20, 21, 22, 23 }; + static const std::vector idx_list_fire_down = { 16, 17, 18, 19 }; + static const std::vector idx_list_fire_left = { 28, 29, 30, 31 }; + static const std::vector idx_list_fire_right = { 24, 25, 26, 27 }; + + anim_idle_up.set_frame_data(tex_gunner, 4, 8, idx_list_idle_up); + anim_idle_down.set_frame_data(tex_gunner, 4, 8, idx_list_idle_down); + anim_idle_left.set_frame_data(tex_gunner, 4, 8, idx_list_idle_left); + anim_idle_right.set_frame_data(tex_gunner, 4, 8, idx_list_idle_right); + anim_fire_up.set_frame_data(tex_gunner, 4, 8, idx_list_fire_up); + anim_fire_down.set_frame_data(tex_gunner, 4, 8, idx_list_fire_down); + anim_fire_left.set_frame_data(tex_gunner, 4, 8, idx_list_fire_left); + anim_fire_right.set_frame_data(tex_gunner, 4, 8, idx_list_fire_right); + + size.x = 48, size.y = 48; + + tower_type = TowerType::Gunner; + + fire_speed = 6; + bullet_type = BulletType::Shell; + } + ~GunnerTower() = default; + +private: + +}; + +#endif // !_GUNNER_TOWER_H_ diff --git a/TdGame/TdGame/tower.h b/TdGame/TdGame/tower.h new file mode 100644 index 0000000..8c49537 --- /dev/null +++ b/TdGame/TdGame/tower.h @@ -0,0 +1,261 @@ +#ifndef _TOWER_H_ +#define _TOWER_H_ + +#include "vector2.h" +#include "animation.h" +#include "tower_type.h" +#include "bullet_manager.h" +#include "facing.h" +#include "enemy_manager.h" + +class Tower +{ +public: + Tower() + { + timer_fire.set_one_shot(true); + timer_fire.set_on_timeout( + [&]() + { + can_fire = true; + } + ); + + anim_idle_up.set_loop(true); + anim_idle_up.set_interval(0.2); + anim_idle_down.set_loop(true); + anim_idle_down.set_interval(0.2); + anim_idle_left.set_loop(true); + anim_idle_left.set_interval(0.2); + anim_idle_right.set_loop(true); + anim_idle_right.set_interval(0.2); + + + anim_fire_up.set_loop(true); + anim_fire_up.set_interval(0.2); + anim_fire_up.set_on_finished( + [&]() + { + update_idle_animation(); + }); + + anim_fire_down.set_loop(true); + anim_fire_down.set_interval(0.2); + anim_fire_down.set_on_finished( + [&]() + { + update_idle_animation(); + }); + + anim_fire_left.set_loop(true); + anim_fire_left.set_interval(0.2); + anim_fire_left.set_on_finished( + [&]() + { + update_idle_animation(); + }); + + anim_fire_right.set_loop(true); + anim_fire_right.set_interval(0.2); + anim_fire_right.set_on_finished( + [&]() + { + update_idle_animation(); + }); + } + ~Tower() = default; + + void set_position(const Vector2& position) + { + this->position = position; + } + + const Vector2& get_size() const + { + return size; + } + + const Vector2& get_position() const + { + return position; + } + + void on_update(double delta) + { + timer_fire.on_update(delta); + anim_current->on_update(delta); + + if (can_fire) on_fire(); + } + + void on_render(SDL_Renderer* renderer) + { + static SDL_Point point; + + point.x = (int)(position.x - size.x / 2); + point.y = (int)(position.y - size.y / 2); + + anim_current->on_render(renderer, point); + } + +//×ÓÀà¿É·ÃÎÊ +protected: + Vector2 size; + + Animation anim_idle_up; + Animation anim_idle_down; + Animation anim_idle_left; + Animation anim_idle_right; + Animation anim_fire_up; + Animation anim_fire_down; + Animation anim_fire_left; + Animation anim_fire_right; + + TowerType tower_type = TowerType::Archer; + + //×Óµ¯·ÉÐÐËÙ¶È + double fire_speed = 0; + BulletType bullet_type = BulletType::Arrow; + + +private: + Timer timer_fire; + Vector2 position; + bool can_fire = true; + Facing facing = Facing::Right; + Animation* anim_current = &anim_idle_right; + +private: + void update_idle_animation() + { + switch (facing) + { + case Left: + anim_current = &anim_idle_left; + break; + case Right: + anim_current = &anim_idle_right; + break; + case Up: + anim_current = &anim_idle_up; + break; + case Down: + anim_current = &anim_idle_down; + break; + } + } + + void update_fire_animation() + { + switch (facing) + { + case Left: + anim_current = &anim_fire_left; + break; + case Right: + anim_current = &anim_fire_right; + break; + case Up: + anim_current = &anim_fire_up; + break; + case Down: + anim_current = &anim_fire_down; + break; + } + } + + Enemy* find_target_enemy() + { + double process = -1; + double view_range = 0; + Enemy* enemy_target = nullptr; + + static ConfigManager* instance = ConfigManager::instance(); + + switch (tower_type) + { + case Archer: + view_range = instance->archer_template.view_range[instance->level_archer]; + break; + case Axeman: + view_range = instance->axeman_template.view_range[instance->level_axeman]; + break; + case Gunner: + view_range = instance->gunner_template.view_range[instance->level_gunner]; + break; + } + + EnemyManager::EnemyList& enemy_list = EnemyManager::instance()->get_enemy_list(); + + for (Enemy* enemy : enemy_list) + { + if ((enemy->get_position() - position).length() <= view_range * SIZE_TILE) + { + double new_process = enemy->get_route_process(); + if (new_process > process) + { + enemy_target = enemy; + process = new_process; + } + } + } + return enemy_target; + } + + void on_fire() + { + Enemy* target_enemy = find_target_enemy(); + + if (!target_enemy) return; + + can_fire = true; + static ConfigManager* instance = ConfigManager::instance(); + static const ResourcesManager::SoundPool& sound_pool = + ResourcesManager::instance()->get_sound_pool(); + + double interval = 0, damage = 0; + switch (tower_type) + { + case Archer: + interval = instance->archer_template.interval[instance->level_archer]; + damage = instance->archer_template.damage[instance->level_archer]; + switch (rand() % 2) + { + case 0: + Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_ArrowFire_1)->second, 0); + break; + case 1: + Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_ArrowFire_2)->second, 0); + break; + } + break; + case Axeman: + interval = instance->axeman_template.interval[instance->level_axeman]; + damage = instance->axeman_template.damage[instance->level_axeman]; + Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_AxeFire)->second, 0); + break; + case Gunner: + interval = instance->gunner_template.interval[instance->level_gunner]; + damage = instance->gunner_template.damage[instance->level_gunner]; + Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_ShellFire)->second, 0); + break; + } + + timer_fire.set_wait_time(interval); + timer_fire.restart(); + + Vector2 direction = target_enemy->get_position() - position; + BulletManager::instance()->fire_bullet(bullet_type, position, direction.normalize() * fire_speed * SIZE_TILE, damage); + + bool is_show_x_anim = abs(direction.x) - abs(direction.y); + if (is_show_x_anim) + facing = direction.x > 0 ? Facing::Right : Facing::Left; + else + facing = direction.y > 0 ? Facing::Down : Facing::Up; + + update_fire_animation(); + anim_current->reset(); + } +}; + +#endif // !_TOWER_H_ diff --git a/TdGame/TdGame/tower_type.h b/TdGame/TdGame/tower_type.h new file mode 100644 index 0000000..abf0508 --- /dev/null +++ b/TdGame/TdGame/tower_type.h @@ -0,0 +1,10 @@ +#ifndef _TOWER_TYPE_H_ +#define _TOWER_TYPE_H_ + +enum TowerType +{ + Archer, + Axeman, + Gunner +}; +#endif // !_TOWER_TYPE_H_