diff --git a/TdGame/TdGame/TdGame.vcxproj b/TdGame/TdGame/TdGame.vcxproj
index 4b8785a..8f1d853 100644
--- a/TdGame/TdGame/TdGame.vcxproj
+++ b/TdGame/TdGame/TdGame.vcxproj
@@ -138,6 +138,11 @@
+
+
+
+
+
@@ -152,6 +157,7 @@
+
diff --git a/TdGame/TdGame/TdGame.vcxproj.filters b/TdGame/TdGame/TdGame.vcxproj.filters
index 059e962..0d784fb 100644
--- a/TdGame/TdGame/TdGame.vcxproj.filters
+++ b/TdGame/TdGame/TdGame.vcxproj.filters
@@ -22,6 +22,9 @@
{26456ec2-6d40-4a7f-9935-8248edc2bef2}
+
+ {dbc74129-2d94-42c1-83b7-40d05f5b8aa2}
+
@@ -98,5 +101,23 @@
头文件\manager
+
+ 头文件\bullet
+
+
+ 头文件\bullet
+
+
+ 头文件\bullet
+
+
+ 头文件\bullet
+
+
+ 头文件\manager
+
+
+ 头文件\bullet
+
\ No newline at end of file
diff --git a/TdGame/TdGame/arrow_bullet.h b/TdGame/TdGame/arrow_bullet.h
new file mode 100644
index 0000000..3744c88
--- /dev/null
+++ b/TdGame/TdGame/arrow_bullet.h
@@ -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 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_
diff --git a/TdGame/TdGame/axe_bullet.h b/TdGame/TdGame/axe_bullet.h
new file mode 100644
index 0000000..c97c880
--- /dev/null
+++ b/TdGame/TdGame/axe_bullet.h
@@ -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 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_
diff --git a/TdGame/TdGame/bullet.h b/TdGame/TdGame/bullet.h
new file mode 100644
index 0000000..b81ea0f
--- /dev/null
+++ b/TdGame/TdGame/bullet.h
@@ -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_
\ No newline at end of file
diff --git a/TdGame/TdGame/bullet_manager.h b/TdGame/TdGame/bullet_manager.h
new file mode 100644
index 0000000..0622574
--- /dev/null
+++ b/TdGame/TdGame/bullet_manager.h
@@ -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
+
+
+class BulletManager : public Manager
+{
+ friend class Manager;
+
+public:
+ typedef std::vector 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
+
diff --git a/TdGame/TdGame/bullet_type.h b/TdGame/TdGame/bullet_type.h
new file mode 100644
index 0000000..ef05a2a
--- /dev/null
+++ b/TdGame/TdGame/bullet_type.h
@@ -0,0 +1,12 @@
+#pragma once
+#ifndef _BULLET_TYPE_H_
+#define _BULLET_TYPE_H_
+
+enum BulletType
+{
+ Arrow,
+ Axe,
+ Shell
+};
+
+#endif
diff --git a/TdGame/TdGame/shell_bullet.h b/TdGame/TdGame/shell_bullet.h
new file mode 100644
index 0000000..4ba979f
--- /dev/null
+++ b/TdGame/TdGame/shell_bullet.h
@@ -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 idx_list = { 0, 1};
+ static const std::vector 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