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_