feat:子弹类的实现(基类,派生,管理器)

This commit is contained in:
sjm 2024-07-02 14:54:00 +08:00
parent 0c0e27ff32
commit 9adb54a5fb
8 changed files with 447 additions and 0 deletions

View File

@ -138,6 +138,11 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="animation.h" /> <ClInclude Include="animation.h" />
<ClInclude Include="arrow_bullet.h" />
<ClInclude Include="axe_bullet.h" />
<ClInclude Include="bullet.h" />
<ClInclude Include="bullet_manager.h" />
<ClInclude Include="bullet_type.h" />
<ClInclude Include="coin_manager.h" /> <ClInclude Include="coin_manager.h" />
<ClInclude Include="config_manager.h" /> <ClInclude Include="config_manager.h" />
<ClInclude Include="enemy.h" /> <ClInclude Include="enemy.h" />
@ -152,6 +157,7 @@
<ClInclude Include="map.h" /> <ClInclude Include="map.h" />
<ClInclude Include="resources_manager.h" /> <ClInclude Include="resources_manager.h" />
<ClInclude Include="route.h" /> <ClInclude Include="route.h" />
<ClInclude Include="shell_bullet.h" />
<ClInclude Include="skeleton_enemy.h" /> <ClInclude Include="skeleton_enemy.h" />
<ClInclude Include="slime_enemy.h" /> <ClInclude Include="slime_enemy.h" />
<ClInclude Include="tile.h" /> <ClInclude Include="tile.h" />

View File

@ -22,6 +22,9 @@
<Filter Include="源文件\cJSON"> <Filter Include="源文件\cJSON">
<UniqueIdentifier>{26456ec2-6d40-4a7f-9935-8248edc2bef2}</UniqueIdentifier> <UniqueIdentifier>{26456ec2-6d40-4a7f-9935-8248edc2bef2}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="头文件\bullet">
<UniqueIdentifier>{dbc74129-2d94-42c1-83b7-40d05f5b8aa2}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="main.cpp"> <ClCompile Include="main.cpp">
@ -98,5 +101,23 @@
<ClInclude Include="coin_manager.h"> <ClInclude Include="coin_manager.h">
<Filter>头文件\manager</Filter> <Filter>头文件\manager</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="bullet.h">
<Filter>头文件\bullet</Filter>
</ClInclude>
<ClInclude Include="arrow_bullet.h">
<Filter>头文件\bullet</Filter>
</ClInclude>
<ClInclude Include="axe_bullet.h">
<Filter>头文件\bullet</Filter>
</ClInclude>
<ClInclude Include="shell_bullet.h">
<Filter>头文件\bullet</Filter>
</ClInclude>
<ClInclude Include="bullet_manager.h">
<Filter>头文件\manager</Filter>
</ClInclude>
<ClInclude Include="bullet_type.h">
<Filter>头文件\bullet</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,52 @@
#ifndef _ARROW_BULLET_H_
#define _ARROW_BULLET_H_
#include "bullet.h"
#include "resources_manager.h"
class ArrowBullet:public Bullet
{
public:
ArrowBullet()
{
static SDL_Texture* tex_arrow = ResourcesManager::instance()
->get_texture_pool().find(ResID::Tex_BulletArrow)->second;
static const std::vector<int> idx_list = { 0, 1 };
animation.set_loop(true);
animation.set_interval(0.1);
animation.set_frame_data(tex_arrow, 2, 1, idx_list);
can_rotated = true;
size.x = 48, size.y = 48;
}
~ArrowBullet() = default;
void on_collide(Enemy* enemy) override
{
static const ResourcesManager::SoundPool& sound_pool
= ResourcesManager::instance()->get_sound_pool();
switch (rand() % 3)
{
case 0:
Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_ArrowHit_1)->second, 0);
break;
case 1:
Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_ArrowHit_2)->second, 0);
break;
case 2:
Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_ArrowHit_3)->second, 0);
break;
}
Bullet::on_collide(enemy);
}
};
#endif // !_ARROW_BULLET_H_

View File

@ -0,0 +1,52 @@
#ifndef _AXE_BULLET_H_
#define _AXE_BULLET_H_
#include "bullet.h"
#include "resources_manager.h"
class AxeBullet : public Bullet
{
public:
AxeBullet()
{
static SDL_Texture* tex_axe = ResourcesManager::instance()
->get_texture_pool().find(ResID::Tex_BulletAxe)->second;
static const std::vector<int> idx_list = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
animation.set_loop(true);
animation.set_interval(0.1);
animation.set_frame_data(tex_axe, 4, 2, idx_list);
size.x = 48, size.y = 48;
}
~AxeBullet() = default;
//ÅöײЧ¹û
void on_collide(Enemy* enemy) override
{
static const ResourcesManager::SoundPool& sound_pool
= ResourcesManager::instance()->get_sound_pool();
switch (rand() % 3)
{
case 0:
Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_AxeHit_1)->second, 0);
break;
case 1:
Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_AxeHit_2)->second, 0);
break;
case 2:
Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_AxeHit_3)->second, 0);
break;
}
enemy->slow_down();
Bullet::on_collide(enemy);
}
};
#endif // !_AXE_BULLET_H_

133
TdGame/TdGame/bullet.h Normal file
View File

@ -0,0 +1,133 @@
#ifndef _BULLET_H_
#define_BULLET_H_
#include "vector2.h"
#include "animation.h"
#include "config_manager.h"
#include"enemy.h"
class Bullet
{
public:
Bullet() = default;
~Bullet() = default;
void set_veloccity(const Vector2 velocity)
{
this->velocity = velocity;
if (can_rotated)
{
double radian = std::atan2(velocity.y, velocity.x);
angle_anim_rotated = radian * 180 / 3.14159265;
}
}
void set_position(const Vector2& size)
{
this->position = position;
}
void set_damage(double damage)
{
this->damage = damage;
}
const Vector2& get_size() const
{
return size;
}
const Vector2& get_position() const
{
return position;
}
double get_damage() const
{
return damage;
}
double get_damage_range() const
{
return damage_range;
}
bool can_collide() const
{
return is_collisional;
}
void disable_collide()
{
is_collisional = false;
}
void make_invalid()
{
is_valid = false;
is_collisional = false;
}
bool can_remove() const
{
return !is_valid;
}
//设置虚函数,允许在基类中定义该函数的行为,并允许派生类根据需要重写它
virtual void on_update(double delta)
{
animation.on_update(delta);
position += velocity * delta;
static const SDL_Rect& rect_map
= ConfigManager::instance()->rect_tile_map;
if (position.x - size.x / 2 <= rect_map.x
|| position.x + size.x / 2 >= rect_map.x + rect_map.w
|| position.y - size.y / 2 <= rect_map.y
|| position.y + size.y / 2 >= rect_map.y + rect_map.h)
{
is_valid = false;
}
}
virtual 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);
animation.on_render(renderer, point, angle_anim_rotated);
}
/*
param:
*/
virtual void on_collide(Enemy* enemy)
{
is_valid = false;
is_collisional = false;
}
protected:
Vector2 size;
Vector2 velocity;
Vector2 position;
Animation animation;
//是否可以旋转
bool can_rotated = false;
double damage = 0;
double damage_range = -1;
private:
bool is_valid = true;
//是否可检测碰撞
bool is_collisional = true;
double angle_anim_rotated = 0;
};
#endif // !_BULLET_H_

View File

@ -0,0 +1,91 @@
#ifndef _BULLET_MANAGER_H
#define _BULLET_MANAGER_H
#include "manager.h"
#include "bullet.h"
#include "bullet_type.h"
#include "arrow_bullet.h"
#include "axe_bullet.h"
#include "shell_bullet.h"
#include <vector>
class BulletManager : public Manager<BulletManager>
{
friend class Manager<BulletManager>;
public:
typedef std::vector<Bullet*> BulletList;
public:
void on_update(double delta)
{
for (Bullet* bullet : bullet_list)
bullet->on_update(delta);
bullet_list.erase(std::remove_if(
bullet_list.begin(), bullet_list.end(),
[](const Bullet* bullet)
{
bool deletable = bullet->can_remove();
if (deletable) delete bullet;
return deletable;
}), bullet_list.end());
}
void on_render(SDL_Renderer* renderer)
{
for (Bullet* bullet : bullet_list)
bullet->on_render(renderer);
}
//用于外部获取子弹列表,检测碰撞之类的逻辑
BulletList& get_bullet_list()
{
return bullet_list;
}
//用于外部生成子弹
void fire_bullet(BulletType type,const Vector2& position,const Vector2& velocity,double damage)
{
Bullet* bullet = nullptr;
switch (type)
{
case Arrow:
bullet = new ArrowBullet();
break;
case Axe:
bullet = new AxeBullet();
break;
case Shell:
bullet = new ShellBullet();
break;
default:
bullet = new ArrowBullet();
break;
}
bullet->set_position(position);
bullet->set_damage(damage);
bullet->set_veloccity(velocity);
bullet_list.push_back(bullet);
}
protected:
BulletManager() = default;
~BulletManager()
{
for (Bullet* bullet : bullet_list)
delete bullet;
}
private:
BulletList bullet_list;
};
#endif // !_BULLET_MANAGER_H

View File

@ -0,0 +1,12 @@
#pragma once
#ifndef _BULLET_TYPE_H_
#define _BULLET_TYPE_H_
enum BulletType
{
Arrow,
Axe,
Shell
};
#endif

View File

@ -0,0 +1,80 @@
#ifndef _SHELL_BULLET_H
#define _SHELL_BULLET_H
#include "bullet.h"
#include "resources_manager.h"
class ShellBullet : public Bullet
{
public:
ShellBullet()
{
static SDL_Texture* tex_shell = ResourcesManager::instance()
->get_texture_pool().find(ResID::Tex_BulletShell)->second;
static SDL_Texture* tex_explode = ResourcesManager::instance()
->get_texture_pool().find(ResID::Tex_EffectExplode)->second;
static const std::vector<int> idx_list = { 0, 1};
static const std::vector<int> idx_explode_list = { 0, 1, 2, 3, 4};
animation.set_loop(true);
animation.set_interval(0.1);
animation.set_frame_data(tex_shell, 2, 1, idx_list);
animation_explode.set_loop(true);
animation_explode.set_interval(0.1);
animation_explode.set_frame_data(tex_shell, 5, 1, idx_explode_list);
animation_explode.set_on_finished(
[&]()
{
make_invalid();
});
damage_range = 96;
size.x = 48, size.y = 48;
}
~ShellBullet() = default;
void on_update(double delta) override
{
if (can_collide)
{
Bullet::on_update(delta);
return;
}
animation_explode.on_update(delta);
}
void on_render(SDL_Renderer* renderer) override
{
if (can_collide)
{
Bullet::on_render(renderer);
return;
}
static SDL_Point point;
point.x = (int)(position.x - 96 / 2);
point.y = (int)(position.y - 96 / 2);
animation_explode.on_render(renderer, point);
}
//碰撞效果
void on_collide(Enemy* enemy) override
{
static const ResourcesManager::SoundPool& sound_pool
= ResourcesManager::instance()->get_sound_pool();
Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_ShellHit)->second, 0);
//Bullet::on_collide(enemy); 爆炸后只禁用碰撞
disable_collide();
}
private:
Animation animation_explode;
};
#endif // !_SHELL_BULLET_H