diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fbb4e3..b17bdc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(SDL2_DIR D:/CLion 2022.1.3/bin/mingw/x86_64-w64-mingw32) include_directories(${SDL2_DIR}/include) link_directories(${SDL2_DIR}/bin) -add_executable(parkour main.c Rect_Queue.c Rect_Queue.h parameter.h load_resource.c load_resource.h Player_Action.c Player_Action.h Monster_Model.c Monster_Model.h collision.c collision.h score.c score.h record.c record.h) +add_executable(parkour main.c Rect_Queue.c Rect_Queue.h parameter.h Player_Action.c Player_Action.h Monster_Model.c Monster_Model.h collision.c collision.h score.c score.h record.c record.h) target_link_libraries(parkour mingw32 SDL2main SDL2 SDL2_image SDL2_ttf) diff --git a/Monster_Model.c b/Monster_Model.c index 4d7aac4..2b6c7e6 100644 --- a/Monster_Model.c +++ b/Monster_Model.c @@ -1,15 +1,28 @@ #include "Monster_Model.h" -void Destroy_Monster_Model(MonsterModel* model){ - SDL_DestroyTexture(model->texture); - SDL_FreeSurface(model->surface); +/** + * 释放怪物模型的内存 + * @param model 怪物模型的指针 + * @param n 该模型怪物的类型数量 + */ +void Destroy_Monster_Model(MonsterModel* model, int n){ + int i; + for(i = 0; i < n; i++){ + SDL_DestroyTexture(model->texture[i]); + SDL_FreeSurface(model->surface[i]); + } free(model); } +/** + * 绘制怪物 + * @param renderer 窗口的渲染器 + * @param model 怪物模型的数组 + * @param node 怪物的位置信息 + */ void Draw_Monster_Model(SDL_Renderer* renderer, MonsterModel* model[], RectNode* node){ - int monster_type = node->rect_type; - + int monster_type = node->rect_type, monster = node->monster; SDL_Rect rect = node->rect; - SDL_RenderCopy(renderer, model[monster_type]->texture, NULL, &rect); + SDL_RenderCopy(renderer, model[monster_type]->texture[monster], NULL, &rect); } diff --git a/Monster_Model.h b/Monster_Model.h index 6a6ee65..a86f928 100644 --- a/Monster_Model.h +++ b/Monster_Model.h @@ -4,13 +4,14 @@ #include "Rect_Queue.h" #ifndef PARKOUR_MONSTER_MODEL_H #define PARKOUR_MONSTER_MODEL_H +#define MAX_TYPE 3 + +/* 怪物模型,用于存储怪物的texture和surface */ typedef struct MonsterModel{ - SDL_Rect rect; - SDL_Texture* texture; - SDL_Surface* surface; + SDL_Texture* texture[MAX_TYPE]; + SDL_Surface* surface[MAX_TYPE]; }MonsterModel; -void Destroy_Monster_Model(MonsterModel* model); +void Destroy_Monster_Model(MonsterModel* model, int n); void Draw_Monster_Model(SDL_Renderer* renderer, MonsterModel* model[], RectNode* node); - #endif diff --git a/Player_Action.c b/Player_Action.c index 8d7c0cb..777775c 100644 --- a/Player_Action.c +++ b/Player_Action.c @@ -1,19 +1,33 @@ #include "Player_Action.h" +/** + * 创建一个PlayerAction结构体 + * @return 一个PlayerAction结构体 + */ PlayerAction* Create_Player_Action(){ PlayerAction* action = (PlayerAction*)malloc(sizeof(PlayerAction)); return action; } +/** + * 设置PlayerAction的surface + * @param action PlayerAction结构体指针 + * @param path_format 路径格式 + */ void Set_Player_Action_Surface(PlayerAction* action, char* path_format){ int i; for(i = 0; i < (action->nums_of_frames); i++) { char path[100]; - sprintf(path, path_format, i+1); - action->surface[i] = IMG_Load(path); + sprintf(path, path_format, i+1); /* 格式化路径 */ + action->surface[i] = IMG_Load(path); /* 加载图片 */ } } +/** + * 设置PlayerAction的texture + * @param action PlayerAction结构体指针 + * @param renderer 窗口的渲染器 + */ void Set_Player_Action_Texture(PlayerAction* action, SDL_Renderer* renderer){ int i; for(i = 0; i < action->nums_of_frames; i++) { @@ -21,6 +35,10 @@ void Set_Player_Action_Texture(PlayerAction* action, SDL_Renderer* renderer){ } } +/** + * 销毁PlayerAction结构体 + * @param action PlayerAction结构体指针 + */ void Destroy_Player_Action(PlayerAction* action){ int i; for(i = 0; i < action->nums_of_frames; i++) { @@ -31,6 +49,11 @@ void Destroy_Player_Action(PlayerAction* action){ } +/** + * 绘制PlayerAction + * @param renderer 窗口的渲染器 + * @param action PlayerAction结构体指针 + */ void Draw_Player_Action(SDL_Renderer* renderer, PlayerAction* action){ int frame = action->current_frame; diff --git a/Player_Action.h b/Player_Action.h index fc79e0b..44c32cb 100644 --- a/Player_Action.h +++ b/Player_Action.h @@ -5,12 +5,13 @@ #ifndef PARKOUR_PLAYER_ACTION_H #define PARKOUR_PLAYER_ACTION_H #define MAX_FRAMES 60 +/* 玩家动作,用于存储玩家动作的帧数、位置、texture和surface */ typedef struct PlayerAction{ - int nums_of_frames; - int current_frame; - SDL_Rect rect; - SDL_Texture* texture[MAX_FRAMES]; - SDL_Surface* surface[MAX_FRAMES]; + int nums_of_frames; /* 动作的总帧数 */ + int current_frame; /* 当前帧 */ + SDL_Rect rect; /* 动作的位置 */ + SDL_Texture* texture[MAX_FRAMES]; /* 动作的texture */ + SDL_Surface* surface[MAX_FRAMES]; /* 动作的surface */ }PlayerAction; PlayerAction* Create_Player_Action(); @@ -18,4 +19,4 @@ void Set_Player_Action_Texture(PlayerAction* action, SDL_Renderer* renderer); void Set_Player_Action_Surface(PlayerAction* action, char* path_format); void Destroy_Player_Action(PlayerAction* action); void Draw_Player_Action(SDL_Renderer* renderer, PlayerAction* action); -#endif //PARKOUR_PLAYER_ACTION_H +#endif diff --git a/Rect_Queue.c b/Rect_Queue.c index 92620da..09e64f6 100644 --- a/Rect_Queue.c +++ b/Rect_Queue.c @@ -2,6 +2,10 @@ #include #include "Rect_Queue.h" +/** + * 初始化队列 + * @return 返回一个队列的指针 + */ RectQueue* InitRectQueue() { RectQueue* queue = (RectQueue*)malloc(sizeof(RectQueue)); queue->front = queue->rear = NULL; @@ -9,16 +13,26 @@ RectQueue* InitRectQueue() { return queue; } -void EnRectQueue(RectQueue* queue, SDL_Rect rect, int rect_type) { +/** + * 入队 + * @param queue 队列的指针 + * @param rect 怪物的位置 + * @param rect_type 怪物的种类 + * @param monster 怪物的类型 + */ +void EnRectQueue(RectQueue* queue, SDL_Rect rect, int rect_type, int monster) { RectNode* node = (RectNode*)malloc(sizeof(RectNode)); node->rect = rect; node->rect_type = rect_type; node->is_passed = 0; node->next = NULL; + node->monster = monster; + if(queue->rear == NULL) { node->rect_index = 0; queue->front = queue->rear = node; - } else { + } + else { node->rect_index = queue->rear->rect_index + 1; queue->rear->next = node; queue->rear = node; @@ -26,13 +40,17 @@ void EnRectQueue(RectQueue* queue, SDL_Rect rect, int rect_type) { queue->size++; } +/** + * 出队 + * @param queue 队列的指针 + * @return 返回一个怪物节点的指针 + */ RectNode* DeRectQueue(RectQueue* queue) { if(queue->front == NULL) { printf("Error: DeRectQueue() failed, queue is empty"); exit(1); } RectNode* node = queue->front; - SDL_Rect rect = node->rect; queue->front = node->next; if(queue->front == NULL) { queue->rear = NULL; @@ -41,6 +59,10 @@ RectNode* DeRectQueue(RectQueue* queue) { return node; } +/** + * 销毁队列 + * @param queue 队列的指针 + */ void DestroyRectQueue(RectQueue* queue) { while(queue->front != NULL) { RectNode* node = queue->front; @@ -50,20 +72,27 @@ void DestroyRectQueue(RectQueue* queue) { free(queue); } +/** + * 创建怪物队列,生成初始怪物的节点 + * @param queue + */ void CreateMonsterRectQueue(RectQueue* queue){ - int i, rect_type; + int i, rect_type, monster; for(i = 0; i < NUMS_OF_MONSTER; i++) { - rect_type = rand() % 2; + rect_type = rand() % 2; /* 随机生成怪物的种类 */ + monster = random_monster(rect_type); /* 随机生成怪物的类型 */ + + /* 根据怪物的种类和类型,生成怪物的位置 */ switch (rect_type) { case MONSTER_GROUND: EnRectQueue(queue, (SDL_Rect) {500 + i * 400, MONSTER_GROUND_Y, MONSTER_GROUND_WIDTH, MONSTER_GROUND_HEIGHT}, - rect_type); + rect_type, monster); break; case MONSTER_AIR: EnRectQueue(queue, (SDL_Rect) {500 + i * 400, MONSTER_AIR_Y, MONSTER_AIR_WIDTH, MONSTER_AIR_HEIGHT}, - rect_type); + rect_type, monster); break; default: printf("error type"); @@ -72,21 +101,28 @@ void CreateMonsterRectQueue(RectQueue* queue){ } } +/** + * 填充怪物队列,生成新的怪物节点 + * @param queue + */ void FillMonsterRectQueue(RectQueue* queue){ - int rect_type, rand_distance_x, rand_distance_y; - rect_type = rand() % 10 < 8 ? MONSTER_GROUND : MONSTER_AIR; - rand_distance_x = rand() % 150 - 40; - rand_distance_y = rand() % 30 - 15; + int rect_type, rand_distance_x, rand_distance_y, monster; + rect_type = rand() % 10 < 8 ? MONSTER_GROUND : MONSTER_AIR; /* 随机生成怪物的种类,以0.8的概率生成地面怪物,0.2的概率生成空中怪物 */ + rand_distance_x = rand() % 150 - 40; /* 随机生成怪物的x坐标偏移量 */ + rand_distance_y = rand() % 30 - 15; /* 随机生成怪物的y坐标偏移量 */ + monster = random_monster(rect_type); /* 随机生成怪物的类型 */ + + /* 根据怪物的种类和类型,生成怪物的位置 */ switch (rect_type) { case MONSTER_GROUND: EnRectQueue(queue, (SDL_Rect) {500 + rand_distance_x, MONSTER_GROUND_Y + rand_distance_y, MONSTER_GROUND_WIDTH, MONSTER_GROUND_HEIGHT}, - rect_type); + rect_type, monster); break; case MONSTER_AIR: EnRectQueue(queue, (SDL_Rect) {500 + rand_distance_x, MONSTER_AIR_Y + rand_distance_y, MONSTER_AIR_WIDTH, MONSTER_AIR_HEIGHT}, - rect_type); + rect_type, monster); break; default: @@ -94,5 +130,16 @@ void FillMonsterRectQueue(RectQueue* queue){ } } +/** + * 随机生成怪物的类型 + * @param monster_type 怪物的种类 + * @return 返回怪物的类型 + */ +int random_monster(int monster_type){ + int monster, n; + n = monster_type == MONSTER_GROUND ? GROUND_TYPE : AIR_TYPE; + monster = rand() % n; + return monster; +} diff --git a/collision.c b/collision.c index d492d9c..9fa7614 100644 --- a/collision.c +++ b/collision.c @@ -1,8 +1,18 @@ #include "collision.h" +/** + * 获取指定(x,y)坐标的像素值 + * @param surface 获取像素值的目标surface + * @param x 像素的x坐标 + * @param y 像素的y坐标 + * @return 指定位置的像素值(Uint32) + */ Uint32 get_pixel(SDL_Surface* surface, int x, int y) { - int bpp = surface->format->BytesPerPixel; - Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * bpp; + + int bpp = surface->format->BytesPerPixel; /* 每个像素的字节数 */ + Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * bpp; /* 指向目标像素的指针 */ + + /* 根据不同的像素格式,进行不同的位运算 */ switch (bpp) { case 1: return *p; @@ -17,33 +27,58 @@ Uint32 get_pixel(SDL_Surface* surface, int x, int y) { } } +/** + * 两个矩形的碰撞检测 + * @param rect1 矩形1的位置 + * @param surface1 矩形1的surface + * @param rect2 矩形2的位置 + * @param surface2 矩形2的surface + * @return 是否相撞,1为相撞,0为不相撞 + */ int CollisionDetect(SDL_Rect rect1, SDL_Surface* surface1, SDL_Rect rect2, SDL_Surface* surface2){ - SDL_Rect intersect_rect; + SDL_Rect intersect_rect; /* 两个矩形的交集矩形 */ + Uint8 alpha1, alpha2, red1, red2, green1, green2, blue1, blue2; /* 两个矩形的像素的RGBA值 */ + + /* 如果两个矩形相交 */ if(SDL_IntersectRect(&rect1, &rect2, &intersect_rect)==SDL_TRUE) { int x, y; + for(y = intersect_rect.y; y < intersect_rect.y + intersect_rect.h; y++) { for(x = intersect_rect.x; x < intersect_rect.x + intersect_rect.w; x++) { + /* 获取两个矩形的交集矩形中的每个像素 */ Uint32 pixel1 = get_pixel(surface1, x - rect1.x, y - rect1.y); Uint32 pixel2 = get_pixel(surface2, x - rect2.x, y - rect2.y); - Uint8 alpha1, alpha2, red1, red2, green1, green2, blue1, blue2; + + /* 获取像素的RGBA值 */ SDL_GetRGBA(pixel1, surface1->format, &red1, &green1, &blue1, &alpha1); SDL_GetRGBA(pixel2, surface2->format, &red2, &green2, &blue2, &alpha2); + + /* 如果两个像素的alpha值都不为0,则两个矩形相交 */ if(alpha1 != 0 && alpha2 != 0) { return 1; } } } } + /* 如果两个矩形不相交 */ else{ return 0; } } +/** + * 玩家与怪物的碰撞检测 + * @param action 玩家的动作 + * @param state 玩家的状态 + * @param model 怪物的模型 + * @param node 怪物的位置 + * @return 是否相撞,1为相撞,0为不相撞 + */ int CollisionDetectPlayerMonster(PlayerAction* action[], int state, MonsterModel* model[], RectNode* node){ - int monster_type = node->rect_type; + int monster_type = node->rect_type, monster = node->monster; SDL_Rect rect = node->rect; - SDL_Surface* surface = model[monster_type]->surface; + SDL_Surface* surface = model[monster_type]->surface[monster]; SDL_Rect player_rect = action[state]->rect; SDL_Surface* player_surface = action[state]->surface[action[state]->current_frame]; return CollisionDetect(player_rect, player_surface, rect, surface); diff --git a/load_resource.c b/load_resource.c deleted file mode 100644 index 8c32506..0000000 --- a/load_resource.c +++ /dev/null @@ -1,71 +0,0 @@ -#include "load_resource.h" - -void Load_Karyl_Actions(SDL_Renderer* renderer, PlayerAction* Karyl_actions[]) { - int i; - - for(i = 0;i < NUMS_OF_STATE; i++){ - Karyl_actions[i] = Create_Player_Action(); - Karyl_actions[i]->current_frame = 0; - } - - Karyl_actions[STATE_RUN]->nums_of_frames = FRAMES_RUN; - Karyl_actions[STATE_JUMP]->nums_of_frames = FRAMES_JUMP; - Karyl_actions[STATE_DIE]->nums_of_frames = FRAMES_DIE; - - Karyl_actions[STATE_RUN]->rect = KARYL_RUN_RECT; - Karyl_actions[STATE_JUMP]->rect = KARYL_JUMP_RECT; - Karyl_actions[STATE_DIE]->rect = KARYL_DIE_RECT; - - Set_Player_Action_Surface(Karyl_actions[STATE_RUN], KARYL_RUN_PATH); - Set_Player_Action_Surface(Karyl_actions[STATE_JUMP], KARYL_JUMP_PATH); - Set_Player_Action_Surface(Karyl_actions[STATE_DIE], KARYL_DIE_PATH); - - Set_Player_Action_Texture(Karyl_actions[STATE_RUN], renderer); - Set_Player_Action_Texture(Karyl_actions[STATE_JUMP], renderer); - Set_Player_Action_Texture(Karyl_actions[STATE_DIE], renderer); -} - -void Reset_Karyl_Actions(PlayerAction* Karyl_actions[]) { - int i; - - for(i = 0; i < NUMS_OF_STATE; i++) { - Karyl_actions[i]->current_frame = 0; - } - - Karyl_actions[STATE_RUN]->rect = KARYL_RUN_RECT; - Karyl_actions[STATE_JUMP]->rect = KARYL_JUMP_RECT; - Karyl_actions[STATE_DIE]->rect = KARYL_DIE_RECT; - -} -void Destroy_Karyl_Actions(PlayerAction* Karyl_actions[]) { - int i; - - for(i = 0; i < NUMS_OF_STATE; i++) { - Destroy_Player_Action(Karyl_actions[i]); - } -} - -void Load_Monster_Model(SDL_Renderer* renderer, MonsterModel* monster_models[]) { - int i; - - for(i = 0; i < NUMS_OF_MONSTER; i++) { - monster_models[i] = (MonsterModel*)malloc(sizeof(MonsterModel)); - } - - monster_models[MONSTER_GROUND]->surface = IMG_Load(MONSTER_GROUND_PATH); - monster_models[MONSTER_AIR]->surface = IMG_Load(MONSTER_AIR_PATH); - - monster_models[MONSTER_GROUND]->texture = SDL_CreateTextureFromSurface(renderer, monster_models[MONSTER_GROUND]->surface); - monster_models[MONSTER_AIR]->texture = SDL_CreateTextureFromSurface(renderer, monster_models[MONSTER_AIR]->surface); - -} - -void Destroy_Monster_Models(MonsterModel* monster_model[]) { - int i; - - for(i = 0; i < NUMS_OF_MONSTER; i++) { - Destroy_Monster_Model(monster_model[i]); - } -} - - diff --git a/load_resource.h b/load_resource.h deleted file mode 100644 index 88464d9..0000000 --- a/load_resource.h +++ /dev/null @@ -1,18 +0,0 @@ -#include "SDL2/SDL_image.h" -#include "SDL2/SDL_ttf.h" -#include "Player_Action.h" -#include "Monster_Model.h" -#include "parameter.h" - -#ifndef PARKOUR_LOAD_RESOURCE_H -#define PARKOUR_LOAD_RESOURCE_H - -void Load_Karyl_Actions(SDL_Renderer* renderer, PlayerAction* Karyl_actions[]); -void Load_Monster_Model(SDL_Renderer* renderer, MonsterModel* monster_models[]); - -void Reset_Karyl_Actions(PlayerAction* Karyl_actions[]); - -void Destroy_Karyl_Actions(PlayerAction* Karyl_actions[]); -void Destroy_Monster_Models(MonsterModel* monster_model[]); - -#endif //PARKOUR_LOAD_RESOURCE_H diff --git a/main.c b/main.c index 32a2d63..7e899f1 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,5 @@ #include #include -#include #include #include "Rect_Queue.h" #include @@ -10,21 +9,22 @@ #include "parameter.h" #include "Player_Action.h" #include "Monster_Model.h" -#include "load_resource.h" +#include "manage.h" #include "collision.h" #include "score.h" #include "record.h" int DrawHomeScreen(SDL_Renderer* renderer); /* 游戏开始界面 */ -int DrawMainScreen(SDL_Renderer* renderer, int *record); /* 游戏主界面 */ +int DrawMainScreen(SDL_Renderer* renderer); /* 游戏主界面 */ void DrawGameOverScreen(SDL_Renderer* renderer, int score); /* 游戏结束界面 */ PlayerAction* Karyl_actions[NUMS_OF_STATE]; MonsterModel* monster_models[NUMS_OF_MONSTER]; +/* 主函数,控制程序整体运行 */ int main(int argc, char* argv[]) { - int signal = SIGNAL_CONTINUE, game_score = 0; + int signal = SIGNAL_CONTINUE; /* 信号,用于判断游戏的状态 */ srand((unsigned)time(NULL)); /* 初始化SDL */ @@ -38,73 +38,78 @@ int main(int argc, char* argv[]) { SDL_SetWindowIcon(window, icon); SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + /* 加载资源 */ Load_Karyl_Actions(renderer, Karyl_actions); Load_Monster_Model(renderer, monster_models); - /* 游戏开始界面 */ + /* 游戏循环 */ while(signal!=SIGNAL_QUIT){ + /* 游戏开始界面 */ signal = DrawHomeScreen(renderer); if (signal == SIGNAL_QUIT) { break; } /* 主游戏界面 */ - signal = DrawMainScreen(renderer, &game_score); + signal = DrawMainScreen(renderer); } + /* 释放资源 */ Destroy_Karyl_Actions(Karyl_actions); Destroy_Monster_Models(monster_models); - - /* 释放资源 */ SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_FreeSurface(icon); - /* 退出 */ IMG_Quit(); TTF_Quit(); SDL_Quit(); - return 0; } +/* 游戏开始界面 */ int DrawHomeScreen(SDL_Renderer* renderer) { TTF_Font* font = TTF_OpenFont("font/font.ttf", 80); /* 加载字体 */ - SDL_Surface* home_screen = IMG_Load("images/bg_home.png"); /* 加载背景 */ - SDL_Surface* logo = IMG_Load("images/logo.png"); /* 加载logo */ - SDL_Color color = {255, 51, 153, 255}; + /* 加载背景 */ + SDL_Surface* background = IMG_Load("images/bg_home.png"); + SDL_Texture* home_screen_texture = SDL_CreateTextureFromSurface(renderer, background); - SDL_Surface* title = TTF_RenderUTF8_Blended(font, "公 主 连 结 跑 酷", color); + /* 加载logo */ + SDL_Surface* logo = IMG_Load("images/logo.png"); + SDL_Texture* logo_texture = SDL_CreateTextureFromSurface(renderer, logo); - //更改字体大小 + /* 加载标题和提示语 */ + SDL_Surface* title = TTF_RenderUTF8_Blended(font, "公 主 连 结 跑 酷", TEXT_COLOR); TTF_SetFontSize(font, 40); - SDL_Surface* hint = TTF_RenderUTF8_Blended(font, "按ENTER开始游戏", (SDL_Color){255, 51, 153, 255}); - SDL_Texture* home_screen_texture = SDL_CreateTextureFromSurface(renderer, home_screen); - SDL_Texture* logo_texture = SDL_CreateTextureFromSurface(renderer, logo); + SDL_Surface* hint = TTF_RenderUTF8_Blended(font, "按ENTER开始游戏", TEXT_COLOR); - SDL_Rect home_screen_rect = {0, 0, 640, 480}; + /* 设置位置 */ + SDL_Rect background_rect = {0, 0, 640, 480}; SDL_Rect logo_rect = {190, 20, 250, 70}; SDL_Rect title_rect = {85, 100, title->w, title->h}; SDL_Rect hint_rect = {200, 250, hint->w, hint->h}; - SDL_RenderCopy(renderer, home_screen_texture, NULL, &home_screen_rect); + /* 渲染 */ + SDL_RenderCopy(renderer, home_screen_texture, NULL, &background_rect); SDL_RenderCopy(renderer, logo_texture, NULL, &logo_rect); SDL_RenderCopy(renderer, SDL_CreateTextureFromSurface(renderer, title), NULL, &title_rect); SDL_RenderCopy(renderer, SDL_CreateTextureFromSurface(renderer, hint), NULL, &hint_rect); - SDL_RenderPresent(renderer); - //按键检测 + + /* 事件循环 */ SDL_Event event; int signal = SIGNAL_CONTINUE; while(signal==SIGNAL_CONTINUE) { while(SDL_PollEvent(&event)) { + /* 退出 */ if(event.type == SDL_QUIT) { signal = SIGNAL_QUIT; } + /* 按下回车键 */ if(event.type == SDL_KEYDOWN) { if(event.key.keysym.sym == SDLK_RETURN) { signal = SIGNAL_NEXT; @@ -113,123 +118,144 @@ int DrawHomeScreen(SDL_Renderer* renderer) { } } + /* 释放资源 */ SDL_DestroyTexture(home_screen_texture); SDL_DestroyTexture(logo_texture); - - SDL_FreeSurface(home_screen); + SDL_FreeSurface(background); SDL_FreeSurface(logo); SDL_FreeSurface(title); + TTF_CloseFont(font); + return signal; } -int DrawMainScreen(SDL_Renderer* renderer, int* record){ - SDL_Surface* background = IMG_Load("images/bg.png"); - RectNode *node1 = NULL, *node2 = NULL; - RectQueue* queue = InitRectQueue(); +/* 游戏主界面 */ +int DrawMainScreen(SDL_Renderer* renderer){ + /* 设置状态 */ - SDL_Texture* background_texture = SDL_CreateTextureFromSurface(renderer, background); - SDL_Texture* background_repeat_texture = SDL_CreateTextureFromSurface(renderer, background); + int state = STATE_RUN; /* 人物动作状态 */ + int signal = SIGNAL_CONTINUE; /* 信号,用于判断游戏的状态 */ + int is_collision = 0; /* 是否碰撞 */ - CreateMonsterRectQueue(queue); - node1 = DeRectQueue(queue); - node2 = DeRectQueue(queue); + /* 加载背景,并创建重复背景 */ + SDL_Surface* background = IMG_Load("images/bg.png"); + SDL_Texture* background_texture = SDL_CreateTextureFromSurface(renderer, background); + SDL_Texture* background_repeat_texture = SDL_CreateTextureFromSurface(renderer, background); SDL_Rect background_rect = {0, 0, 640, 480}; SDL_Rect background_repeat_rect = {640, 0, 640, 480}; - SDL_Event event; - //设置状态 - int state = STATE_RUN; - int signal = SIGNAL_CONTINUE; - int is_collision = 0; + /* 绘制分数 */ + TTF_Font* font = TTF_OpenFont("font/font.ttf", 80); /*加载字体*/ + SDL_Color color = {255, 51, 153, 255}; /* 设置字体颜色 */ + Score* score = InitScore(); /* 初始化分数 */ + DrawScore(renderer, score, font, TEXT_COLOR); /* 渲染分数 */ - TTF_Font* font = TTF_OpenFont("font/font.ttf", 80); - SDL_Color color = {255, 51, 153, 255}; - - Score* score = InitScore(); - - DrawScore(renderer, score, font, color); + /* 创建怪物的位置队列 */ + RectQueue* queue = InitRectQueue(); + CreateMonsterRectQueue(queue); + /* 从队列中获取两个节点 */ + RectNode *node1 = NULL, *node2 = NULL; + node1 = DeRectQueue(queue); + node2 = DeRectQueue(queue); + SDL_Event event; while(signal==SIGNAL_CONTINUE || signal==SIGNAL_WAIT) { - - /* 事件处理 */ while(SDL_PollEvent(&event)) { - - /* 退出事件 */ + /* 退出 */ if(event.type == SDL_QUIT) { signal = SIGNAL_QUIT; } /* 键盘事件 */ if (event.type == SDL_KEYDOWN) { - /* 按下空格键,则改变角色状态 */ + /* 按下空格键,跃起,改变动作状态 */ if (event.key.keysym.sym == SDLK_SPACE && state == STATE_RUN) { state = STATE_JUMP; } } } + /* 渲染背景和怪物 */ SDL_RenderCopy(renderer, background_texture, NULL, &background_rect); SDL_RenderCopy(renderer, background_repeat_texture, NULL, &background_repeat_rect); Draw_Monster_Model(renderer, monster_models, node1); Draw_Monster_Model(renderer, monster_models, node2); + /* 渲染人物 + * 根据不同的状态,渲染不同的动作 + */ switch(state) { case STATE_RUN: Karyl_actions[STATE_RUN]->current_frame++; + + /* 如果当前帧数大于最大帧数,重置为0 */ if(Karyl_actions[STATE_RUN]->current_frame >= FRAMES_RUN) { Karyl_actions[STATE_RUN]->current_frame = 0; } Draw_Player_Action(renderer, Karyl_actions[STATE_RUN]); break; + case STATE_JUMP: Karyl_actions[STATE_JUMP]->current_frame++; - Karyl_actions[STATE_JUMP]->rect.y = 140 - JUMP_HEIGHT(Karyl_actions[STATE_JUMP]->current_frame); + Karyl_actions[STATE_JUMP]->rect.y = 140 - JUMP_HEIGHT(Karyl_actions[STATE_JUMP]->current_frame); /* 模拟重力,计算人物的y坐标 */ + + /* 如果当前帧数大于最大帧数,重置为0,并将状态重置为run */ if(Karyl_actions[STATE_JUMP]->current_frame >= FRAMES_JUMP) { Karyl_actions[STATE_JUMP]->current_frame = 0; - state = 0; + state = STATE_RUN; } Draw_Player_Action(renderer, Karyl_actions[STATE_JUMP]); break; + case STATE_DIE: Karyl_actions[STATE_DIE]->current_frame++; + + /* 如果当前帧数大于最大帧数,使动作保持在最后一帧,并将游戏状态改为跳转下一窗口 */ if(Karyl_actions[STATE_DIE]->current_frame >= FRAMES_DIE) { Karyl_actions[STATE_DIE]->current_frame = 24; signal = SIGNAL_NEXT; } Draw_Player_Action(renderer, Karyl_actions[STATE_DIE]); break; + default: break; } - //判断人物是否越过怪物 + + /* 如果人物越过怪物的位置,分数加1 */ if(state!=STATE_DIE && Karyl_actions[STATE_RUN]->rect.x >= node1->rect.x && node1->is_passed == 0) { node1->is_passed = 1; score->score++; } - + /* 绘制分数 */ DrawScore(renderer, score, font, color); SDL_RenderPresent(renderer); + /* 碰撞检测 */ is_collision = CollisionDetectPlayerMonster(Karyl_actions, state, monster_models, node1) ; + + /* 如果碰撞,改变游戏状态,进入死亡动画的绘制 */ if(is_collision == 1 && signal == SIGNAL_CONTINUE) { signal = SIGNAL_WAIT; state = STATE_DIE; } - - if(signal == SIGNAL_CONTINUE) { - //背景滚动并将右边的部分用background_repeat填充 + /* 如继续游戏,更新背景和怪物的位置 */ + else if(signal == SIGNAL_CONTINUE) { + /* 更新背景位置,并用重复背景填充空白 */ background_rect.x -= 3; background_repeat_rect.x -= 3; node1->rect.x -= 8; node2->rect.x -= 8; + + /* 如果背景移动到了最左边,将背景重置到最右边 */ if(background_rect.x <= -640) { background_rect.x = 640; } @@ -237,6 +263,7 @@ int DrawMainScreen(SDL_Renderer* renderer, int* record){ background_repeat_rect.x = 640; } + /* 如果怪物移动到了最左边,队列生成新的怪物,并传递给节点 */ if(node1->rect.x <= -100) { free(node1); FillMonsterRectQueue(queue); @@ -245,6 +272,7 @@ int DrawMainScreen(SDL_Renderer* renderer, int* record){ node2->rect.x += node1->rect.x; } } + /* 如果游戏结束,跳转到游戏结束界面 */ else if(signal == SIGNAL_NEXT) { DrawGameOverScreen(renderer, score->score); } @@ -253,6 +281,7 @@ int DrawMainScreen(SDL_Renderer* renderer, int* record){ } + /* 释放资源 */ free(node1); free(node2); DestroyRectQueue(queue); @@ -260,35 +289,41 @@ int DrawMainScreen(SDL_Renderer* renderer, int* record){ SDL_DestroyTexture(background_texture); SDL_DestroyTexture(background_repeat_texture); SDL_FreeSurface(background); + TTF_CloseFont(font); + /* 重载人物动作数组 */ Reset_Karyl_Actions(Karyl_actions); - return signal; } +/* 绘制游戏结束界面 */ void DrawGameOverScreen(SDL_Renderer* renderer, int score){ - int quit = 0, record = read_record(); - record = score > record ? score : record; - write_record(record); + int quit = 0; /* 退出标志 */ + int record = read_record(); /* 读取本地最高分 */ + + record = score > record ? score : record; /* 如果当前分数大于最高分,更新最高分 */ + write_record(record); /* 将最高分写入本地 */ + SDL_Surface* result = IMG_Load("images/text/result.png"); SDL_Surface* board = IMG_Load("images/text/board.png"); SDL_Texture* result_texture = SDL_CreateTextureFromSurface(renderer, result); SDL_Texture* board_texture = SDL_CreateTextureFromSurface(renderer, board); SDL_Rect result_rect = {225, 15, 200, 60}; SDL_Rect board_rect = {120, 80, 400, 220}; + TTF_Font *font = TTF_OpenFont("font/font.ttf", 40); SDL_Color color = {255, 51, 153, 255}; char score_str[25], record_str[25]; sprintf(score_str, "Score:%15d", score); sprintf(record_str, "Record:%15d", record); - SDL_Surface* score_surface = TTF_RenderText_Solid(font, score_str, color); + SDL_Surface* score_surface = TTF_RenderText_Solid(font, score_str, TEXT_COLOR); SDL_Texture* score_texture = SDL_CreateTextureFromSurface(renderer, score_surface); - SDL_Surface* record_surface = TTF_RenderText_Solid(font, record_str, color); + SDL_Surface* record_surface = TTF_RenderText_Solid(font, record_str, TEXT_COLOR); SDL_Texture* record_texture = SDL_CreateTextureFromSurface(renderer, record_surface); - SDL_Surface* hint_surface = TTF_RenderText_Solid(font, "Press Enter to continue", color); + SDL_Surface* hint_surface = TTF_RenderText_Solid(font, "Press Enter to continue", TEXT_COLOR); SDL_Texture* hint_texture = SDL_CreateTextureFromSurface(renderer, hint_surface); SDL_Rect score_rect = {170, 100, 300, 40}; @@ -332,6 +367,8 @@ void DrawGameOverScreen(SDL_Renderer* renderer, int score){ SDL_FreeSurface(record_surface); SDL_FreeSurface(hint_surface); + TTF_CloseFont(font); + } diff --git a/parameter.h b/parameter.h index 6f42dab..2ec4bc7 100644 --- a/parameter.h +++ b/parameter.h @@ -23,6 +23,8 @@ #define STATE_DIE 2 #define NUMS_OF_STATE 3 #define NUMS_OF_MONSTER 2 +#define AIR_TYPE 2 +#define GROUND_TYPE 3 #define KARYL_RUN_PATH "images/run/run (%d).png" #define KARYL_JUMP_PATH "images/jump/jump (%d).png" #define KARYL_DIE_PATH "images/die/die (%d).png" @@ -30,8 +32,9 @@ #define KARYL_JUMP_RECT (SDL_Rect){40, 140, 250/0.8, 250/0.8} #define KARYL_DIE_RECT (SDL_Rect){20, 200, 250, 250} #define SCORE_RECT (SDL_Rect){450, 0, 0, 0} -#define MONSTER_GROUND_PATH "images/monster/img_1.png" -#define MONSTER_AIR_PATH "images/monster/img.png" +#define TEXT_COLOR (SDL_Color){255, 51, 153, 255} +#define MONSTER_GROUND_PATH "images/monster/ground%d.png" +#define MONSTER_AIR_PATH "images/monster/air%d.png" #define JUMP_HEIGHT(FRAME) (int)(12.5*FRAME - FRAME*FRAME/3.2) #define SIGNAL_QUIT 0 #define SIGNAL_NEXT 1 diff --git a/parkour.exe b/parkour.exe index 95ab708..1b2df28 100644 Binary files a/parkour.exe and b/parkour.exe differ diff --git a/record.c b/record.c index 0d1f2bb..967dbb0 100644 --- a/record.c +++ b/record.c @@ -1,11 +1,16 @@ - - #include "record.h" +/** + * 读取本地的记录 + * @return 记录的值 + */ int read_record(){ FILE *fp; int record; - fp = fopen("record.bin", "rb+"); + + fp = fopen("record.bin", "rb+"); /* 读取二进制文件 */ + + /* 如果文件不存在,创建文件并写入0,并返回0 */ if(fp == NULL){ fp = fopen("record.bin", "w+b"); if(fp == NULL){ @@ -19,19 +24,29 @@ int read_record(){ return record; } } + + /* 否则,直接从文件中读取记录 */ fread(&record, sizeof(int), 1, fp); fclose(fp); return record; } +/** + * 写入记录 + * @param score 成绩 + */ void write_record(int score){ FILE *fp; + + /* 打开文件 */ fp = fopen("record.bin", "w+b"); if(fp == NULL){ printf("Error: cannot open record.bin"); return; } + + /* 写入记录 */ fwrite(&score, sizeof(int), 1, fp); fclose(fp); } diff --git a/record.h b/record.h index a6d0a00..0ed236a 100644 --- a/record.h +++ b/record.h @@ -4,4 +4,4 @@ #define PARKOUR_RECORD_H int read_record(); void write_record(int score); -#endif //PARKOUR_RECORD_H +#endif