feat:防御塔子类实现

This commit is contained in:
sjm 2024-07-02 21:48:12 +08:00
parent 9adb54a5fb
commit 5fb76ce452
10 changed files with 457 additions and 1 deletions

View File

@ -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" />

View File

@ -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>

View 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_

View 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_

View File

@ -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;

View File

@ -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
View File

@ -0,0 +1,12 @@
#ifndef _FACING_H_
#define _FACING_H_
enum Facing
{
Left,
Right,
Up,
Down
};
#endif // !_FACING_H_

View 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
View 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_

View File

@ -0,0 +1,10 @@
#ifndef _TOWER_TYPE_H_
#define _TOWER_TYPE_H_
enum TowerType
{
Archer,
Axeman,
Gunner
};
#endif // !_TOWER_TYPE_H_