diff --git a/.gitignore b/.gitignore index cbef543..7745194 100644 --- a/.gitignore +++ b/.gitignore @@ -432,3 +432,21 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml +# ---> CMake +build/ +cmake-build-*/ +CMakeCache.txt +CMakeFiles/ +CMakeScripts/ +*.cmake +!CMakeLists.txt +Makefile +*.make + +session-*.md +.hermes/ + +# CMake 构建产物 +build_Debug/ +build_Release/ +build_*/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2031d20 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.10) +project(tank_battles_on_the_scrap_paper + VERSION 1.0 + LANGUAGES CXX +) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(SDL2 REQUIRED) +find_package(SDL2_image REQUIRED) +find_package(SDL2_mixer REQUIRED) +find_package(SDL2_ttf REQUIRED) + +set(SOURCES + tank_battles_on_the_scrap_paper/main.cpp + tank_battles_on_the_scrap_paper/src/AssetManager.cpp + tank_battles_on_the_scrap_paper/src/Renderer.cpp + tank_battles_on_the_scrap_paper/src/Map.cpp + tank_battles_on_the_scrap_paper/src/Bullet.cpp + tank_battles_on_the_scrap_paper/src/Tank.cpp + tank_battles_on_the_scrap_paper/src/Game.cpp +) + +set(HEADERS + tank_battles_on_the_scrap_paper/data_config.h + tank_battles_on_the_scrap_paper/src/AssetManager.h + tank_battles_on_the_scrap_paper/src/Renderer.h + tank_battles_on_the_scrap_paper/src/Map.h + tank_battles_on_the_scrap_paper/src/Bullet.h + tank_battles_on_the_scrap_paper/src/Tank.h + tank_battles_on_the_scrap_paper/src/Game.h + tank_battles_on_the_scrap_paper/src/UI.h +) + +add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS}) + +target_link_libraries(${PROJECT_NAME} PRIVATE + SDL2::SDL2 + SDL2_image::SDL2_image + SDL2_mixer::SDL2_mixer + SDL2_ttf::SDL2_ttf +) + +target_include_directories(${PROJECT_NAME} PRIVATE + tank_battles_on_the_scrap_paper +) + +file(COPY + tank_battles_on_the_scrap_paper/images/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/images/ +) + +file(COPY + tank_battles_on_the_scrap_paper/music/ + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/music/ +) diff --git a/README.md b/README.md index d1df6a6..beaaf4f 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,6 @@ v16: 添加了全局背景音效 -v17: 修改了一点bug,在返回菜单后调用InitMap(),避免再次进入游戏界面时有脏数据导致显示出错 \ No newline at end of file +v17: 修改了一点bug,在返回菜单后调用InitMap(),避免再次进入游戏界面时有脏数据导致显示出错 + +v18: 从 Windows/EasyX 移植到 SDL2,支持 Linux;修复启动黑屏问题(自动设置工作目录为可执行文件所在目录) \ No newline at end of file diff --git a/tank_battles_on_the_scrap_paper.sln b/tank_battles_on_the_scrap_paper.sln deleted file mode 100644 index aa28c4a..0000000 --- a/tank_battles_on_the_scrap_paper.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.33530.505 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tank_battles_on_the_scrap_paper", "tank_battles_on_the_scrap_paper\tank_battles_on_the_scrap_paper.vcxproj", "{AC8C4A04-1650-473C-8E9A-3B7CDE2AD5CC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {AC8C4A04-1650-473C-8E9A-3B7CDE2AD5CC}.Debug|x64.ActiveCfg = Debug|x64 - {AC8C4A04-1650-473C-8E9A-3B7CDE2AD5CC}.Debug|x64.Build.0 = Debug|x64 - {AC8C4A04-1650-473C-8E9A-3B7CDE2AD5CC}.Debug|x86.ActiveCfg = Debug|Win32 - {AC8C4A04-1650-473C-8E9A-3B7CDE2AD5CC}.Debug|x86.Build.0 = Debug|Win32 - {AC8C4A04-1650-473C-8E9A-3B7CDE2AD5CC}.Release|x64.ActiveCfg = Release|x64 - {AC8C4A04-1650-473C-8E9A-3B7CDE2AD5CC}.Release|x64.Build.0 = Release|x64 - {AC8C4A04-1650-473C-8E9A-3B7CDE2AD5CC}.Release|x86.ActiveCfg = Release|Win32 - {AC8C4A04-1650-473C-8E9A-3B7CDE2AD5CC}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {4E9B74CF-EE0B-430C-8380-34BE94639065} - EndGlobalSection -EndGlobal diff --git a/tank_battles_on_the_scrap_paper/bullet.h b/tank_battles_on_the_scrap_paper/bullet.h deleted file mode 100644 index 653f5b3..0000000 --- a/tank_battles_on_the_scrap_paper/bullet.h +++ /dev/null @@ -1,24 +0,0 @@ -// ӵ -#ifndef BULLET_H -#define BULLET_H - -/* - ӵ - ӵ꣺xy - damageʾǰӵɵ˺ - ־is_alive - dir - UP - DOWN - LEFT - RIGHT -*/ -struct bullet { - int x, y; - int damage; // ӵ - int dir; - bool is_live; // Ƿ - //tank shooter; //ֵΪenemies[i]player -}; - -#endif // !BULLET_H \ No newline at end of file diff --git a/tank_battles_on_the_scrap_paper/data_config.h b/tank_battles_on_the_scrap_paper/data_config.h index 60ee9ec..018626c 100644 --- a/tank_battles_on_the_scrap_paper/data_config.h +++ b/tank_battles_on_the_scrap_paper/data_config.h @@ -1,52 +1,36 @@ -// ö +// 项目配置常量 #ifndef DATA_CONFIG_H #define DATA_CONFIG_H -// tank bullet ͷļ -#include "tank.h" -#include "bullet.h" -// -const int CELL_SIZE = 30; // ÿԪ̹ˡǽյصȣĴС磺أ -const int MAP_CELL_NUM = 20; // ͼСΪMAP_CELL_NUM^2 -const int ENEMIES_NUM = 10; // ͼĵ -const int BULLET_NUM = 20; // ͼӵ -const int SINGLE_BULLET = 3; // ÿ̹ͬʱڵӵ -const int White = 0; // Ҷͼ- -const int Black = 1; // Ҷͼ- +// 网格 +constexpr int CELL_SIZE = 30; +constexpr int MAP_CELL_NUM = 20; -#define PIEXL1 30 //س -#define PIEXL2 4 -#define X_OFFSET 50 //ϵһǽΪ׼ƫ -#define Y_OFFSET 45 //ϵһǽΪ׼ƫ -/* - ͼ - ʹ洢ͼϢ - map[x][y] 洢ǰ̹Ϣ - BLANK յ - RED_TANK 췽̹ - RED_DEAD_TANK 췽̹ - BLUE_TANK, ̹ - BLUE_DEAD_TANK ̹ - WALL ǽ - BULLET ӵ -*/ +// 偏移 +constexpr int X_OFFSET = 50; +constexpr int Y_OFFSET = 45; + +// 窗口 +constexpr int WINDOW_W = 700; +constexpr int WINDOW_H = 700; + +// 实体数量 +constexpr int ENEMIES_NUM = 10; +constexpr int MAX_PLAYER_BULLETS = 3; +constexpr int MAX_ENEMY_BULLETS = ENEMIES_NUM; + +// 方向 +enum Direction { UP, DOWN, LEFT, RIGHT }; + +// 地图单元类型 enum CELL_Type { - BLANK, // յ - RED_TANK, // 췽̹ - RED_DEAD_TANK, // 췽̹ - BLUE_TANK, // ̹ - BLUE_DEAD_TANK, // ̹ - WALL, // ǽ - BULLET, // ӵ + BLANK, + RED_TANK, + RED_DEAD_TANK, + BLUE_TANK, + BLUE_DEAD_TANK, + WALL, + BULLET }; -int map[MAP_CELL_NUM][MAP_CELL_NUM]; //map.hԤ -int kill = 5; //ɱ -tank player; // -tank enemies[ENEMIES_NUM]; // -bullet E_bullets[BULLET_NUM * ENEMIES_NUM]; //з̹ӵ -bullet P_bullets[BULLET_NUM]; //ӵ - -tank enemy; // ڸĵ˵ԣѶõ - -#endif // !DATA_CONFIG_H \ No newline at end of file +#endif diff --git a/tank_battles_on_the_scrap_paper/main.cpp b/tank_battles_on_the_scrap_paper/main.cpp index 864fd83..22b696c 100644 --- a/tank_battles_on_the_scrap_paper/main.cpp +++ b/tank_battles_on_the_scrap_paper/main.cpp @@ -1,1457 +1,6 @@ -// Ŀֽϵ̹˴ս -#include -#include -#include -#include -#include -#include -#include -// data_config ͷļ -#include "data_config.h" -// #include "map.h" // Ԥͼͷļ -// #include "main.h" // 뺯ͷļ +#include "src/Game.h" -// -------- Ч -------- -#include"resource.h"//Դ֮һresource.hͷļ ǵü -#include -#include -#pragma comment(lib,"winmm.lib") - -using namespace std; - -void EnemyBulletMove(); -void PlayerBulletMove(); -int BulletMoveCheck(int dir, bullet bul); -void change(); -void EnemiesMove(); -void EnemyInit(); -void EnemyShoot(); -void GameView(); -void GameView_ShowBullet(); -void GameView_ShowLose(); -void GameView_ShowMap(); -void GameView_ShowTank(); -void GameView_ShowWIN(); -void InitMap(); -// void InitMap(const int preset_map[50][50]); -bool IsWin(); -void Level(); -void MemberView(); -void MenuView(); -void Move(); -void PlayerInit(); -void PlayerMove(); -void PlayerShoot(); -int TankMoveCheck(int dir, tank tank); -void Update(); - -// git - - -/* - ˵棺 - չʾϷѶȣ˳ѡ - ûͨwsѡӦİťس - - Ϸ - ѡϷͼʼͼ̹ - - Ѷȣ - öӦѶȽϷ - - ڿԱ - ҵҳ棬չʾԱ - - ˳Ϸ - ѡ˳Ϸ - - Ϸ - չʾͼ̹ˣҶ̹ԶƶͿ - wsadҷƶ - ¿ոԼǰڵ - УѪ - һ̹ˣϷ,ص˵ - - ͣ - չʾϷ˳ϷťͬʱϷͣ -*/ - -/* - - 1˵ - 2˵Ϸ - 3Ϸͣ - 4ͣò˵ -*/ - -//-----------------view------------------------ -/* - ˣ - ܣչʾϷѶȣ˳ѡ, - Ϸ - ѡϷʱϷ溯ֱӽϷ - Ѷȣ - ѡѶʱҳ溯з̹ѪԼ仯ĺݡ - ֮Ҫesc˵ȻɽϷ - ˳Ϸ - ѡ˳ʱ˳ֱӽϷ - ǣ - չʾŶϢ - // Ϸеʼҳ -*/ -void MenuView(); - -/* -* Ϸ - ˣunder a bushel - ܣ -*/ -// ÿһΣͼͼÿһ״̬ -// һµͼϽӣ̹˺ӵ꣺λúͷ -void GameView() //Ϸͼ -{ - InitMap(); //ʼͼ - // InitMap(map1); //ʼͼ - EnemyInit(); //ʼз̹˵λ - PlayerInit(); //ʼ̹˵λ - - GameView_ShowMap(); //ʾͼ - GameView_ShowTank(); //ʾ̹ - - while (!IsWin()) // Ϸûʤ - { - if (player.hp <= 0) //жҵֵǷСڻ 0 - { - GameView_ShowLose(); // failView ʾʧͼ - /*MenuView();*/ //ص˵ - break; - } - - if (GetAsyncKeyState(VK_ESCAPE)) //ûļ¼ǷΪ ESC - { - MenuView(); // menuView ص˵ - } - - Move(); // MoveShoot Update ЩҪʵ̹˺ӵƶ״̬¡ - // - if(GetAsyncKeyState(VK_SPACE)) - PlayerShoot(); - EnemyShoot(); - // Update(); - Update(); - GameView_ShowMap(); //ʾͼ״̬ - GameView_ShowBullet(); //ʾӵ״̬ - GameView_ShowTank(); //ʾ̹˵״̬ - } - - if (IsWin()) //Ϸʤ winView ʾʤͼص˵档 - { - GameView_ShowWIN(); - /*MenuView();*/ - } -} - -/* - :Ӻˮ - - жӵǷﵽޣ0-3ֱӱ0-3ҵһis_live == false,break - ģӵʼ -*/ -void PlayerShoot() -{ - static clock_t start = clock() - 500; - if ((clock() - start) < 500) - return; - start = clock(); - for (int i = 0; i < SINGLE_BULLET; i++) - { - if (P_bullets[i].is_live == false) - { - //ʼӵ - P_bullets[i].x = player.x; - P_bullets[i].y = player.y; - P_bullets[i].dir = player.dir; - P_bullets[i].damage = player.attack; - P_bullets[i].is_live = true; - break; - } - } -} - -/* - :Ӻˮ - 룺˽ṹ - ˷ӵԶ,̹ - жǷҪ䣬%2,01 - if Ҫ ӵ -*/ -void EnemyShoot() -{ - static clock_t start = clock() - 3000; - if ((clock() - start) < 3000) - return; - start = clock(); - for (int i = 0; i < ENEMIES_NUM; i++) //е̹ - { - if (enemies[i].hp > 0) { - for (auto& j : E_bullets) - { - if (j.is_live == false) //ֻҪһӵڣ䣬ŶѾڣ򲻷ӵ - { - j.x = enemies[i].x; - j.y = enemies[i].y; - j.dir = enemies[i].dir; - j.damage = enemy.attack; - j.is_live = true; - break; - } - } - } - } -} - -/* - :Ӻˮ - ܣ - ƶӵƶӵĿĴײ -*/ -void Move() -{ - bool move = false; - if (GetAsyncKeyState('W') || GetAsyncKeyState(VK_UP)) - { - player.dir = UP; - move = true; - } - else if (GetAsyncKeyState('S') || GetAsyncKeyState(VK_DOWN)) - { - player.dir = DOWN; - move = true; - } - else if (GetAsyncKeyState('A') || GetAsyncKeyState(VK_LEFT)) - { - player.dir = LEFT; - move = true; - } - else if (GetAsyncKeyState('D') || GetAsyncKeyState(VK_RIGHT)) - { - player.dir = RIGHT; - move = true; - };//ķ - - - - if (move) { - PlayerMove(); //player.dir ȫֱô - } - EnemiesMove(); //ƶ - PlayerBulletMove(); - EnemyBulletMove(); -} - -///* -//* ҷǰһǿյ -//*/ -//bool PlayerCollision(); - - -/* - ˣС yang - ܣ - mapɵͼ -*/ -void GameView_ShowMap() // ̹ȫֵģҪ -//void GameView_ShowMap(tank player) -{ - // ˫ - setbkmode(TRANSPARENT); // ñ͸ - BeginBatchDraw(); // ʼͼ - - //ȡͼƬ - //·ȷȷΨһ ------ - IMAGE image_WALL, image_back, image_RED_HP; - // IMAGE image_WALL, image_back, image_RED_HP, image_BLUE_HP; - loadimage(&image_WALL, ".//images//wall.jpg", CELL_SIZE, CELL_SIZE); - loadimage(&image_back, ".//images//Ϸ汳.jpg", 700, 700); - loadimage(&image_RED_HP, ".//images//red_hp_bar.jpg", CELL_SIZE, CELL_SIZE); - // loadimage(&image_BLUE_HP, ".//images//blue_hp.jpg", 30, 30); // version1汾ĿǰзѪ - - //Ⱦ - putimage(0, 0, &image_back); - - //췽̹HPȾ - for (int i = 0; i < player.hp; i++) - { - putimage(100 + i * 30 , 10, &image_RED_HP); - } - - ////̹HPȾ - //for (int j = 0; j < player.hp; j++) - //{ - // putimage(570 - j * 30, 120, &image_RED_HP); - //} - - int dieNum = 0; - for (auto& i : enemies) { - if (i.hp <= 0) dieNum++; - } - //ʾʵʱȾ - settextcolor((157, 157, 157)); - settextstyle(30, 0, ""); - outtextxy(110, 660, "ܣ"); - outtextxy(185, 660, to_string(dieNum).data()); - outtextxy(210, 660, "/"); - outtextxy(225, 660, "10"); - - outtextxy(325, 660, string("" + to_string(player.attack)).data()); - - - //ǽȾ - for (int i = 0; i < MAP_CELL_NUM; i++) - { - for (int j = 0; j < MAP_CELL_NUM; j++) - { - if (map[i][j] == WALL) - { - putimage(j * CELL_SIZE + X_OFFSET, i * CELL_SIZE + Y_OFFSET, &image_WALL); - } - } - } -} - - -/* - ˣ - ܣڵͼ -*/ -// void GameView_ShowBullet(); -// void GameView_ShowBullet(bullet b); - -/* - ˣС yang - ܣ̹ͼ - -*/ -void GameView_ShowTank() -// void GameView_ShowTank(tank player, tank enemies[]) -{ - // ˫ - setbkmode(TRANSPARENT); // ñ͸ - BeginBatchDraw(); // ʼͼ - - //̹ͼƬ - IMAGE image_REDtank_UP[2], image_REDtank_DOWN[2], image_REDtank_LEFT[2], image_REDtank_RIGHT[2], - - image_BLUEtank_UP[2], image_BLUEtank_DOWN[2], image_BLUEtank_LEFT[2], image_BLUEtank_RIGHT[2], - - image_BLUE_DEADtank[2]; - - //صͼ - //·ȷȷΨһ ------ - - loadimage(&image_REDtank_DOWN[White], ".//images//red_down_w.png", CELL_SIZE, CELL_SIZE); - loadimage(&image_REDtank_DOWN[Black], ".//images//red_down_b.png", CELL_SIZE, CELL_SIZE); - - loadimage(&image_REDtank_UP[White], ".//images//red_up_w.png", CELL_SIZE, CELL_SIZE); - loadimage(&image_REDtank_UP[Black], ".//images//red_up_b.png", CELL_SIZE, CELL_SIZE); - - loadimage(&image_REDtank_LEFT[White], ".//images//red_left_w.png", CELL_SIZE, CELL_SIZE); - loadimage(&image_REDtank_LEFT[Black], ".//images//red_left_b.png", CELL_SIZE, CELL_SIZE); - - loadimage(&image_REDtank_RIGHT[White], ".//images//red_right_w.png", CELL_SIZE, CELL_SIZE); - loadimage(&image_REDtank_RIGHT[Black], ".//images//red_right_b.png", CELL_SIZE, CELL_SIZE); - - - loadimage(&image_BLUEtank_UP[White], ".//images//blue_up_w.png", CELL_SIZE, CELL_SIZE); - loadimage(&image_BLUEtank_UP[Black], ".//images//blue_up_b.png", CELL_SIZE, CELL_SIZE); - - loadimage(&image_BLUEtank_DOWN[White], ".//images//blue_down_w.png", CELL_SIZE, CELL_SIZE); - loadimage(&image_BLUEtank_DOWN[Black], ".//images//blue_down_b.png", CELL_SIZE, CELL_SIZE); - - loadimage(&image_BLUEtank_LEFT[White], ".//images//blue_left_w.png", CELL_SIZE, CELL_SIZE); - loadimage(&image_BLUEtank_LEFT[Black], ".//images//blue_left_b.png", CELL_SIZE, CELL_SIZE); - - loadimage(&image_BLUEtank_RIGHT[White], ".//images//blue_right_w.png", CELL_SIZE, CELL_SIZE); - loadimage(&image_BLUEtank_RIGHT[Black], ".//images//blue_right_b.png", CELL_SIZE, CELL_SIZE); - - // loadimage(&image_RED_DEADtank, "./̹.png", CELL_SIZE, CELL_SIZE); // ̹˱ϺζϷֱӵϷʧҳ棬˲ҪʾԼı״̬ - loadimage(&image_BLUE_DEADtank[White], ".//images//dead_tank_w.png", CELL_SIZE, CELL_SIZE); - loadimage(&image_BLUE_DEADtank[Black], ".//images//dead_tank_b.png", CELL_SIZE, CELL_SIZE); - //loadimage(&image_BLANK, ".//images//blank.jpg", CELL_SIZE, CELL_SIZE); - - - - - //ȾͼԪ - for (int i = 0; i < MAP_CELL_NUM; i++) - { - for (int j = 0; j < MAP_CELL_NUM; j++) - { - //if (map[i][j] == BLANK) - //{ - // putimage(j * CELL_SIZE + X_OFFSET, i * CELL_SIZE + Y_OFFSET, &image_BLANK); // ͼ - //} - - if ((map[i][j] == RED_TANK && player.dir == LEFT)) - { - putimage(player.x * CELL_SIZE + X_OFFSET, player.y * CELL_SIZE + Y_OFFSET, &image_REDtank_LEFT[White], SRCAND); - putimage(player.x * CELL_SIZE + X_OFFSET, player.y * CELL_SIZE + Y_OFFSET, &image_REDtank_LEFT[Black], SRCPAINT); - } - - if (map[i][j] == RED_TANK && player.dir == RIGHT) - { - putimage(player.x * CELL_SIZE + X_OFFSET, player.y * CELL_SIZE + Y_OFFSET, &image_REDtank_RIGHT[White], SRCAND); - putimage(player.x * CELL_SIZE + X_OFFSET, player.y * CELL_SIZE + Y_OFFSET, &image_REDtank_RIGHT[Black], SRCPAINT); - } - - if (map[i][j] == RED_TANK && player.dir == DOWN) - { - putimage(player.x * CELL_SIZE + X_OFFSET, player.y * CELL_SIZE + Y_OFFSET, &image_REDtank_DOWN[White], SRCAND); - putimage(player.x * CELL_SIZE + X_OFFSET, player.y * CELL_SIZE + Y_OFFSET, &image_REDtank_DOWN[Black], SRCPAINT); - } - - if (map[i][j] == RED_TANK && player.dir == UP) - { - putimage(player.x * CELL_SIZE + X_OFFSET, player.y * CELL_SIZE + Y_OFFSET, &image_REDtank_UP[White], SRCAND); - putimage(player.x * CELL_SIZE + X_OFFSET, player.y * CELL_SIZE + Y_OFFSET, &image_REDtank_UP[Black], SRCPAINT); - } - - //if (map[i][j] == RED_DEAD_TANK) - //{ - - // putimage(j * CELL_SIZE + X_OFFSET, i * CELL_SIZE + Y_OFFSET, &image_RED_DEADtank); - //} - } - } - - //Ⱦ̹ - for (int i = 0; i < ENEMIES_NUM; i++) - { - if (enemies[i].is_taken) - continue; - if (enemies[i].hp > 0) { - switch (enemies[i].dir) - { - case UP: - putimage(enemies[i].x * CELL_SIZE + X_OFFSET, enemies[i].y * CELL_SIZE + Y_OFFSET, &image_BLUEtank_UP[White], SRCAND); - putimage(enemies[i].x * CELL_SIZE + X_OFFSET, enemies[i].y * CELL_SIZE + Y_OFFSET, &image_BLUEtank_UP[Black], SRCPAINT); - break; - case DOWN: - putimage(enemies[i].x * CELL_SIZE + X_OFFSET, enemies[i].y * CELL_SIZE + Y_OFFSET, &image_BLUEtank_DOWN[White], SRCAND); - putimage(enemies[i].x * CELL_SIZE + X_OFFSET, enemies[i].y * CELL_SIZE + Y_OFFSET, &image_BLUEtank_DOWN[Black], SRCPAINT); - break; - case LEFT: - putimage(enemies[i].x * CELL_SIZE + X_OFFSET, enemies[i].y * CELL_SIZE + Y_OFFSET, &image_BLUEtank_LEFT[White], SRCAND); - putimage(enemies[i].x * CELL_SIZE + X_OFFSET, enemies[i].y * CELL_SIZE + Y_OFFSET, &image_BLUEtank_LEFT[Black], SRCPAINT); - break; - case RIGHT: - putimage(enemies[i].x * CELL_SIZE + X_OFFSET, enemies[i].y * CELL_SIZE + Y_OFFSET, &image_BLUEtank_RIGHT[White], SRCAND); - putimage(enemies[i].x * CELL_SIZE + X_OFFSET, enemies[i].y * CELL_SIZE + Y_OFFSET, &image_BLUEtank_RIGHT[Black], SRCPAINT); - break; - default: - break; - } - } - else { - putimage(enemies[i].x * CELL_SIZE + X_OFFSET, enemies[i].y * CELL_SIZE + Y_OFFSET, &image_BLUE_DEADtank[White], SRCAND); - putimage(enemies[i].x * CELL_SIZE + X_OFFSET, enemies[i].y * CELL_SIZE + Y_OFFSET, &image_BLUE_DEADtank[Black], SRCPAINT); - } - } - - // ͼʾͼ - EndBatchDraw(); // ͼ -} - - -IMAGE image_BULLET[4][2]; - -void GameView_ShowBullet() -{ - bool b = true; - if (b) { - b = false; - loadimage(&image_BULLET[UP][White], ".//images//B_UP_w.png", CELL_SIZE / 2 / 2, CELL_SIZE / 2); - loadimage(&image_BULLET[UP][Black], ".//images//B_UP_b.png", CELL_SIZE / 2 / 2, CELL_SIZE / 2); - loadimage(&image_BULLET[DOWN][White], ".//images//B_DOWN_w.png", CELL_SIZE / 2 / 2, CELL_SIZE / 2); - loadimage(&image_BULLET[DOWN][Black], ".//images//B_DOWN_b.png", CELL_SIZE / 2 / 2, CELL_SIZE / 2); - loadimage(&image_BULLET[LEFT][White], ".//images//B_LEFT_w.png", CELL_SIZE / 2, CELL_SIZE / 2 / 2); - loadimage(&image_BULLET[LEFT][Black], ".//images//B_LEFT_b.png", CELL_SIZE / 2, CELL_SIZE / 2 / 2); - loadimage(&image_BULLET[RIGHT][White], ".//images//B_RIGHT_w.png", CELL_SIZE / 2, CELL_SIZE / 2 / 2); - loadimage(&image_BULLET[RIGHT][Black], ".//images//B_RIGHT_b.png", CELL_SIZE / 2, CELL_SIZE / 2 / 2); - } - for (int i = 0; i < BULLET_NUM; i++) { //ӵ - if (P_bullets[i].is_live) { - int x = P_bullets[i].x * CELL_SIZE + X_OFFSET; - int y = P_bullets[i].y * CELL_SIZE + Y_OFFSET; - putimage((P_bullets[i].dir > DOWN ? x : x + 10.5), (P_bullets[i].dir > DOWN ? y + 10.5 : y), &image_BULLET[P_bullets[i].dir][White], SRCAND); - putimage((P_bullets[i].dir > DOWN ? x : x + 10.5), (P_bullets[i].dir > DOWN ? y + 10.5 : y), &image_BULLET[P_bullets[i].dir][Black], SRCPAINT); - } - } - for (int i = 0; i < BULLET_NUM * ENEMIES_NUM; i++) { //Ƶзӵ - if (E_bullets[i].is_live) { - int x = E_bullets[i].x * CELL_SIZE + X_OFFSET; - int y = E_bullets[i].y * CELL_SIZE + Y_OFFSET; - putimage((E_bullets[i].dir > DOWN ? x : x + 10.5), (E_bullets[i].dir > DOWN ? y + 10.5 : y), &image_BULLET[E_bullets[i].dir][White], SRCAND); - putimage((E_bullets[i].dir > DOWN ? x : x + 10.5), (E_bullets[i].dir > DOWN ? y + 10.5 : y), &image_BULLET[E_bullets[i].dir][Black], SRCPAINT); - } - } - - /*for (int i = 0; i < 50; i++) - { - for (int j = 0; j < 50; j++) - { - if (map[i][j] == BULLET && bullets[i].dir == UP) - { - putimage(j * PIEXL1 + X + (PIEXL1 - PIEXL2) / 2, i * PIEXL1 + (PIEXL1 - PIEXL2) / 2, &image_BULLET_UP); - } - if (map[i][j] == BULLET && BULLET.dir == DOWN) - { - putimage(j * PIEXL1 + X + (PIEXL1 - PIEXL2) / 2, i * PIEXL1 + (PIEXL1 - PIEXL2) / 2, &image_BULLET_DOWN); - } - if (map[i][j] == BULLET && BULLET.dir == RIGHT) - { - putimage(j * PIEXL1 + X + (PIEXL1 - PIEXL2) / 2, i * PIEXL1 + (PIEXL1 - PIEXL2) / 2, &image_BULLET_RIGHT); - } - if (map[i][j] == BULLET && BULLET.dir == LEFT) - { - putimage(j * PIEXL1 + X + (PIEXL1 - PIEXL2) / 2, i * PIEXL1 + (PIEXL1 - PIEXL2) / 2, &image_BULLET_LEFT); - } - } - }*/ -} - -/* - ˣ - ܣʤ -*/ -void GameView_ShowWIN() -{ - cleardevice(); - setbkmode(TRANSPARENT); - IMAGE img; - loadimage(&img, ".//images//ʤ.png", 700, 700); - putimage(0, 0, &img); - IMAGE img_back; - loadimage(&img_back, ".//images//ذť.jpg", 150, 50); - putimage(30, 550, &img_back); - // - ExMessage msg; - while (true) - { - //̲ - if (_kbhit()) - { - char key = _getch();//һֱ - //printf("%d,%c\n", key, key); - switch (key) - { - case 27://ϼ - //ز˵ - MenuView(); - //printf("ز˵/n"); - return; - break; - } - } - - // - if (peekmessage(&msg, WH_MOUSE)) - { - switch (msg.message) - { - case WM_LBUTTONDOWN: - - //ص˵ - if (msg.x >= 30 && msg.x <= 180 && msg.y >= 550 && msg.y <= 600) - { - MenuView(); - return; - //printf("ص˵\n"); - //תѶȽ - } - break; - default: - break; - } - } - } - //char s[] = "˵"; - //outtextxy(250, 400, s); - //_getch(); -} - -/* - ˣ - ܣʧܽ - -*/ - -void GameView_ShowLose() -{ - cleardevice(); - setbkmode(TRANSPARENT); - IMAGE img; - loadimage(&img, ".//images//ʧ.png", 700, 700); - putimage(0, 0, &img); - IMAGE img_back; - loadimage(&img_back, ".//images//ذť.jpg", 150, 50); - putimage(30, 550, &img_back); - // - ExMessage msg; - while (true) - { - //̲ - if (_kbhit()) - { - char key = _getch();//һֱ - //printf("%d,%c\n", key, key); - switch (key) - { - case 27://ϼ - //ز˵ - MenuView(); - //printf("ز˵/n"); - return; - break; - } - } - - // - if (peekmessage(&msg, WH_MOUSE)) - { - switch (msg.message) - { - case WM_LBUTTONDOWN: - - //ص˵ - if (msg.x >= 30 && msg.x <= 180 && msg.y >= 550 && msg.y <= 600) - { - MenuView(); - return; - //printf("ص˵\n"); - //תѶȽ - } - break; - default: - break; - } - } - } - //char s[] = "˵"; - //outtextxy(250, 400, s); - //_getch(); -} - -//------------------view------------------- - -//-------------------service--------------- - -/* -* ˢµͼ -*/ - void Update() -{ - InitMap(); //ԭеĵͼݸһmap - - map[player.x][player.y] = RED_TANK; //ҡˡӵ飬λϢд뵽ͼ - - for (int i = 0; i < ENEMIES_NUM; i++) { - if (enemies[i].hp > 0) { - map[enemies[i].x][enemies[i].y] = BLUE_TANK; - } - else if (enemies[i].hp <= 0 && enemies[i].is_taken == false) { - map[enemies[i].x][enemies[i].y] = BLUE_DEAD_TANK; - } - } - - //for (int j = 0; j < BULLET_NUM; j++) { //ӵ - // if (P_bullets[j].is_live == true) { - // map[enemies[j].x][enemies[j].y] = BULLET; - // } - //} - - //for (int k = 0; k < BULLET_NUM * ENEMIES_NUM; k++) { //зӵ - // if (E_bullets[k].is_live == true) { - // map[enemies[k].x][enemies[k].y] = BULLET; - // } - //} -} - -/* - ˣ - ܣʼΪǽĿհ׵ͼ -*/ -void InitMap() -{ - // ʼͼ - for (int i = 0; i < MAP_CELL_NUM; i++) { - for (int j = 0; j < MAP_CELL_NUM; j++) { - // ܵλã趨Ϊ WALL - if (i == 0 || i == MAP_CELL_NUM - 1 || j == 0 || j == MAP_CELL_NUM - 1) { - map[i][j] = WALL; - } - // λ趨Ϊ BLANK - else { - map[i][j] = BLANK; - } - } - } -} - -/* - ˣ - ܣչĵͼʼmap.hļͼ -*/ -//void InitMap(const int preset_map[MAP_CELL_NUM][MAP_CELL_NUM]) { -// for (int i = 0; i < MAP_CELL_NUM; i++) { -// for (int j = 0; j < MAP_CELL_NUM; j++) { -// map[i][j] = preset_map[i][j]; -// } -// } -//} - -/* - ˣɥɥ - ܣ - շж̹ƶĿ - ʵ̹ƶ -*/ -void PlayerMove() { - static clock_t start = clock() - 100; - if ((clock() - start) < 100) - return; - start = clock(); - if (player.dir == UP) { - switch (TankMoveCheck(player.dir, player)) { //յ,з̹,ӵ,з̹,ǽ - case BLANK: - player.y--; - break; - case BULLET: - player.y--; - player.hp--; - for (int i = 0; i <= BULLET_NUM * ENEMIES_NUM; i++) { //ҳĿӵ䱨 - if (E_bullets[i].x == player.x && E_bullets[i].y == player.y) { - E_bullets[i].is_live = false; - } - } - break; - case BLUE_DEAD_TANK: - player.y--; - player.attack++; - if(player.hp < 5) player.hp++; - for (int i = 0; i < ENEMIES_NUM; i++) { //ѭ̹ - if (player.x == enemies[i].x && player.y == enemies[i].y) //Ҹλ̹ - enemies[i].is_taken = true; - } - break; - default: - break; - } - - - } - else if (player.dir == DOWN) { - switch (TankMoveCheck(player.dir, player)) { //յ,з̹,ӵ,з̹,ǽ - case BLANK: - player.y++; - break; - case BULLET: - player.y++; - player.hp--; - for (int i = 0; i <= BULLET_NUM * ENEMIES_NUM; i++) { //ҳĿӵ䱨 - if (E_bullets[i].x == player.x && E_bullets[i].y == player.y) { - E_bullets[i].is_live = false; - } - } - break; - case BLUE_DEAD_TANK: - player.y++; - player.attack++; - if (player.hp < 5) player.hp++; - for (int i = 0; i < ENEMIES_NUM; i++) { //ѭ̹ - if (player.x == enemies[i].x && player.y == enemies[i].y) //Ҹλ̹ - enemies[i].is_taken = true; - } - break; - default: - break; - } - } - else if (player.dir == LEFT) { - switch (TankMoveCheck(player.dir, player)) { //յ,з̹,ӵ,з̹,ǽ - case BLANK: - player.x--; - break; - case BULLET: - player.x--; - player.hp--; - for (int i = 0; i <= BULLET_NUM * ENEMIES_NUM; i++) { //ҳĿӵ䱨 - if (E_bullets[i].x == player.x && E_bullets[i].y == player.y) { - E_bullets[i].is_live = false; - } - } - break; - case BLUE_DEAD_TANK: - player.x--; - player.attack++; - if (player.hp < 5) player.hp++; - for (int i = 0; i < ENEMIES_NUM; i++) { //ѭ̹ - if (player.x == enemies[i].x && player.y == enemies[i].y) //Ҹλ̹ - enemies[i].is_taken = true; - } - break; - default: - break; - } - } - else if (player.dir == RIGHT) { - switch (TankMoveCheck(player.dir, player)) { //յ,з̹,ӵ,з̹,ǽ - case BLANK: - player.x++; - break; - case BULLET: - player.x++; - player.hp--; - for (int i = 0; i <= BULLET_NUM * ENEMIES_NUM; i++) { //ҳĿӵ䱨 - if (E_bullets[i].x == player.x && E_bullets[i].y == player.y) { - E_bullets[i].is_live = false; - } - } - break; - case BLUE_DEAD_TANK: - player.x++; - player.attack++; - if (player.hp < 5) player.hp++; - for (int i = 0; i < ENEMIES_NUM; i++) { //ѭ̹ - if (player.x == enemies[i].x && player.y == enemies[i].y) //Ҹλ̹ - enemies[i].is_taken = true; - } - break; - default: - break; - } - } -}//ײǽ͵з̹̹˲ƶ޸ - -/* - ˣɥɥ - ܣ̹ײ⣺Ƿǽз̹ˡз̹ˡյ - ԲͬвͬĴ - 0->յء1->ʾǽ2->̹ˡ3->̹ˡ4->̹ - һλõ꣨player.dir㣩ʲô -*/ -int TankMoveCheck(int dir, tank tank) { //̹ܷƶ,ؼλô洢öֵ - int ret = 0; // ĬϷֵΪ 0 - switch (dir) { - case UP: - return map[tank.x][tank.y - 1]; - break; - case DOWN: - return map[tank.x][tank.y + 1]; - break; - case LEFT: - return map[tank.x - 1][tank.y]; - break; - case RIGHT: - return map[tank.x + 1][tank.y]; - break; - default: // ĬϷ֧ - break; - } - return ret; -} - -/* - ˣ - ܣӵ飬ÿһӵд - ȿ϶üĩ״̬λã12-1512131415 - ӵײ⣺Ƿǽз̹ˡз̹ˡӵзӵյء̹ˡ -*/ - -/* - ˣ -*/ -int BulletMoveCheck(int dir, bullet bul) //صǰĿmapֵ -{ - int ret = 0; // ĬϷֵΪ 0 - switch (dir) { - case UP: - return map[bul.x][bul.y - 1]; - break; - case DOWN: - return map[bul.x][bul.y + 1]; - break; - case LEFT: - return map[bul.x - 1][bul.y]; - break; - case RIGHT: - return map[bul.x + 1][bul.y]; - break; - default: // ĬϷ֧ - return ret; - break; - } -} - -/* - ˣɥɥ - ܣ - ƶwasd4ȡģ0123 - ֮-жһλõ״̬ȻӦ - ʱƶı䷽жϵƶĿʵֵƶ -*/ -void EnemiesMove() { //ؿ - static clock_t start = clock() - 1000; - if((clock() - start) < 1000) - return; - start = clock(); - for (int i = 0; i < ENEMIES_NUM; ++i) { //nз̹ƶ - if (enemies[i].hp <= 0) - continue; - int dir = rand() % 4; //ɵз̹˵ƶ - if (dir == UP) { //0 - enemies[i].dir = UP; // ǰ enemies[i] ķ - switch (TankMoveCheck(dir, enemies[i])) { //յ,з̹,ӵ,ǽ - case BLANK: - enemies[i].y--; - break; - case BULLET: - enemies[i].y--; - for (int i = 0; i < BULLET_NUM; i++) { //ӵ - if (P_bullets[i].x == enemies[i].x && P_bullets[i].y == enemies[i].y) { - P_bullets[i].is_live = false; - enemies[i].hp--; - } - } - break; - } - } - else if (dir == DOWN) { //1 - enemies[i].dir = DOWN; - switch (TankMoveCheck(dir, enemies[i])) { //յ,з̹,ӵ,ǽ - case BLANK: - enemies[i].y++; - break; - case BULLET: - enemies[i].y++; - for (int i = 0; i < BULLET_NUM; i++) { //ӵ - if (P_bullets[i].x == enemies[i].x && P_bullets[i].y == enemies[i].y) { - P_bullets[i].is_live = false; - enemies[i].hp--; - } - } - break; - } - } - else if (dir == LEFT) { //2 - enemies[i].dir = LEFT; - switch (TankMoveCheck(dir, enemies[i])) { //յ,з̹,ӵǽ - case BLANK: - enemies[i].x--; - break; - case BULLET: - enemies[i].x--; - for (int i = 0; i < BULLET_NUM; i++) { //ӵ - if (P_bullets[i].x == enemies[i].x && P_bullets[i].y == enemies[i].y) { - P_bullets[i].is_live = false; - enemies[i].hp--; - } - } - break; - } - } - else if (dir == RIGHT) { //3 - enemies[i].dir = RIGHT; - switch (TankMoveCheck(dir, enemies[i])) { //յ,з̹,ӵ,ǽ - case BLANK: - enemies[i].x++; - break; - case BULLET: - enemies[i].x++; - for (int i = 0; i < BULLET_NUM; i++) { //ӵ - if (P_bullets[i].x == enemies[i].x && P_bullets[i].y == enemies[i].y) { - P_bullets[i].is_live = false; - enemies[i].hp--; - } - } - break; - } - } - } -} - -/* - ˣ - ܣ - շBulletMoveCheck() -ķֵжӵƶ - ʵӵƶ -*/ - -void PlayerBulletMove() { - static clock_t start = clock() - 100; - if ((clock() - start) < 100) - return; - start = clock(); - - int arr[4][2] = { - {0, -1}, - {0, 1}, - {-1, 0}, - {1, 0}, - }; - for (int i = 0; i < BULLET_NUM; i++) // ӵ - { - if (P_bullets[i].is_live == false) - { - continue; - } - else - { - // ӵײ⣺Ƿյءǽ̹ˡз̹ˡз̹ˡӵзӵ - // 0->յء1->ʾǽ2->̹ˡ3->̹ˡ4->̹ˡ5->ҷӵ6->зӵ - // 0 յ 1 ǽ 3 з̹ 6 зӵ - int type = BulletMoveCheck(P_bullets[i].dir, P_bullets[i]); - if (type == BLANK) - { - P_bullets[i].x += arr[P_bullets[i].dir][0]; - P_bullets[i].y += arr[P_bullets[i].dir][1]; - } - else if (type == WALL) - { - P_bullets[i].is_live = false; - } - else if (type == BLUE_TANK) //з̹ - { - P_bullets[i].is_live = false; //ӵ - for (int k = 0; k < ENEMIES_NUM; k++) //̹˱ - { - switch (P_bullets[i].dir) { - case UP: - if (enemies[k].x == P_bullets[i].x && enemies[k].y == P_bullets[i].y - 1) //Ϸз̹ - { - enemies[k].hp -= P_bullets[i].damage; - } - break; - case DOWN: - if (enemies[k].x == P_bullets[i].x && enemies[k].y == P_bullets[i].y + 1) //Ϸз̹ - { - enemies[k].hp -= P_bullets[i].damage; - } - break; - case LEFT: - if (enemies[k].x == P_bullets[i].x - 1 && enemies[k].y == P_bullets[i].y) //Ϸз̹ - { - enemies[k].hp -= P_bullets[i].damage; - } - break; - case RIGHT: - if (enemies[k].x == P_bullets[i].x + 1 && enemies[k].y == P_bullets[i].y) //Ϸз̹ - { - enemies[k].hp -= P_bullets[i].damage; - } - break; - default: // ĬϷ֧ - break; - } - - } - } - else - { - P_bullets[i].is_live = false; - if (BULLET_NUM == 2) - { - for (int k = 3; k <= 8; k++) - { - if (P_bullets[k].x == P_bullets[i].x && P_bullets[k].y == P_bullets[i].y) - { - P_bullets[k].is_live = false; - break; - } - } - } - else - { - for (int k = 3; k <= 12; k++) - { - if (P_bullets[k].x == P_bullets[i].x && P_bullets[k].y == P_bullets[i].y) - { - P_bullets[k].is_live = false; - break; - } - } - } - break; - } - } - } -} - -void EnemyBulletMove() { - static clock_t start = clock() - 500; - if ((clock() - start) < 500) - return; - start = clock(); - - int arr[4][2] = { - {0, -1}, - {0, 1}, - {-1, 0}, - {1, 0}, - }; - for (auto& i : E_bullets) { - if (i.is_live) { - int type = BulletMoveCheck(i.dir, i); - if (type == BLANK) - { - i.x += arr[i.dir][0]; - i.y += arr[i.dir][1]; - } - else if (type == WALL) - { - i.is_live = false; - } - else if (type == RED_TANK) - { - i.is_live = false; - player.hp -= i.damage; - } - else { - i.x += arr[i.dir][0]; - i.y += arr[i.dir][1]; - } - /*else - { - i.is_live = false; - if (BULLET_NUM == 2) - { - for (int k = 3; k <= 8; k++) - { - if (P_bullets[k].x == i.x && P_bullets[k].y == i.y) - { - P_bullets[k].is_live = false; - break; - } - } - } - else - { - for (int k = 3; k <= 12; k++) - { - if (P_bullets[k].x == i.x && P_bullets[k].y == i.y) - { - P_bullets[k].is_live = false; - break; - } - } - } - break; - }*/ - } - } -} -/* - ˣ - ܣ̹ -*/ -void PlayerInit() -{ - player.x = MAP_CELL_NUM / 2; // ʼ - player.y = MAP_CELL_NUM / 2; - player.hp = 5; // Ѫʼ - player.dir = UP; // ʼҷ - player.attack = 5; // ʼҹΪ 5 - kill = 0; // ҳʼɱΪ 0 - map[player.x][player.y] = RED_TANK; // ڵͼϱ̹˵λ -} - -/* - ˣ - ܣɵз̹ -*/ -void EnemyInit() -{ - srand((unsigned int)time(NULL)); // - // ʹ ⴴ - //default_random_engine generator; - //uniform_int_distribution distribution(0, 49); // һȷֲɵΧ1-48 - - // ʼ̹ - for (int i = 0; i < ENEMIES_NUM; i++) { - enemies[i].x = rand() % (MAP_CELL_NUM - 2) + 1 ; // ʹ - enemies[i].y = rand() % (MAP_CELL_NUM - 2) + 1; - - // ɵλѾ̹˻ǽô - while (map[enemies[i].x][enemies[i].y] != BLANK) { - enemies[i].x = rand() % (MAP_CELL_NUM - 2) + 1; - enemies[i].y = rand() % (MAP_CELL_NUM - 2) + 1; - } - - enemies[i].hp = enemy.hp; // ˳ʼѪΪ5 - enemies[i].attack = enemy.attack; // ˳ʼΪ1 - enemies[i].dir = LEFT; // ˳ʼ泯 - map[enemies[i].x][enemies[i].y] = BLUE_TANK; // ڵͼϱǵλ - } -} - -/* - ˣ - ܣ - ֵΪ:˵ʧܣ̹hp<=0߻û棺̹hp>0,з̹>0 - ֵΪ棺˵Ӯ ̹hp==0,з̹==0 -*/ -bool IsWin() { - bool all_die = true; - for (auto& i : enemies) { - if (i.hp > 0) - all_die = false; - } - if (player.hp > 0 && all_die) { - return true; // ʤ - } - else return false; // ûʤʧܡ ϷС -} - -// -void Level() -{ - cleardevice(); - IMAGE img_memberview; - loadimage(&img_memberview, ".//images//Ϸ汳.jpg", 700, 700); - putimage(0, 0, &img_memberview); - - IMAGE img_easy; - loadimage(&img_easy, ".//images//Ѷ.jpg", 150, 100); - putimage(275, 150, &img_easy); - - IMAGE img_middle; - loadimage(&img_middle, ".//images//еѶ.jpg", 150, 100); - putimage(275, 300, &img_middle); - - IMAGE img_difficult; - loadimage(&img_difficult, ".//images//Ѷ.jpg", 150, 100); - putimage(275, 450, &img_difficult); - - //̲ - ExMessage msg; - while (true) - { - //̲ - if (_kbhit()) - { - char key = _getch();//һֱ - //printf("%d,%c\n", key, key); - switch (key) - { - case 27://ϼ - //ز˵ - MenuView(); - //printf("ز˵/n"); - return; - break; - } - } - - // - if (peekmessage(&msg, WH_MOUSE)) - { - switch (msg.message) - { - case WM_LBUTTONDOWN: - - //ѡѶ - if (msg.x >= 275 && msg.x <= 425 && msg.y >= 150 && msg.y <= 250) - { - enemy.hp = 5; - enemy.attack = 1; - //printf("Ѷ\n"); - MenuView(); - //printf("ز˵/n"); - return; - } - //ѡеѶ - if (msg.x >= 275 && msg.x <= 425 && msg.y >= 300 && msg.y <= 400) - { - enemy.hp = 10; - enemy.attack = 2; - //printf("еѶ\n"); - MenuView(); - //printf("ز˵/n"); - return; - } - //ѡѶ - if (msg.x >= 275 && msg.x <= 425 && msg.y >= 450 && msg.y <= 550) - { - enemy.hp = 15; - enemy.attack = 3; - //printf("Ѷ\n"); - MenuView(); - //printf("ز˵/n"); - return; - } - break; - default: - break; - } - } - } -} - -// -void MemberView() -{ - cleardevice(); - IMAGE img_memberview; - loadimage(&img_memberview, ".//images//Ա.jpg", 700, 700); - putimage(0, 0, &img_memberview); - - IMAGE img_back; - loadimage(&img_back, ".//images//ذť.jpg", 150, 50); - putimage(30, 550, &img_back); - // - ExMessage msg; - while (true) - { - //̲ - if (_kbhit()) - { - char key = _getch();//һֱ - //printf("%d,%c\n", key, key); - switch (key) - { - case 27://ϼ - //ز˵ - MenuView(); - //printf("ز˵/n"); - return; - break; - } - } - - // - if (peekmessage(&msg, WH_MOUSE)) - { - switch (msg.message) - { - case WM_LBUTTONDOWN: - - //ص˵ - if (msg.x >= 30 && msg.x <= 180 && msg.y >= 550 && msg.y <= 600) - { - MenuView(); - return; - //printf("ص˵\n"); - //תѶȽ - } - break; - default: - break; - } - } - } -} - -// -void MenuView() -{ - InitMap(); - cleardevice(); - //ͼƬ - setbkmode(TRANSPARENT); - IMAGE img_menuview; - loadimage(&img_menuview, ".//images//˵.jpg", 700, 700); - putimage(0, 0, &img_menuview); - - IMAGE img_start; - loadimage(&img_start, ".//images//ʼϷ.jpg", 150, 50); - putimage(50, 250, &img_start); - - IMAGE img_level; - loadimage(&img_level, ".//images//Ѷð.jpg", 150, 50); - putimage(50, 330, &img_level); - - IMAGE img_member; - loadimage(&img_member, ".//images//Ա.jpg", 150, 50); - putimage(50, 410, &img_member); - - IMAGE img_quit; - loadimage(&img_quit, ".//images//˳Ϸ.jpg", 150, 50); - putimage(50, 490, &img_quit); - // - ExMessage msg; - while (true) - { - - // - if (peekmessage(&msg, WH_MOUSE)) - { - switch (msg.message) - { - case WM_LBUTTONDOWN: - - //תϷ - if (msg.x >= 50 && msg.x <= 200 && msg.y >= 250 && msg.y <= 300) - { - GameView(); - //printf("ʼϷ\n"); - } - //תѶȽ - if (msg.x >= 50 && msg.x <= 200 && msg.y >= 330 && msg.y <= 380) - { - Level(); - return; - //printf("Ѷ\n"); - } - //תԱ - if (msg.x >= 50 && msg.x <= 200 && msg.y >= 410 && msg.y <= 460) - { - MemberView(); - return; - //printf("Ա\n"); - } - //Ϸ - if (msg.x >= 50 && msg.x <= 200 && msg.y >= 490 && msg.y <= 540) - { - exit(0); - } - break; - default: - break; - } - } - } -} - -void change() -{ - //ȡھ - HWND hnd = GetHWnd(); - //ôڱ - SetWindowText(hnd, "ֽ̹"); -} - - -//-------------------service--------------- - -/* - ˣɥɥ -*/ int main() { - // bgm - //PlaySound(LPWSTR(IDR_WAVE1), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC | SND_LOOP); - PlaySound(MAKEINTRESOURCE(IDR_WAVE1), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC | SND_LOOP); - - // ---------------------- - // - initgraph(700, 700); - change(); - - MenuView(); - - getchar(); - //رմ - closegraph(); - - return 0; -} \ No newline at end of file + Game game; + return game.run(); +} diff --git a/tank_battles_on_the_scrap_paper/map.cpp b/tank_battles_on_the_scrap_paper/map.cpp deleted file mode 100644 index bc78e00..0000000 --- a/tank_battles_on_the_scrap_paper/map.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// map.cpp -#include "map.h" - -// ͼ -int map1[50][50]; -int map2[50][50]; - -void init_map1() -{ - for (int i = 0; i < 50; i++) - { - for (int j = 0; j < 50; j++) - { - // Ϊǽ - if (i == 0 || i == 49 || j == 0 || j == 49) - { - map1[i][j] = WALL; - } - // м+״ - else if (i == 24 || j == 24) - { - map1[i][j] = WALL; - } - else - { - map1[i][j] = BLANK; - } - } - } -} - -void init_map2() -{ - for (int i = 0; i < 50; i++) - { - for (int j = 0; j < 50; j++) - { - // Ϊǽ - if (i == 0 || i == 49 || j == 0 || j == 49) - { - map2[i][j] = WALL; - } - // мX״ - else if (i == j || i + j == 49) - { - map2[i][j] = WALL; - } - else - { - map2[i][j] = BLANK; - } - } - } -} diff --git a/tank_battles_on_the_scrap_paper/map.h b/tank_battles_on_the_scrap_paper/map.h deleted file mode 100644 index 580b357..0000000 --- a/tank_battles_on_the_scrap_paper/map.h +++ /dev/null @@ -1,16 +0,0 @@ -// ԤƵͼ -// map.h -#ifndef MAP_H -#define MAP_H - -#include "data_config.h" - -// ͼ -extern int map1[50][50]; -extern int map2[50][50]; - -// ͼʼ -void init_map1(); -void init_map2(); - -#endif // !MAP_H diff --git a/tank_battles_on_the_scrap_paper/resource.h b/tank_battles_on_the_scrap_paper/resource.h deleted file mode 100644 index 6964a71..0000000 --- a/tank_battles_on_the_scrap_paper/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ ɵİļ -// resource.rc ʹ -// -#define IDR_WAVE1 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/tank_battles_on_the_scrap_paper/resource.rc b/tank_battles_on_the_scrap_paper/resource.rc deleted file mode 100644 index ada8777..0000000 Binary files a/tank_battles_on_the_scrap_paper/resource.rc and /dev/null differ diff --git a/tank_battles_on_the_scrap_paper/src/AssetManager.cpp b/tank_battles_on_the_scrap_paper/src/AssetManager.cpp new file mode 100644 index 0000000..2852b82 --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/AssetManager.cpp @@ -0,0 +1,52 @@ +#include "AssetManager.h" +#include + +AssetManager::AssetManager(SDL_Renderer* r) : renderer(r) {} + +AssetManager::~AssetManager() { + for (auto& [_, tex] : textures) + SDL_DestroyTexture(tex); + if (font) TTF_CloseFont(font); + if (bgm) { Mix_HaltMusic(); Mix_FreeMusic(bgm); } +} + +SDL_Texture* AssetManager::getTexture(const std::string& path) { + auto it = textures.find(path); + if (it != textures.end()) + return it->second; + + SDL_Surface* surf = IMG_Load(path.c_str()); + if (!surf) { + fprintf(stderr, "IMG_Load error: %s - %s\n", path.c_str(), IMG_GetError()); + return nullptr; + } + SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, surf); + SDL_FreeSurface(surf); + if (tex) { + SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND); + } else { + fprintf(stderr, "CreateTexture error: %s - %s\n", path.c_str(), SDL_GetError()); + return nullptr; + } + textures[path] = tex; + return tex; +} + +bool AssetManager::loadFont(const char* path, int size) { + font = TTF_OpenFont(path, size); + if (font) { + printf("Loaded font: %s\n", path); + return true; + } + return false; +} + +bool AssetManager::loadBGM(const char* path) { + bgm = Mix_LoadMUS(path); + if (bgm) { + Mix_PlayMusic(bgm, -1); + return true; + } + fprintf(stderr, "BGM load failed: %s\n", Mix_GetError()); + return false; +} diff --git a/tank_battles_on_the_scrap_paper/src/AssetManager.h b/tank_battles_on_the_scrap_paper/src/AssetManager.h new file mode 100644 index 0000000..714d912 --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/AssetManager.h @@ -0,0 +1,30 @@ +#ifndef ASSET_MANAGER_H +#define ASSET_MANAGER_H + +#include +#include +#include +#include +#include +#include + +class AssetManager { +public: + AssetManager(SDL_Renderer* renderer); + ~AssetManager(); + + SDL_Texture* getTexture(const std::string& path); + TTF_Font* getFont() const { return font; } + Mix_Music* getBGM() const { return bgm; } + + bool loadFont(const char* path, int size); + bool loadBGM(const char* path); + +private: + SDL_Renderer* renderer; + std::unordered_map textures; + TTF_Font* font = nullptr; + Mix_Music* bgm = nullptr; +}; + +#endif diff --git a/tank_battles_on_the_scrap_paper/src/Bullet.cpp b/tank_battles_on_the_scrap_paper/src/Bullet.cpp new file mode 100644 index 0000000..e3475b4 --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/Bullet.cpp @@ -0,0 +1,15 @@ +#include "Bullet.h" +#include "Tank.h" + +void Bullet::fire(int bx, int by, Direction d, int dmg) { + x = bx; y = by; dir = d; damage = dmg; isLive = true; +} + +CELL_Type Bullet::peekAt(int map[MAP_CELL_NUM][MAP_CELL_NUM]) const { + return static_cast(map[x + dx(dir)][y + dy(dir)]); +} + +void Bullet::step() { + x += dx(dir); + y += dy(dir); +} diff --git a/tank_battles_on_the_scrap_paper/src/Bullet.h b/tank_battles_on_the_scrap_paper/src/Bullet.h new file mode 100644 index 0000000..1e4e6da --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/Bullet.h @@ -0,0 +1,18 @@ +#ifndef BULLET_H +#define BULLET_H + +#include "../data_config.h" + +class Bullet { +public: + int x = 0, y = 0; + int damage = 0; + Direction dir = UP; + bool isLive = false; + + void fire(int bx, int by, Direction d, int dmg); + CELL_Type peekAt(int map[MAP_CELL_NUM][MAP_CELL_NUM]) const; + void step(); +}; + +#endif diff --git a/tank_battles_on_the_scrap_paper/src/Game.cpp b/tank_battles_on_the_scrap_paper/src/Game.cpp new file mode 100644 index 0000000..6f8a35c --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/Game.cpp @@ -0,0 +1,451 @@ +#include "Game.h" +#include "Tank.h" +#include "UI.h" +#include +#include +#include +#include +#include + +Game::Game() { + std::srand(static_cast(std::time(nullptr))); + playerBullets.resize(MAX_PLAYER_BULLETS); + enemyBullets.resize(MAX_ENEMY_BULLETS); + enemies.resize(ENEMIES_NUM); +} + +Game::~Game() { + delete render; + delete assets; + if (sdlRenderer) SDL_DestroyRenderer(sdlRenderer); + if (window) SDL_DestroyWindow(window); + Mix_CloseAudio(); + TTF_Quit(); + IMG_Quit(); + SDL_Quit(); +} + +bool Game::initSDL() { + char* base = SDL_GetBasePath(); + if (base) { chdir(base); SDL_free(base); } + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { + fprintf(stderr, "SDL init failed: %s\n", SDL_GetError()); + return false; + } + if (!(IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG) & (IMG_INIT_PNG | IMG_INIT_JPG))) { + fprintf(stderr, "SDL_image init failed: %s\n", IMG_GetError()); + return false; + } + if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) { + fprintf(stderr, "SDL_mixer init failed: %s\n", Mix_GetError()); + return false; + } + if (TTF_Init() < 0) { + fprintf(stderr, "SDL_ttf init failed: %s\n", TTF_GetError()); + return false; + } + + window = SDL_CreateWindow("纸牌坦克", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + WINDOW_W, WINDOW_H, SDL_WINDOW_SHOWN); + if (!window) { fprintf(stderr, "Window failed: %s\n", SDL_GetError()); return false; } + + sdlRenderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (!sdlRenderer) { fprintf(stderr, "Renderer failed: %s\n", SDL_GetError()); return false; } + + assets = new AssetManager(sdlRenderer); + render = new Renderer(sdlRenderer, assets); + + const char* fontPaths[] = { + "/usr/share/fonts/wqy-microhei-fonts/wqy-microhei.ttc", + "/usr/share/fonts/wqy-zenhei-fonts/wqy-zenhei.ttc", + "/usr/share/fonts/google-noto-sans-cjk-vf-fonts/NotoSansCJK-VF.ttc", + "/usr/share/fonts/google-noto-serif-cjk-vf-fonts/NotoSerifCJK-VF.ttc", + nullptr + }; + bool fontOk = false; + for (int i = 0; fontPaths[i]; i++) { + if (assets->loadFont(fontPaths[i], 30)) { fontOk = true; break; } + } + if (!fontOk) fprintf(stderr, "Warning: no Chinese font found\n"); + + assets->loadBGM("music/bgm.wav"); + + lastPlayerMove = lastPlayerShoot = lastEnemyMove = lastEnemyShoot = 0; + lastBulletMove = lastEnemyBulletMove = 0; + return true; +} + +int Game::run() { + if (!initSDL()) return -1; + + scene = Scene::MENU; + SDL_Event e; + while (running) { + while (SDL_PollEvent(&e)) handleEvents(e); + update(); + renderScene(); + SDL_Delay(16); + } + return 0; +} + +// ------------------- event ------------------- + +void Game::handleEvents(SDL_Event& e) { + if (e.type == SDL_QUIT) { running = false; return; } + + if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) { + switch (scene) { + case Scene::LEVEL: + case Scene::MEMBER: + case Scene::GAME: + case Scene::WIN: + case Scene::LOSE: + scene = Scene::MENU; + map.reset(); + break; + default: break; + } + return; + } + + if (e.type != SDL_MOUSEBUTTONDOWN) return; + int mx = e.button.x, my = e.button.y; + + switch (scene) { + case Scene::MENU: + if (UI::hit(UI::BTN_START, mx, my)) { initGame(); scene = Scene::GAME; } + if (UI::hit(UI::BTN_LEVEL, mx, my)) { scene = Scene::LEVEL; } + if (UI::hit(UI::BTN_MEMBER, mx, my)) { scene = Scene::MEMBER; } + if (UI::hit(UI::BTN_QUIT, mx, my)) { running = false; } + break; + case Scene::LEVEL: + if (UI::hit(UI::BTN_EASY, mx, my)) { + enemyCfg.hp = 5; enemyCfg.attack = 1; scene = Scene::MENU; + } + if (UI::hit(UI::BTN_MEDIUM, mx, my)) { + enemyCfg.hp = 10; enemyCfg.attack = 2; scene = Scene::MENU; + } + if (UI::hit(UI::BTN_HARD, mx, my)) { + enemyCfg.hp = 15; enemyCfg.attack = 3; scene = Scene::MENU; + } + break; + case Scene::MEMBER: + if (UI::hit(UI::BTN_BACK, mx, my)) scene = Scene::MENU; + break; + case Scene::WIN: + case Scene::LOSE: + if (UI::hit(UI::BTN_BACK, mx, my)) scene = Scene::MENU; + break; + default: break; + } +} + +// ------------------- update ------------------- + +void Game::update() { + if (scene != Scene::GAME) return; + updateGame(); +} + +void Game::initGame() { + map.reset(); + killCount = 0; + + player = Tank(5, 5); + player.x = MAP_CELL_NUM / 2; + player.y = MAP_CELL_NUM / 2; + player.dir = UP; + + std::default_random_engine gen(std::random_device{}()); + std::uniform_int_distribution dist(1, MAP_CELL_NUM - 2); + + for (auto& e : enemies) { + do { + e.x = dist(gen); + e.y = dist(gen); + } while (map.get(e.x, e.y) != BLANK); + e.hp = enemyCfg.hp; + e.attack = enemyCfg.attack; + e.dir = LEFT; + e.isTaken = false; + map.set(e.x, e.y, BLUE_TANK); + } + + for (auto& b : playerBullets) b.isLive = false; + for (auto& b : enemyBullets) b.isLive = false; +} + +bool Game::isWin() const { + for (auto& e : enemies) + if (e.hp > 0) return false; + return player.hp > 0; +} + +void Game::updateGame() { + if (player.hp <= 0) { scene = Scene::LOSE; return; } + if (isWin()) { scene = Scene::WIN; return; } + + Uint32 now = SDL_GetTicks(); + + // --- 玩家移动 --- + const Uint8* keys = SDL_GetKeyboardState(nullptr); + bool moved = false; + if (keys[SDL_SCANCODE_W] || keys[SDL_SCANCODE_UP]) { player.dir = UP; moved = true; } + else if (keys[SDL_SCANCODE_S] || keys[SDL_SCANCODE_DOWN]) { player.dir = DOWN; moved = true; } + else if (keys[SDL_SCANCODE_A] || keys[SDL_SCANCODE_LEFT]) { player.dir = LEFT; moved = true; } + else if (keys[SDL_SCANCODE_D] || keys[SDL_SCANCODE_RIGHT]){ player.dir = RIGHT; moved = true; } + + if (moved && now - lastPlayerMove >= 100) { + lastPlayerMove = now; + int tx = player.x + dx(player.dir); + int ty = player.y + dy(player.dir); + CELL_Type c = map.get(tx, ty); + + if (c == BLANK) { + player.x = tx; player.y = ty; + } else if (c == BULLET) { + player.x = tx; player.y = ty; + player.hp--; + for (auto& b : enemyBullets) { + if (b.isLive && b.x == tx && b.y == ty) { b.isLive = false; break; } + } + } else if (c == BLUE_DEAD_TANK) { + player.x = tx; player.y = ty; + player.attack++; + if (player.hp < 5) player.hp++; + for (auto& e : enemies) { + if (e.hp <= 0 && !e.isTaken && e.x == tx && e.y == ty) { + e.isTaken = true; break; + } + } + } + } + + // --- 玩家射击 --- + if (keys[SDL_SCANCODE_SPACE] && now - lastPlayerShoot >= 500) { + lastPlayerShoot = now; + for (auto& b : playerBullets) { + if (!b.isLive) { + b.fire(player.x, player.y, player.dir, player.attack); + break; + } + } + } + + // --- 敌人移动 --- + if (now - lastEnemyMove >= 1000) { + lastEnemyMove = now; + for (auto& e : enemies) { + if (e.hp <= 0) continue; + Direction d = static_cast(rand() % 4); + e.dir = d; + int tx = e.x + dx(d); + int ty = e.y + dy(d); + CELL_Type c = map.get(tx, ty); + + if (c == BLANK) { + e.x = tx; e.y = ty; + } else if (c == BULLET) { + e.x = tx; e.y = ty; + e.hp--; + for (auto& pb : playerBullets) { + if (pb.isLive && pb.x == tx && pb.y == ty) { pb.isLive = false; break; } + } + } + } + } + + // --- 敌人射击 --- + if (now - lastEnemyShoot >= 3000) { + lastEnemyShoot = now; + for (auto& e : enemies) { + if (e.hp <= 0) continue; + for (auto& b : enemyBullets) { + if (!b.isLive) { + b.fire(e.x, e.y, e.dir, enemyCfg.attack); + break; + } + } + } + } + + // --- 玩家子弹移动 --- + if (now - lastBulletMove >= 100) { + lastBulletMove = now; + for (auto& b : playerBullets) { + if (!b.isLive) continue; + CELL_Type c = b.peekAt(map.grid); + + if (c == BLANK) { + b.step(); + } else if (c == WALL) { + b.isLive = false; + } else if (c == BLUE_TANK) { + b.isLive = false; + int tx = b.x + dx(b.dir), ty = b.y + dy(b.dir); + for (auto& e : enemies) { + if (e.hp > 0 && e.x == tx && e.y == ty) { e.hp -= b.damage; break; } + } + } else { + b.isLive = false; + } + } + } + + // --- 敌人子弹移动 --- + if (now - lastEnemyBulletMove >= 500) { + lastEnemyBulletMove = now; + for (auto& eb : enemyBullets) { + if (!eb.isLive) continue; + CELL_Type c = eb.peekAt(map.grid); + + if (c == BLANK) { + eb.step(); + } else if (c == WALL) { + eb.isLive = false; + } else if (c == RED_TANK) { + eb.isLive = false; + player.hp -= eb.damage; + } else { + eb.step(); + } + } + } + + // --- 同步地图 --- + map.reset(); + map.set(player.x, player.y, RED_TANK); + for (auto& e : enemies) { + if (e.hp > 0) + map.set(e.x, e.y, BLUE_TANK); + else if (!e.isTaken) + map.set(e.x, e.y, BLUE_DEAD_TANK); + } +} + +// ------------------- render ------------------- + +void Game::renderScene() { + render->clear(); + switch (scene) { + case Scene::MENU: renderMenu(); break; + case Scene::LEVEL: renderLevel(); break; + case Scene::MEMBER: renderMember(); break; + case Scene::GAME: renderGameView(); break; + case Scene::WIN: renderWin(); break; + case Scene::LOSE: renderLose(); break; + default: break; + } + render->present(); +} + +static SDL_Color GRAY = {157, 157, 157, 255}; + +void Game::renderMenu() { + render->drawImage("images/菜单界面.jpg", 0, 0, WINDOW_W, WINDOW_H); + render->drawImage("images/开始游戏按键.jpg", UI::BTN_START.x, UI::BTN_START.y, UI::BTN_START.w, UI::BTN_START.h); + render->drawImage("images/难度设置按键.jpg", UI::BTN_LEVEL.x, UI::BTN_LEVEL.y, UI::BTN_LEVEL.w, UI::BTN_LEVEL.h); + render->drawImage("images/相关人员按键.jpg", UI::BTN_MEMBER.x, UI::BTN_MEMBER.y, UI::BTN_MEMBER.w, UI::BTN_MEMBER.h); + render->drawImage("images/退出游戏按键.jpg", UI::BTN_QUIT.x, UI::BTN_QUIT.y, UI::BTN_QUIT.w, UI::BTN_QUIT.h); +} + +void Game::renderLevel() { + render->drawImage("images/游戏主界面背景.jpg", 0, 0, WINDOW_W, WINDOW_H); + render->drawImage("images/简单难度.jpg", UI::BTN_EASY.x, UI::BTN_EASY.y, UI::BTN_EASY.w, UI::BTN_EASY.h); + render->drawImage("images/中等难度.jpg", UI::BTN_MEDIUM.x, UI::BTN_MEDIUM.y, UI::BTN_MEDIUM.w, UI::BTN_MEDIUM.h); + render->drawImage("images/困难难度.jpg", UI::BTN_HARD.x, UI::BTN_HARD.y, UI::BTN_HARD.w, UI::BTN_HARD.h); +} + +void Game::renderMember() { + render->drawImage("images/开发人员界面.jpg", 0, 0, WINDOW_W, WINDOW_H); + render->drawImage("images/返回按钮.jpg", UI::BTN_BACK.x, UI::BTN_BACK.y, UI::BTN_BACK.w, UI::BTN_BACK.h); +} + +void Game::renderGameView() { + render->drawImage("images/游戏主界面背景.jpg", 0, 0, WINDOW_W, WINDOW_H); + + SDL_Texture* hpTex = assets->getTexture("images/red_hp_bar.jpg"); + for (int i = 0; i < player.hp; i++) + render->drawTexture(hpTex, UI::HP_BAR_X + i * CELL_SIZE, UI::HP_BAR_Y, CELL_SIZE, CELL_SIZE); + + int dieNum = 0; + for (auto& e : enemies) if (e.hp <= 0) dieNum++; + render->drawText("杀敌:", 110, 660, GRAY); + render->drawInt(dieNum, 185, 660, GRAY); + render->drawText("/10", 210, 660, GRAY); + std::string atk = "当前攻击力" + std::to_string(player.attack); + render->drawText(atk, 325, 660, GRAY); + + SDL_Texture* wallTex = assets->getTexture("images/wall.jpg"); + for (int i = 0; i < MAP_CELL_NUM; i++) + for (int j = 0; j < MAP_CELL_NUM; j++) + if (map.grid[i][j] == WALL) + render->drawTexture(wallTex, j * CELL_SIZE + X_OFFSET, i * CELL_SIZE + Y_OFFSET, CELL_SIZE, CELL_SIZE); + + // 子弹 + auto drawBullet = [&](Bullet& b) { + if (!b.isLive) return; + int sx = b.x * CELL_SIZE + X_OFFSET; + int sy = b.y * CELL_SIZE + Y_OFFSET; + bool horiz = (b.dir == LEFT || b.dir == RIGHT); + int tx = horiz ? sx : sx + 10; + int ty = horiz ? sy + 10 : sy; + int bw = horiz ? CELL_SIZE / 2 : CELL_SIZE / 4; + int bh = horiz ? CELL_SIZE / 4 : CELL_SIZE / 2; + const char* img = nullptr; + switch (b.dir) { + case UP: img = "images/B_UP_b.png"; break; + case DOWN: img = "images/B_DOWN_b.png"; break; + case LEFT: img = "images/B_LEFT_b.png"; break; + case RIGHT: img = "images/B_RIGHT_b.png"; break; + } + SDL_Texture* tex = assets->getTexture(img); + render->drawTexture(tex, tx, ty, bw, bh); + }; + + for (auto& b : playerBullets) drawBullet(b); + for (auto& b : enemyBullets) drawBullet(b); + + // 坦克 + auto drawTank = [&](Tank& t, bool isPlayer) { + int px = t.x * CELL_SIZE + X_OFFSET; + int py = t.y * CELL_SIZE + Y_OFFSET; + const char* img = nullptr; + if (isPlayer) { + switch (t.dir) { + case UP: img = "images/red_up_b.png"; break; + case DOWN: img = "images/red_down_b.png"; break; + case LEFT: img = "images/red_left_b.png"; break; + case RIGHT: img = "images/red_right_b.png"; break; + } + } else { + switch (t.dir) { + case UP: img = "images/blue_up_b.png"; break; + case DOWN: img = "images/blue_down_b.png"; break; + case LEFT: img = "images/blue_left_b.png"; break; + case RIGHT: img = "images/blue_right_b.png"; break; + } + } + render->drawTexture(assets->getTexture(img), px, py, CELL_SIZE, CELL_SIZE); + }; + + drawTank(player, true); + for (auto& e : enemies) { + if (e.isTaken) continue; + if (e.hp > 0) drawTank(e, false); + else render->drawTexture(assets->getTexture("images/dead_tank_b.png"), + e.x * CELL_SIZE + X_OFFSET, e.y * CELL_SIZE + Y_OFFSET, CELL_SIZE, CELL_SIZE); + } +} + +void Game::renderWin() { + render->drawImage("images/胜利.png", 0, 0, WINDOW_W, WINDOW_H); + render->drawImage("images/返回按钮.jpg", UI::BTN_BACK.x, UI::BTN_BACK.y, UI::BTN_BACK.w, UI::BTN_BACK.h); +} + +void Game::renderLose() { + render->drawImage("images/失败.png", 0, 0, WINDOW_W, WINDOW_H); + render->drawImage("images/返回按钮.jpg", UI::BTN_BACK.x, UI::BTN_BACK.y, UI::BTN_BACK.w, UI::BTN_BACK.h); +} diff --git a/tank_battles_on_the_scrap_paper/src/Game.h b/tank_battles_on_the_scrap_paper/src/Game.h new file mode 100644 index 0000000..cf3f3c3 --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/Game.h @@ -0,0 +1,62 @@ +#ifndef GAME_H +#define GAME_H + +#include +#include +#include "../data_config.h" +#include "Map.h" +#include "Tank.h" +#include "Bullet.h" +#include "AssetManager.h" +#include "Renderer.h" + +enum class Scene { MENU, LEVEL, MEMBER, GAME, WIN, LOSE, QUIT }; + +class Game { +public: + Game(); + ~Game(); + int run(); + +private: + SDL_Window* window = nullptr; + SDL_Renderer* sdlRenderer = nullptr; + AssetManager* assets = nullptr; + Renderer* render = nullptr; + + Scene scene = Scene::MENU; + bool running = true; + + Map map; + Tank player; + std::vector enemies; + std::vector playerBullets; + std::vector enemyBullets; + Tank enemyCfg; + int killCount = 0; + + // 计时 + Uint32 lastPlayerMove = 0, lastPlayerShoot = 0; + Uint32 lastEnemyMove = 0, lastEnemyShoot = 0; + Uint32 lastBulletMove = 0, lastEnemyBulletMove = 0; + + bool initSDL(); + bool initFont(); + void handleEvents(SDL_Event& e); + void update(); + void renderScene(); + + void initGame(); + void updateGame(); + + void renderMenu(); + void renderLevel(); + void renderMember(); + void renderGameView(); + void renderWin(); + void renderLose(); + + bool isWin() const; +}; + +#endif diff --git a/tank_battles_on_the_scrap_paper/src/Map.cpp b/tank_battles_on_the_scrap_paper/src/Map.cpp new file mode 100644 index 0000000..138a07f --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/Map.cpp @@ -0,0 +1,34 @@ +#include "Map.h" + +Map::Map() { + reset(); +} + +void Map::reset() { + for (int i = 0; i < MAP_CELL_NUM; i++) { + for (int j = 0; j < MAP_CELL_NUM; j++) { + if (i == 0 || i == MAP_CELL_NUM - 1 || j == 0 || j == MAP_CELL_NUM - 1) + grid[i][j] = WALL; + else + grid[i][j] = BLANK; + } + } +} + +CELL_Type Map::get(int x, int y) const { + return static_cast(grid[x][y]); +} + +void Map::set(int x, int y, CELL_Type type) { + grid[x][y] = type; +} + +CELL_Type Map::peek(int x, int y, Direction dir) const { + switch (dir) { + case UP: return static_cast(grid[x][y - 1]); + case DOWN: return static_cast(grid[x][y + 1]); + case LEFT: return static_cast(grid[x - 1][y]); + case RIGHT: return static_cast(grid[x + 1][y]); + } + return BLANK; +} diff --git a/tank_battles_on_the_scrap_paper/src/Map.h b/tank_battles_on_the_scrap_paper/src/Map.h new file mode 100644 index 0000000..67dfd9f --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/Map.h @@ -0,0 +1,17 @@ +#ifndef MAP_H +#define MAP_H + +#include "../data_config.h" + +class Map { +public: + int grid[MAP_CELL_NUM][MAP_CELL_NUM]; + + Map(); + void reset(); + CELL_Type get(int x, int y) const; + void set(int x, int y, CELL_Type type); + CELL_Type peek(int x, int y, Direction dir) const; +}; + +#endif diff --git a/tank_battles_on_the_scrap_paper/src/Renderer.cpp b/tank_battles_on_the_scrap_paper/src/Renderer.cpp new file mode 100644 index 0000000..d86ec21 --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/Renderer.cpp @@ -0,0 +1,40 @@ +#include "Renderer.h" + +Renderer::Renderer(SDL_Renderer* r, AssetManager* a) : renderer(r), assets(a) {} + +void Renderer::clear() { + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); +} + +void Renderer::present() { + SDL_RenderPresent(renderer); +} + +void Renderer::drawTexture(SDL_Texture* tex, int x, int y, int w, int h) { + if (!tex) return; + SDL_Rect dst = {x, y, w, h}; + SDL_RenderCopy(renderer, tex, nullptr, &dst); +} + +void Renderer::drawImage(const std::string& path, int x, int y, int w, int h) { + drawTexture(assets->getTexture(path), x, y, w, h); +} + +void Renderer::drawText(const std::string& text, int x, int y, SDL_Color color) { + TTF_Font* font = assets->getFont(); + if (!font || text.empty()) return; + SDL_Surface* surf = TTF_RenderUTF8_Blended(font, text.c_str(), color); + if (!surf) return; + SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, surf); + if (tex) { + SDL_Rect dst = {x, y, surf->w, surf->h}; + SDL_RenderCopy(renderer, tex, nullptr, &dst); + SDL_DestroyTexture(tex); + } + SDL_FreeSurface(surf); +} + +void Renderer::drawInt(int value, int x, int y, SDL_Color color) { + drawText(std::to_string(value), x, y, color); +} diff --git a/tank_battles_on_the_scrap_paper/src/Renderer.h b/tank_battles_on_the_scrap_paper/src/Renderer.h new file mode 100644 index 0000000..cdb93e4 --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/Renderer.h @@ -0,0 +1,25 @@ +#ifndef RENDERER_H +#define RENDERER_H + +#include +#include +#include +#include "AssetManager.h" + +class Renderer { +public: + Renderer(SDL_Renderer* r, AssetManager* a); + + void clear(); + void present(); + void drawTexture(SDL_Texture* tex, int x, int y, int w, int h); + void drawImage(const std::string& path, int x, int y, int w, int h); + void drawText(const std::string& text, int x, int y, SDL_Color color); + void drawInt(int value, int x, int y, SDL_Color color); + +private: + SDL_Renderer* renderer; + AssetManager* assets; +}; + +#endif diff --git a/tank_battles_on_the_scrap_paper/src/Tank.cpp b/tank_battles_on_the_scrap_paper/src/Tank.cpp new file mode 100644 index 0000000..348a49c --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/Tank.cpp @@ -0,0 +1,3 @@ +#include "Tank.h" + +Tank::Tank(int h, int a) : hp(h), attack(a) {} diff --git a/tank_battles_on_the_scrap_paper/src/Tank.h b/tank_battles_on_the_scrap_paper/src/Tank.h new file mode 100644 index 0000000..e85a167 --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/Tank.h @@ -0,0 +1,19 @@ +#ifndef TANK_H +#define TANK_H + +#include "../data_config.h" + +class Tank { +public: + int x = 0, y = 0; + int hp = 5, attack = 1; + Direction dir = UP; + bool isTaken = false; + + Tank(int h = 5, int a = 1); +}; + +inline int dx(Direction d) { return d == LEFT ? -1 : (d == RIGHT ? 1 : 0); } +inline int dy(Direction d) { return d == UP ? -1 : (d == DOWN ? 1 : 0); } + +#endif diff --git a/tank_battles_on_the_scrap_paper/src/UI.h b/tank_battles_on_the_scrap_paper/src/UI.h new file mode 100644 index 0000000..ce59453 --- /dev/null +++ b/tank_battles_on_the_scrap_paper/src/UI.h @@ -0,0 +1,32 @@ +#ifndef UI_H +#define UI_H + +#include + +namespace UI { + +inline bool hit(const SDL_Rect& r, int mx, int my) { + return mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h; +} + +// 菜单按钮 +constexpr SDL_Rect BTN_START = {50, 250, 150, 50}; +constexpr SDL_Rect BTN_LEVEL = {50, 330, 150, 50}; +constexpr SDL_Rect BTN_MEMBER = {50, 410, 150, 50}; +constexpr SDL_Rect BTN_QUIT = {50, 490, 150, 50}; + +// 难度按钮 +constexpr SDL_Rect BTN_EASY = {275, 150, 150, 100}; +constexpr SDL_Rect BTN_MEDIUM = {275, 300, 150, 100}; +constexpr SDL_Rect BTN_HARD = {275, 450, 150, 100}; + +// 返回按钮 +constexpr SDL_Rect BTN_BACK = {30, 550, 150, 50}; + +// HP 条 +constexpr int HP_BAR_X = 100; +constexpr int HP_BAR_Y = 10; + +} + +#endif diff --git a/tank_battles_on_the_scrap_paper/tank.h b/tank_battles_on_the_scrap_paper/tank.h deleted file mode 100644 index 9b020d1..0000000 --- a/tank_battles_on_the_scrap_paper/tank.h +++ /dev/null @@ -1,33 +0,0 @@ -// ̹˶ -#ifndef TANK_H -#define TANK_H - -/* - ̹ˣ - ꣺xy - Ѫhpʾǰ̹Ѫ - attackʾǰ̹˹ - dir - UP - DOWN - LEFT - RIGHT -*/ -enum Direction { - UP, // - DOWN, // - LEFT, // - RIGHT, // -}; - -struct tank { - int x, y;// - int hp; // Ѫ - int attack; // - int dir; // - bool is_taken = false;//̹ǷѾҼȡ - - tank(): attack(1), hp(5){} -}; - -#endif // !TANK_H diff --git a/tank_battles_on_the_scrap_paper/tank_battles_on_the_scrap_paper.vcxproj b/tank_battles_on_the_scrap_paper/tank_battles_on_the_scrap_paper.vcxproj deleted file mode 100644 index 4157d31..0000000 --- a/tank_battles_on_the_scrap_paper/tank_battles_on_the_scrap_paper.vcxproj +++ /dev/null @@ -1,147 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {ac8c4a04-1650-473c-8e9a-3b7cde2ad5cc} - tankbattlesonthescrappaper - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - MultiByte - - - Application - false - v143 - true - MultiByte - - - - - - - - - - - - - - - - - - - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tank_battles_on_the_scrap_paper/tank_battles_on_the_scrap_paper.vcxproj.filters b/tank_battles_on_the_scrap_paper/tank_battles_on_the_scrap_paper.vcxproj.filters deleted file mode 100644 index 97a5b30..0000000 --- a/tank_battles_on_the_scrap_paper/tank_battles_on_the_scrap_paper.vcxproj.filters +++ /dev/null @@ -1,46 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - 源文件 - - - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - - - 资源文件 - - - - - 资源文件 - - - \ No newline at end of file