feat:防御塔子类实现
This commit is contained in:
parent
9adb54a5fb
commit
5fb76ce452
@ -138,7 +138,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="animation.h" />
|
||||
<ClInclude Include="archer_tower.h" />
|
||||
<ClInclude Include="arrow_bullet.h" />
|
||||
<ClInclude Include="axeman_tower.h" />
|
||||
<ClInclude Include="axe_bullet.h" />
|
||||
<ClInclude Include="bullet.h" />
|
||||
<ClInclude Include="bullet_manager.h" />
|
||||
@ -148,9 +150,11 @@
|
||||
<ClInclude Include="enemy.h" />
|
||||
<ClInclude Include="enemy_manager.h" />
|
||||
<ClInclude Include="enemy_type.h" />
|
||||
<ClInclude Include="facing.h" />
|
||||
<ClInclude Include="game_manager.h" />
|
||||
<ClInclude Include="goblin_enemy.h" />
|
||||
<ClInclude Include="goblin_priest_enemy.h" />
|
||||
<ClInclude Include="gunner_tower.h" />
|
||||
<ClInclude Include="home_manager.h" />
|
||||
<ClInclude Include="king_slime_enemy.h" />
|
||||
<ClInclude Include="manager.h" />
|
||||
@ -162,6 +166,8 @@
|
||||
<ClInclude Include="slime_enemy.h" />
|
||||
<ClInclude Include="tile.h" />
|
||||
<ClInclude Include="timer.h" />
|
||||
<ClInclude Include="tower.h" />
|
||||
<ClInclude Include="tower_type.h" />
|
||||
<ClInclude Include="vector2.h" />
|
||||
<ClInclude Include="wave.h" />
|
||||
<ClInclude Include="wave_manager.h" />
|
||||
|
@ -25,6 +25,9 @@
|
||||
<Filter Include="头文件\bullet">
|
||||
<UniqueIdentifier>{dbc74129-2d94-42c1-83b7-40d05f5b8aa2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="头文件\tower">
|
||||
<UniqueIdentifier>{934287b6-3a61-4491-8b40-951a2d797c87}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
@ -119,5 +122,23 @@
|
||||
<ClInclude Include="bullet_type.h">
|
||||
<Filter>头文件\bullet</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tower.h">
|
||||
<Filter>头文件\tower</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tower_type.h">
|
||||
<Filter>头文件\tower</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="facing.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="archer_tower.h">
|
||||
<Filter>头文件\tower</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="axeman_tower.h">
|
||||
<Filter>头文件\tower</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gunner_tower.h">
|
||||
<Filter>头文件\tower</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
47
TdGame/TdGame/archer_tower.h
Normal file
47
TdGame/TdGame/archer_tower.h
Normal file
@ -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<int> idx_list_idle_up = { 3, 4 };
|
||||
static const std::vector<int> idx_list_idle_down = { 0, 1 };
|
||||
static const std::vector<int> idx_list_idle_left = { 6, 7 };
|
||||
static const std::vector<int> idx_list_idle_right = { 9, 10 };
|
||||
static const std::vector<int> idx_list_fire_up = { 15, 16, 17 };
|
||||
static const std::vector<int> idx_list_fire_down = { 12, 13, 14 };
|
||||
static const std::vector<int> idx_list_fire_left = {18, 19, 20};
|
||||
static const std::vector<int> 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_
|
46
TdGame/TdGame/axeman_tower.h
Normal file
46
TdGame/TdGame/axeman_tower.h
Normal file
@ -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<int> idx_list_idle_up = { 3, 4 };
|
||||
static const std::vector<int> idx_list_idle_down = { 0, 1 };
|
||||
static const std::vector<int> idx_list_idle_left = { 9, 10 };
|
||||
static const std::vector<int> idx_list_idle_right = { 6, 7 };
|
||||
static const std::vector<int> idx_list_fire_up = { 15, 16, 17 };
|
||||
static const std::vector<int> idx_list_fire_down = { 12, 13, 14 };
|
||||
static const std::vector<int> idx_list_fire_left = { 21, 22, 23 };
|
||||
static const std::vector<int> 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_
|
@ -110,6 +110,7 @@ public:
|
||||
is_valid = false;
|
||||
is_collisional = false;
|
||||
}
|
||||
|
||||
protected:
|
||||
Vector2 size;
|
||||
Vector2 velocity;
|
||||
|
@ -123,6 +123,11 @@ public:
|
||||
return enemy_list.empty();
|
||||
}
|
||||
|
||||
EnemyList& get_enemy_list()
|
||||
{
|
||||
return enemy_list;
|
||||
}
|
||||
|
||||
protected:
|
||||
EnemyManager() = default;
|
||||
|
||||
|
12
TdGame/TdGame/facing.h
Normal file
12
TdGame/TdGame/facing.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _FACING_H_
|
||||
#define _FACING_H_
|
||||
|
||||
enum Facing
|
||||
{
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down
|
||||
};
|
||||
#endif // !_FACING_H_
|
||||
|
47
TdGame/TdGame/gunner_tower.h
Normal file
47
TdGame/TdGame/gunner_tower.h
Normal file
@ -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<int> idx_list_idle_up = { 4, 5 };
|
||||
static const std::vector<int> idx_list_idle_down = { 0, 1 };
|
||||
static const std::vector<int> idx_list_idle_left = { 12, 13 };
|
||||
static const std::vector<int> idx_list_idle_right = { 8, 9 };
|
||||
static const std::vector<int> idx_list_fire_up = { 20, 21, 22, 23 };
|
||||
static const std::vector<int> idx_list_fire_down = { 16, 17, 18, 19 };
|
||||
static const std::vector<int> idx_list_fire_left = { 28, 29, 30, 31 };
|
||||
static const std::vector<int> 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_
|
261
TdGame/TdGame/tower.h
Normal file
261
TdGame/TdGame/tower.h
Normal file
@ -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_
|
10
TdGame/TdGame/tower_type.h
Normal file
10
TdGame/TdGame/tower_type.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _TOWER_TYPE_H_
|
||||
#define _TOWER_TYPE_H_
|
||||
|
||||
enum TowerType
|
||||
{
|
||||
Archer,
|
||||
Axeman,
|
||||
Gunner
|
||||
};
|
||||
#endif // !_TOWER_TYPE_H_
|
Loading…
Reference in New Issue
Block a user