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_