diff --git a/TdGame/TdGame/TdGame.vcxproj b/TdGame/TdGame/TdGame.vcxproj
index 234ca3b..308a1af 100644
--- a/TdGame/TdGame/TdGame.vcxproj
+++ b/TdGame/TdGame/TdGame.vcxproj
@@ -146,6 +146,7 @@
+
@@ -159,14 +160,17 @@
+
+
+
diff --git a/TdGame/TdGame/TdGame.vcxproj.filters b/TdGame/TdGame/TdGame.vcxproj.filters
index 30e52f7..f7cdc82 100644
--- a/TdGame/TdGame/TdGame.vcxproj.filters
+++ b/TdGame/TdGame/TdGame.vcxproj.filters
@@ -28,6 +28,12 @@
{934287b6-3a61-4491-8b40-951a2d797c87}
+
+ {897a51c7-844c-4f07-84bc-aac1ebca8e19}
+
+
+ {eb558f9c-e602-498f-a18e-eb239eea8991}
+
@@ -140,5 +146,17 @@
头文件\tower
+
+ 头文件\tower
+
+
+ 头文件
+
+
+ 头文件\ui
+
+
+ 头文件\ui\panel
+
\ No newline at end of file
diff --git a/TdGame/TdGame/animation.h b/TdGame/TdGame/animation.h
index ad0783f..92368c9 100644
--- a/TdGame/TdGame/animation.h
+++ b/TdGame/TdGame/animation.h
@@ -92,7 +92,7 @@ public:
rect_dst.x = pos_dst.x, rect_dst.y = pos_dst.y;
rect_dst.w = width_frame, rect_dst.h = height_frame;
- //äÖȾÆ÷£¬ÎÆÀí£¬²Ã¼ô¾ØÐΣ¬Ä¿±ê¾ØÐΣ¬½Ç¶È£¬ÐýתÖÐÐĵã(ĬÈÏ1/2)£¬·×ª¡£ ÎÆÀí»æÖÆ
+ //äÖȾÆ÷£¬ÎÆÀí£¬²Ã¼ô¾ØÐΣ¬Ä¿±ê¾ØÐΣ¬½Ç¶È£¬ÐýתÖÐÐĵã(ĬÈÏ1/2)£¬·×ª¡£
SDL_RenderCopyEx(renderer, texture, &rect_src_list[idx_frame], &rect_dst, angle, nullptr, SDL_RendererFlip::SDL_FLIP_NONE);
}
private:
diff --git a/TdGame/TdGame/bullet.h b/TdGame/TdGame/bullet.h
index 78a27c3..326333f 100644
--- a/TdGame/TdGame/bullet.h
+++ b/TdGame/TdGame/bullet.h
@@ -12,7 +12,7 @@ public:
Bullet() = default;
~Bullet() = default;
- void set_veloccity(const Vector2 velocity)
+ void set_veloccity(const Vector2& velocity)
{
this->velocity = velocity;
@@ -23,7 +23,7 @@ public:
}
}
- void set_position(const Vector2& size)
+ void set_position(const Vector2& position)
{
this->position = position;
}
diff --git a/TdGame/TdGame/coin_manager.h b/TdGame/TdGame/coin_manager.h
index a01d996..fa8aa88 100644
--- a/TdGame/TdGame/coin_manager.h
+++ b/TdGame/TdGame/coin_manager.h
@@ -2,11 +2,17 @@
#ifndef _COIN_MANAGER_H_
#define _COIN_MANAGER_H_
+#include "coin_prop.h"
#include"manager.h"
+#include "config_manager.h"
class CoinManager:public Manager
{
friend class Manager;
+
+public:
+ typedef std::vector CoinPropList;
+
public:
void increase_coin(double val)
{
@@ -20,19 +26,59 @@ public:
if (num_coin < 0)
num_coin = 0;
}
+
+ void on_update(double delta)
+ {
+ for (CoinProp* coin_prop : coin_prop_list)
+ coin_prop->on_update(delta);
+ coin_prop_list.erase(std::remove_if(coin_prop_list.begin(), coin_prop_list.end(), [](CoinProp* coin_prop)
+ {
+ bool deletable = coin_prop->can_remove();
+ if (deletable) delete coin_prop;
+ return deletable;
+ }),coin_prop_list.end());
+ }
+
+ void on_render(SDL_Renderer* renderer)
+ {
+ for (CoinProp* coin_prop : coin_prop_list)
+ coin_prop->on_render(renderer);
+ }
+
+ double get_current_coin_num() const
+ {
+ return num_coin;
+ }
+
+ CoinPropList& get_coin_prop_list()
+ {
+ return coin_prop_list;
+ }
+
+ void spawn_coin_prop(const Vector2& position)
+ {
+ CoinProp* coin_prop = new CoinProp();
+ coin_prop->set_position(position);
+
+ coin_prop_list.push_back(coin_prop);
+ }
protected:
CoinManager()
{
num_coin = ConfigManager::instance()->num_initial_coin;
+
}
~CoinManager()
{
-
+ for (CoinProp* coin_prop : coin_prop_list)
+ delete coin_prop;
}
private:
- double num_coin = 0;
+ double num_coin = 100;
+
+ CoinPropList coin_prop_list;
};
diff --git a/TdGame/TdGame/coin_prop.h b/TdGame/TdGame/coin_prop.h
new file mode 100644
index 0000000..cee13df
--- /dev/null
+++ b/TdGame/TdGame/coin_prop.h
@@ -0,0 +1,108 @@
+#ifndef _COIN_PROP_H_
+#define _COIN_PROP_H_
+
+#include "tile.h"
+#include "vector2.h"
+#include "timer.h"
+#include "resources_manager.h"
+
+#include
+
+class CoinProp
+{
+public:
+ CoinProp()
+ {
+ timer_jump.set_one_shot(true);
+ timer_jump.set_wait_time(interval_jump);
+ timer_jump.set_on_timeout(
+ [&]()
+ {
+ is_jumping = false;
+ });
+
+ timer_disappear.set_one_shot(true);
+ timer_disappear.set_wait_time(interval_disappear);
+ timer_disappear.set_on_timeout(
+ [&]()
+ {
+ is_valid = false;
+ });
+
+ velocity.x = (rand() % 2 ? 1 : -1) * 2 * SIZE_TILE;
+ velocity.y = -3 * SIZE_TILE;
+ }
+
+ ~CoinProp() = default;
+
+ void set_position(const Vector2& position)
+ {
+ this->position = position;
+ }
+
+ const Vector2 get_position() const
+ {
+ return position;
+ }
+
+ const Vector2& get_size() const
+ {
+ return size;
+ }
+
+ void make_invalid()
+ {
+ is_valid = false;
+ }
+
+ bool can_remove()
+ {
+ return !is_valid;
+ }
+
+ void on_update(double delta)
+ {
+ timer_jump.on_update(delta);
+ timer_disappear.on_update(delta);
+
+ if (is_jumping)
+ {
+ velocity.y += gravity * delta;
+ }
+ else
+ {
+ velocity.x = 0;
+ velocity.y = sin(SDL_GetTicks64() / 1000 * 4) * 30;
+ }
+ position += velocity * delta;
+ }
+
+ void on_render(SDL_Renderer* renderer)
+ {
+ static SDL_Rect rect = { 0, 0, (int)size.y, (int)size.y };
+ static SDL_Texture* tex_coin = ResourcesManager::instance()
+ ->get_texture_pool().find(ResID::Tex_Coin)->second;
+
+ rect.x = (int)(position.x - size.x) / 2;
+ rect.y = (int)(position.y - size.y) / 2;
+
+ SDL_RenderCopy(renderer, tex_coin, nullptr, &rect);
+ }
+private:
+ Vector2 position;
+ Vector2 velocity;
+
+ Timer timer_jump;
+ Timer timer_disappear;
+
+ bool is_valid = true;
+ bool is_jumping = true;
+
+ double gravity = 490;
+ double interval_jump = 0.75;
+ Vector2 size = { 16, 16 };
+ double interval_disappear = 10;
+};
+
+
+#endif // !_COIN_PROP_H_
diff --git a/TdGame/TdGame/enemy_manager.h b/TdGame/TdGame/enemy_manager.h
index adc4ba3..e31a80a 100644
--- a/TdGame/TdGame/enemy_manager.h
+++ b/TdGame/TdGame/enemy_manager.h
@@ -11,6 +11,8 @@
#include "skeleton_enemy.h"
#include "goblin_enemy.h"
#include "goblin_priest_enemy.h"
+#include "bullet_manager.h"
+#include "coin_manager.h"
#include
#include
@@ -173,7 +175,52 @@ private:
//×Óµ¯Åöײ¼ì²â
void process_bullet_collision()
{
+ static BulletManager::BulletList& bullet_list
+ = BulletManager::instance()->get_bullet_list();
+ for (Enemy* enemy : enemy_list)
+ {
+ if (enemy->can_remove()) continue;
+
+ const Vector2& size_enemy = enemy->get_size();
+ const Vector2& pos_enemy = enemy->get_position();
+
+ for (Bullet* bullet : bullet_list)
+ {
+ if (!bullet->can_collide()) continue;
+
+ const Vector2& pos_bullet = bullet->get_position();
+
+ if (pos_bullet.x >= pos_enemy.x - size_enemy.x / 2
+ && pos_bullet.y >= pos_enemy.y - size_enemy.y / 2
+ && pos_bullet.x <= pos_enemy.x + size_enemy.x / 2
+ && pos_bullet.y <= pos_enemy.y + size_enemy.y / 2)
+ {
+ double damage = bullet->get_damage();
+ double damage_range = bullet->get_damage_range();
+ if (damage_range < 0)
+ {
+ enemy->decrease_hp(damage);
+ if (enemy->can_remove())
+ try_spawn_coin_prop(pos_enemy, enemy->get_reward_ratio());
+ }
+ else
+ {
+ for (Enemy* target_enemy : enemy_list)
+ {
+ const Vector2& pos_target_enemy = target_enemy->get_position();
+ if ((pos_target_enemy - pos_bullet).length() <= damage_range)
+ {
+ target_enemy->decrease_hp(damage);
+ if(target_enemy->can_remove())
+ try_spawn_coin_prop(pos_target_enemy, target_enemy->get_reward_ratio());
+ }
+ }
+ }
+ bullet->on_collide(enemy);
+ }
+ }
+ }
}
//ÒƳýÎÞЧµÐÈË
void remove_invalid_enemy()
@@ -186,6 +233,13 @@ private:
return deletable;
}), enemy_list.end());
}
+
+ void try_spawn_coin_prop(const Vector2& position, double ratio)
+ {
+ static CoinManager* instance = CoinManager::instance();
+ if ((double)(rand() % 100) / 100 <= ratio)
+ instance->spawn_coin_prop(position);
+ }
};
#endif // !_ENEMY_MANAGER_H
diff --git a/TdGame/TdGame/game_manager.h b/TdGame/TdGame/game_manager.h
index ea40b04..d98888b 100644
--- a/TdGame/TdGame/game_manager.h
+++ b/TdGame/TdGame/game_manager.h
@@ -7,6 +7,9 @@
#include "resources_manager.h"
#include "enemy_manager.h"
#include "wave_manager.h"
+#include "tower_manager.h"
+#include "bullet_manager.h"
+#include "status_bar.h"
#include
#include
@@ -22,6 +25,8 @@ class GameManager : public Manager
public:
int run(int argc,char** argv)
{
+ TowerManager::instance()->place_tower(TowerType::Archer, { 5,0 });
+
Uint64 last_counter = SDL_GetPerformanceCounter();
const Uint64 counter_freq = SDL_GetPerformanceFrequency();
@@ -83,6 +88,8 @@ protected:
init_assert(generate_tile_map_texture(),u8"Éú³ÉÍßƬµØͼÀàÐÍʧ°Ü£¡");
+ status_bar.set_position(15, 15);
+
}
~GameManager()
@@ -100,6 +107,8 @@ private:
SDL_Event event;
bool is_quit = false;
+ StatusBar status_bar;
+
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
@@ -125,9 +134,11 @@ private:
if (!instance->is_game_over)
{
+ status_bar.on_update(renderer);
WaveManager::instance()->on_update(delta);
EnemyManager::instance()->on_update(delta);
-
+ BulletManager::instance()->on_update(delta);
+ TowerManager::instance()->on_update(delta);
return;
}
}
@@ -138,7 +149,15 @@ private:
static SDL_Rect& rect_dst = instance->rect_tile_map;
SDL_RenderCopy(renderer, tex_tile_map, nullptr, &rect_dst);
+
EnemyManager::instance()->on_render(renderer);
+ BulletManager::instance()->on_render(renderer);
+ TowerManager::instance()->on_render(renderer);
+
+ if (!instance->is_game_over)
+ {
+ status_bar.on_render(renderer);
+ }
}
bool generate_tile_map_texture()
diff --git a/TdGame/TdGame/home_manager.h b/TdGame/TdGame/home_manager.h
index 4d789aa..0278c8a 100644
--- a/TdGame/TdGame/home_manager.h
+++ b/TdGame/TdGame/home_manager.h
@@ -12,7 +12,7 @@ class HomeManager:public Manager
friend class Manager;
public:
- double get_current_hp()
+ double get_current_hp_num()
{
return num_hp;
}
diff --git a/TdGame/TdGame/panel.h b/TdGame/TdGame/panel.h
new file mode 100644
index 0000000..c62dae0
--- /dev/null
+++ b/TdGame/TdGame/panel.h
@@ -0,0 +1,240 @@
+#ifndef _PANEL_H_
+#define _PANEL_H_
+
+#include "tile.h"
+#include "resources_manager.h"
+
+
+#include
+#include
+
+class Panel
+{
+public:
+ Panel()
+ {
+ tex_select_cursor = ResourcesManager::instance()->get_texture_pool().find(ResID::Tex_UISelectCursor)->second;
+ }
+ ~Panel()
+ {
+ SDL_DestroyTexture(tex_text_background);
+ SDL_DestroyTexture(tex_text_foreground);
+ }
+
+ void show()
+ {
+ visible = true;
+ }
+
+ void set_idx_tile(const SDL_Point& idx)
+ {
+ idx_tile_selected = idx;
+ }
+
+ void set_center_position(const SDL_Point& pos)
+ {
+ center_pos = pos;
+ }
+
+ void on_input(const SDL_Event& event)
+ {
+ if (!visible) return;
+
+ switch (event.type)
+ {
+ case SDL_MOUSEMOTION:
+ {
+ SDL_Point pos_cursor = { event.motion.x,event.motion.y };
+ SDL_Rect rect_target = { 0, 0, size_button, size_button };
+
+ rect_target.x = center_pos.x - width / 2 + offset_top.x;
+ rect_target.y = center_pos.y - height / 2 + offset_top.y;
+ if (SDL_PointInRect(&pos_cursor, &rect_target))
+ {
+ hovered_target = HoveredTarget::Top;
+ return;
+ }
+
+ rect_target.x = center_pos.x - width / 2 + offset_left.x;
+ rect_target.y = center_pos.y - height / 2 + offset_left.y;
+ if (SDL_PointInRect(&pos_cursor, &rect_target))
+ {
+ hovered_target = HoveredTarget::Left;
+ return;
+ }
+
+ rect_target.x = center_pos.x - width / 2 + offset_right.x;
+ rect_target.y = center_pos.y - height / 2 + offset_right.y;
+ if (SDL_PointInRect(&pos_cursor, &rect_target))
+ {
+ hovered_target = HoveredTarget::Right;
+ return;
+ }
+
+ hovered_target = HoveredTarget::None;
+ }
+ break;
+
+ case SDL_MOUSEBUTTONUP:
+ {
+ switch (hovered_target)
+ {
+ case Panel::HoveredTarget::Top:
+ on_click_top_area;
+ break;
+ case Panel::HoveredTarget::Left:
+ on_click_left_area;
+ break;
+ case Panel::HoveredTarget::Right:
+ on_click_right_area;
+ break;
+ }
+
+ visible = false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ virtual void on_update(SDL_Renderer* renderer)
+ {
+ static TTF_Font* font = ResourcesManager::instance()->get_font_pool().find(ResID::Font_Main)->second;
+
+ if (hovered_target == HoveredTarget::None)
+ return;
+
+ int val = 0;
+ switch (hovered_target)
+ {
+ case Panel::HoveredTarget::Top:
+ val = val_top;
+ break;
+ case Panel::HoveredTarget::Left:
+ val = val_left;
+ break;
+ case Panel::HoveredTarget::Right:
+ val = val_right;
+ break;
+ default:
+ break;
+ }
+
+ SDL_DestroyTexture(tex_text_background);
+ tex_text_background = nullptr;
+ SDL_DestroyTexture(tex_text_foreground);
+ tex_text_foreground = nullptr;
+
+ std::string str_val = val < 0 ? "MAX" : std::to_string(val);
+
+ SDL_Surface* suf_text_background = TTF_RenderText_Blended(font, str_val.c_str(), color_text_background);
+ SDL_Surface* suf_text_foreground = TTF_RenderText_Blended(font, str_val.c_str(), color_text_foreground);
+
+ width_text = suf_text_background->w; height_text = suf_text_background->h;
+ tex_text_background = SDL_CreateTextureFromSurface(renderer, suf_text_background);
+ tex_text_foreground = SDL_CreateTextureFromSurface(renderer, suf_text_foreground);
+
+ SDL_FreeSurface(suf_text_background);
+ SDL_FreeSurface(suf_text_foreground);
+ }
+
+ virtual void on_render(SDL_Renderer* renderer)
+ {
+ if (!visible) return;
+
+ SDL_Rect rect_dst_cursor =
+ {
+ center_pos.x = SIZE_TILE / 2,
+ center_pos.y = SIZE_TILE / 2,
+ SIZE_TILE, SIZE_TILE
+ };
+
+ SDL_RenderCopy(renderer, tex_select_cursor, nullptr, &rect_dst_cursor);
+
+ SDL_Rect rect_dst_panel =
+ {
+ center_pos.x - width / 2,
+ center_pos.y - height / 2,
+ width,height
+ };
+
+ SDL_Texture* tex_panel = nullptr;
+ switch (hovered_target)
+ {
+ case Panel::HoveredTarget::None:
+ tex_panel = tex_idle;
+ break;
+ case Panel::HoveredTarget::Top:
+ tex_panel = tex_hovered_top;
+ break;
+ case Panel::HoveredTarget::Left:
+ tex_panel = tex_hovered_left;
+ break;
+ case Panel::HoveredTarget::Right:
+ tex_panel = tex_hovered_right;
+ break;
+ }
+
+ SDL_RenderCopy(renderer, tex_panel, nullptr, &rect_dst_panel);
+
+ if (hovered_target == HoveredTarget::None) return;
+
+ SDL_Rect rect_dst_text;
+
+ rect_dst_text.x = center_pos.x - width_text / 2 + offset_shadow.x;
+ rect_dst_text.y = center_pos.y + height / 2 + offset_shadow.y;
+ rect_dst_text.w = width_text; rect_dst_text.h = height_text;
+
+ SDL_RenderCopy(renderer, tex_text_background, nullptr, &rect_dst_text);
+
+ rect_dst_text.x -= offset_shadow.x;
+ rect_dst_text.y -= offset_shadow.y;
+ SDL_RenderCopy(renderer, tex_text_foreground, nullptr, &rect_dst_text);
+ }
+
+
+protected:
+ enum class HoveredTarget
+ {
+ None,
+ Top,
+ Left,
+ Right
+ };
+
+protected:
+ bool visible = true;
+ SDL_Point idx_tile_selected;
+ SDL_Point center_pos = { 0 };
+ SDL_Texture* tex_idle = nullptr;
+ SDL_Texture* tex_hovered_top = nullptr;
+ SDL_Texture* tex_hovered_left = nullptr;
+ SDL_Texture* tex_hovered_right = nullptr;
+ SDL_Texture* tex_select_cursor = nullptr;
+ int val_top = 0, val_left = 0, val_right = 0;
+ HoveredTarget hovered_target = HoveredTarget::None;
+
+protected:
+ virtual void on_click_top_area() = 0;
+ virtual void on_click_left_area() = 0;
+ virtual void on_click_right_area() = 0;
+
+
+private:
+ const int size_button = 48;
+ const int width = 144, height = 144;
+ const SDL_Point offset_top = { 48,6 };
+ const SDL_Point offset_left = { 8,80 };
+ const SDL_Point offset_right = { 90,80 };
+ const SDL_Point offset_shadow = { 3,3 };
+ const SDL_Color color_text_background = { 175,175,175,255 };
+ const SDL_Color color_text_foreground = { 255,255,255,255 };
+
+ int width_text = 0, height_text = 0;
+ SDL_Texture* tex_text_background = nullptr;
+ SDL_Texture* tex_text_foreground = nullptr;
+};
+
+
+#endif // !_PANEL_H_
diff --git a/TdGame/TdGame/shell_bullet.h b/TdGame/TdGame/shell_bullet.h
index 4ba979f..3218cde 100644
--- a/TdGame/TdGame/shell_bullet.h
+++ b/TdGame/TdGame/shell_bullet.h
@@ -38,7 +38,7 @@ public:
void on_update(double delta) override
{
- if (can_collide)
+ if (can_collide())
{
Bullet::on_update(delta);
return;
@@ -48,7 +48,7 @@ public:
void on_render(SDL_Renderer* renderer) override
{
- if (can_collide)
+ if (can_collide())
{
Bullet::on_render(renderer);
return;
diff --git a/TdGame/TdGame/status_bar.h b/TdGame/TdGame/status_bar.h
new file mode 100644
index 0000000..1bf24d9
--- /dev/null
+++ b/TdGame/TdGame/status_bar.h
@@ -0,0 +1,118 @@
+#ifndef _STATUES_BAR_H_
+#define _STATUES_BAR_H_
+
+
+#include "coin_manager.h"
+#include "home_manager.h"
+#include "resources_manager.h"
+
+#include
+#include
+#include "SDL.h"
+
+class StatusBar
+{
+public:
+ StatusBar() = default;
+ ~StatusBar() = default;
+
+ void set_position(int x,int y)
+ {
+ position.x = x, position.y = y;
+ }
+
+ void on_update(SDL_Renderer* renderer)
+ {
+ static TTF_Font* font = ResourcesManager::instance()->get_font_pool().find(ResID::Font_Main)->second;
+
+ SDL_DestroyTexture(tex_text_background);
+ tex_text_background = nullptr;
+ SDL_DestroyTexture(tex_text_foreground);
+ tex_text_foreground = nullptr;
+
+ std::string str_val = std::to_string((int)CoinManager::instance()->get_current_coin_num());
+ SDL_Surface* suf_text_background = TTF_RenderText_Blended(font, str_val.c_str(), color_text_background);
+ SDL_Surface* suf_text_foreground = TTF_RenderText_Blended(font, str_val.c_str(), color_text_foredground);
+
+ width_text = suf_text_background->w, height_text = suf_text_background->h;
+
+ tex_text_background = SDL_CreateTextureFromSurface(renderer, suf_text_background);
+ tex_text_foreground = SDL_CreateTextureFromSurface(renderer, suf_text_foreground);
+
+ SDL_FreeSurface(suf_text_background);
+ SDL_FreeSurface(suf_text_foreground);
+ }
+
+ void on_render(SDL_Renderer* renderer)
+ {
+ static SDL_Rect rect_dst;
+ static const ResourcesManager::TexturePool& tex_pool = ResourcesManager::instance()->get_texture_pool();
+ static SDL_Texture* tex_coin = tex_pool.find(ResID::Tex_UICoin)->second;
+ static SDL_Texture* tex_heart = tex_pool.find(ResID::Tex_UIHeart)->second;
+ static SDL_Texture* tex_home_avatar = tex_pool.find(ResID::Tex_UIHomeAvatar)->second;
+ static SDL_Texture* tex_player_avatar = tex_pool.find(ResID::Tex_UIPlayerAvatar)->second;
+
+ rect_dst.x = position.x, rect_dst.y = position.y;
+ rect_dst.w = 78, rect_dst.h = 78;
+ SDL_RenderCopy(renderer, tex_home_avatar, nullptr, &rect_dst);
+
+ for (int i = 0; i < (int)HomeManager::instance()->get_current_hp_num(); i++)
+ {
+ rect_dst.x = position.x + 78 + 15 + i * (32 + 2);
+ rect_dst.y = position.y;
+ rect_dst.w = 32, rect_dst.h = 32;
+ SDL_RenderCopy(renderer, tex_heart, nullptr, &rect_dst);
+ }
+
+ rect_dst.x = position.x + 78 + 15;
+ rect_dst.y = position.y + 78 - 32;
+ rect_dst.w = 32, rect_dst.h = 32;
+ SDL_RenderCopy(renderer, tex_coin, nullptr, &rect_dst);
+
+ rect_dst.x += 32 + 10 + offset_shadow.x;
+ rect_dst.y = rect_dst.y + (32 - height_text) / 2 + offset_shadow.y;
+ rect_dst.w = width_text, rect_dst.h = height_text;
+ SDL_RenderCopy(renderer, tex_text_background, nullptr, &rect_dst);
+
+ rect_dst.x -= offset_shadow.x;
+ rect_dst.y -= offset_shadow.y;
+ SDL_RenderCopy(renderer, tex_text_foreground, nullptr, &rect_dst);
+
+ rect_dst.x = position.x + (78 - 65) / 2;
+ rect_dst.y = position.y + 78 + 5;
+ rect_dst.w = 65, rect_dst.h = 65;
+ SDL_RenderCopy(renderer, tex_player_avatar, nullptr, &rect_dst);
+
+ rect_dst.x = position.x + 78 + 15;
+ rect_dst.y += 10;
+ roundedBoxRGBA(renderer, rect_dst.x, rect_dst.y, rect_dst.x + width_mp_bar, rect_dst.y + height_mp_bar, 4,
+ color_mp_bar_background.r, color_mp_bar_background.g, color_mp_bar_background.b, color_mp_bar_background.a);
+
+ rect_dst.x += width_border_mp_bar;
+ rect_dst.y += width_border_mp_bar;
+ rect_dst.w = width_mp_bar - 2 * width_border_mp_bar;
+ rect_dst.h = height_mp_bar - 2 * width_border_mp_bar;
+ roundedBoxRGBA(renderer, rect_dst.x, rect_dst.y, rect_dst.x + rect_dst.w, rect_dst.y + rect_dst.h, 2,
+ color_mp_bar_foredground.r, color_mp_bar_foredground.g, color_mp_bar_foredground.b, color_mp_bar_foredground.a);
+
+ }
+private:
+ const int size_heart = 32;
+ const int width_mp_bar = 200;
+ const int height_mp_bar = 20;
+ const int width_border_mp_bar = 4;
+ const SDL_Point offset_shadow = { 2,2 };
+ const SDL_Color color_text_background = { 175,175,175,255 };
+ const SDL_Color color_text_foredground = { 255,255,255,255 };
+ const SDL_Color color_mp_bar_background = { 48,40,51,255 };
+ const SDL_Color color_mp_bar_foredground = { 144,121,173,255 };
+
+private:
+ SDL_Point position = { 0 };
+ int width_text = 0, height_text = 0;
+ SDL_Texture* tex_text_background = nullptr;
+ SDL_Texture* tex_text_foreground = nullptr;
+
+};
+
+#endif // !_STATUES_BAR_H_
diff --git a/TdGame/TdGame/tile.h b/TdGame/TdGame/tile.h
index d1b308d..3ce37ec 100644
--- a/TdGame/TdGame/tile.h
+++ b/TdGame/TdGame/tile.h
@@ -1,4 +1,3 @@
-#pragma once
#ifndef _TILE_H_
#define _TILE_H_
diff --git a/TdGame/TdGame/tower.h b/TdGame/TdGame/tower.h
index 8c49537..e64f324 100644
--- a/TdGame/TdGame/tower.h
+++ b/TdGame/TdGame/tower.h
@@ -21,17 +21,17 @@ public:
}
);
- anim_idle_up.set_loop(true);
+ anim_idle_up.set_loop(false);
anim_idle_up.set_interval(0.2);
- anim_idle_down.set_loop(true);
+ anim_idle_down.set_loop(false);
anim_idle_down.set_interval(0.2);
- anim_idle_left.set_loop(true);
+ anim_idle_left.set_loop(false);
anim_idle_left.set_interval(0.2);
- anim_idle_right.set_loop(true);
+ anim_idle_right.set_loop(false);
anim_idle_right.set_interval(0.2);
- anim_fire_up.set_loop(true);
+ anim_fire_up.set_loop(false);
anim_fire_up.set_interval(0.2);
anim_fire_up.set_on_finished(
[&]()
@@ -39,7 +39,7 @@ public:
update_idle_animation();
});
- anim_fire_down.set_loop(true);
+ anim_fire_down.set_loop(false);
anim_fire_down.set_interval(0.2);
anim_fire_down.set_on_finished(
[&]()
@@ -47,7 +47,7 @@ public:
update_idle_animation();
});
- anim_fire_left.set_loop(true);
+ anim_fire_left.set_loop(false);
anim_fire_left.set_interval(0.2);
anim_fire_left.set_on_finished(
[&]()
@@ -55,7 +55,7 @@ public:
update_idle_animation();
});
- anim_fire_right.set_loop(true);
+ anim_fire_right.set_loop(false);
anim_fire_right.set_interval(0.2);
anim_fire_right.set_on_finished(
[&]()
@@ -208,7 +208,7 @@ private:
if (!target_enemy) return;
- can_fire = true;
+ can_fire = false;
static ConfigManager* instance = ConfigManager::instance();
static const ResourcesManager::SoundPool& sound_pool =
ResourcesManager::instance()->get_sound_pool();
diff --git a/TdGame/TdGame/tower_manager.h b/TdGame/TdGame/tower_manager.h
new file mode 100644
index 0000000..5deef12
--- /dev/null
+++ b/TdGame/TdGame/tower_manager.h
@@ -0,0 +1,158 @@
+#ifndef _TOWER_MANAGER_H_
+#define _TOWER_MANAGER_H_
+
+#include "tower.h"
+#include "tower_type.h"
+#include "manager.h"
+#include "archer_tower.h"
+#include "axeman_tower.h"
+#include "gunner_tower.h"
+#include "config_manager.h"
+#include "resources_manager.h"
+
+#include
+
+class TowerManager : public Manager
+{
+
+ friend class Manager;
+
+public:
+ void on_update(double delta)
+ {
+ for (Tower* tower : tower_list)
+ tower->on_update(delta);
+ }
+
+ void on_render(SDL_Renderer* renderer)
+ {
+ for (Tower* tower : tower_list)
+ tower->on_render(renderer);
+ }
+
+ double get_place_cost(TowerType type)
+ {
+ static ConfigManager* instance = ConfigManager::instance();
+
+ switch (type)
+ {
+ case Archer:
+ return instance->archer_template.cost[instance->level_archer];
+ break;
+ case Axeman:
+ return instance->axeman_template.cost[instance->level_axeman];
+ break;
+ case Gunner:
+ return instance->gunner_template.cost[instance->level_gunner];
+ break;
+ }
+ return 0;
+ }
+
+ double get_upgrade_cost(TowerType type)
+ {
+ static ConfigManager* instance = ConfigManager::instance();
+
+ switch (type)
+ {
+ case Archer:
+ return instance->level_archer == 9 ? -1 :
+ instance->archer_template.upgrade_cost[instance->level_archer];
+ break;
+ case Axeman:
+ return instance->level_axeman == 9 ? -1 :
+ instance->axeman_template.upgrade_cost[instance->level_axeman];
+ break;
+ case Gunner:
+ return instance->level_gunner == 9 ? -1 :
+ instance->gunner_template.upgrade_cost[instance->level_gunner];
+ break;
+ }
+ return 0;
+ }
+
+ double get_damage_range(TowerType type)
+ {
+ static ConfigManager* instance = ConfigManager::instance();
+
+ switch (type)
+ {
+ case Archer:
+ return instance->archer_template.view_range[instance->level_archer];
+ break;
+ case Axeman:
+ return instance->axeman_template.view_range[instance->level_axeman];
+ break;
+ case Gunner:
+ return instance->gunner_template.view_range[instance->level_gunner];
+ break;
+ }
+ return 0;
+ }
+
+ void place_tower(TowerType type,const SDL_Point& idx)
+ {
+ Tower* tower = nullptr;
+
+ switch (type)
+ {
+ case Archer:
+ tower = new ArcherTower();
+ break;
+ case Axeman:
+ tower = new AxemanTower();
+ break;
+ case Gunner:
+ tower = new GunnerTower();
+ break;
+ default:
+ tower = new ArcherTower();
+ break;
+ }
+
+ static Vector2 position;
+ static const SDL_Rect& rect = ConfigManager::instance()->rect_tile_map;
+
+ position.x = rect.x + idx.x * SIZE_TILE + SIZE_TILE / 2;
+ position.y = rect.y + idx.y * SIZE_TILE + SIZE_TILE / 2;
+ tower->set_position(position);
+ tower_list.push_back(tower);
+
+ static const ResourcesManager::SoundPool& sound_pool
+ = ResourcesManager::instance()->get_sound_pool();
+
+ Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_PlaceTower)->second, 0);
+ }
+
+ void upgrade_tower(TowerType type)
+ {
+ static ConfigManager* instance = ConfigManager::instance();
+
+ switch (type)
+ {
+ case Archer:
+ instance->level_archer = instance->level_archer >= 9 ? 9 : instance->level_archer + 1;
+ break;
+ case Axeman:
+ instance->level_axeman = instance->level_axeman >= 9 ? 9 : instance->level_axeman + 1;
+ break;
+ case Gunner:
+ instance->level_gunner = instance->level_gunner >= 9 ? 9 : instance->level_gunner + 1;
+ break;
+ }
+
+ static const ResourcesManager::SoundPool& sound_pool
+ = ResourcesManager::instance()->get_sound_pool();
+
+ Mix_PlayChannel(-1, sound_pool.find(ResID::Sound_TowerLevelUp)->second, 0);
+ }
+protected:
+ TowerManager() = default;
+ ~TowerManager() = default;
+
+private:
+ std::vector tower_list;
+};
+
+
+#endif // !_TOWER_MANAGER_H_