SDL2(Simple DirectMedia Layer 2)游戏开发概述(二)
以下是如何使用C语言和SDL2库结构化你的项目以创建一款简单的横版格斗游戏:
项目结构
main.c:游戏的入口点,负责初始化SDL库,设置游戏循环,并处理用户输入。
game.h:包含游戏相关常量、结构体以及函数声明的头文件。
game.c:包含游戏相关功能实现的源文件,如游戏逻辑、碰撞检测和计分系统等。
player.h:包含玩家相关常量、结构体以及函数声明的头文件。
player.c:包含玩家相关功能实现的源文件,如玩家移动、攻击和防守动作等。
enemy.h:包含敌人相关常量、结构体以及函数声明的头文件。
enemy.c:包含敌人相关功能实现的源文件,如敌人移动、攻击和防守动作等。
level.h:包含关卡相关常量、结构体以及函数声明的头文件。
level.c:包含关卡相关功能实现的源文件,如关卡加载、瓦片地图绘制以及碰撞检测等。
graphics.h:包含图形相关常量、结构体以及函数声明的头文件。
graphics.c:包含图形相关功能实现的源文件,如渲染、精灵管理以及动画播放等。
audio.h:包含音频相关常量、结构体以及函数声明的头文件。
audio.c:包含音频相关功能实现的源文件,如音效播放、背景音乐控制以及语音配音等。
SDL_utils.h:包含SDL相关实用函数的头文件,如错误处理和资源管理等。
SDL_utils.c:包含SDL相关实用函数的具体实现的源文件。
游戏循环
游戏循环将在main.c中定义,它会不断调用各个模块的功能来更新游戏状态、处理事件、渲染画面和播放声音,从而形成一个完整的、连续运行的游戏流程。
int main() {
// Initialize SDL
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
// Set up game window and renderer
SDL_Window* window = SDL_CreateWindow("Side-Scrolling Fighting Game",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1,
SDL_RENDERER_ACCELERATED);
// Set up game state
Game game;
game_init(&game);
// Game loop
while (1) {
// Handle user input
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
break;
}
// Handle player input
player_handle_input(&game.player, &event);
}
// Update game state
game_update(&game);
// Render game
renderer_clear(renderer);
game_render(&game, renderer);
SDL_RenderPresent(renderer);
// Cap framerate
SDL_Delay(16);
}
// Clean up
game_free(&game);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
游戏状态
游戏状态将会包含关于当前关卡、玩家、敌人以及其他游戏相关数据的信息。
以下是一个Game结构体可能的样子的例子:
typedef struct {
Level level;
Player player;
Enemy enemies[10];
int score;
int lives;
} Game;
玩家
玩家会有自己的一套用于移动、攻击和防御的功能方法。以下是一个Player结构体可能的样子示例: (Player结构体不仅包含了表示玩家状态的各种属性,还包含了指向移动、攻击和防御等操作函数的指针,以便在游戏中实现玩家的行为逻辑。)
typedef struct {
int x, y;
int velocity_x, velocity_y;
int health;
int attack_cooldown;
SDL_Texture* sprite;
} Player;
敌人
敌人会有自己的一套用于移动、攻击和防御的功能函数。下面是一个Enemy结构体可能的样子的示例:
typedef struct {
int x, y;
int velocity_x, velocity_y;
int health;
int attack_cooldown;
SDL_Texture* sprite;
} Enemy;
Level
关卡
关卡将包含当前关卡的相关信息,例如瓦片地图、碰撞检测以及关卡几何结构等。
以下是一个Level结构体可能的样子的示例。
typedef struct {
int width, height;
int** tile_map;
SDL_Texture* background;
} Level;
根据以上架构写出示例代码
代码示例
请注意,这只是个简化的例子,为了创建一个完全功能性的游戏,你需要添加更多的特性、错误处理以及完善工作。
main.c
#include "SDL_utils.h"
#include "game.h"
int main() {
// Initialize SDL
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
// Set up game window and renderer
SDL_Window* window = SDL_CreateWindow("Side-Scrolling Fighting Game",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// Set up game state
Game game;
game_init(&game);
// Game loop
while (1) {
// Handle user input
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
break;
}
// Handle player input
player_handle_input(&game.player, &event);
}
// Update game state
game_update(&game);
// Render game
renderer_clear(renderer);
game_render(&game, renderer);
SDL_RenderPresent(renderer);
// Cap framerate
SDL_Delay(16);
}
// Clean up
game_free(&game);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
game.h
#ifndef GAME_H
#define GAME_H
#include "player.h"
#include "enemy.h"
#include "level.h"
typedef struct {
Level level;
Player player;
Enemy enemies[10];
int score;
int lives;
} Game;
void game_init(Game* game);
void game_update(Game* game);
void game_render(Game* game, SDL_Renderer* renderer);
void game_free(Game* game);
#endif // GAME_H
game.c
#include "game.h"
#include "SDL_utils.h"
void game_init(Game* game) {
// Initialize level
level_init(&game->level);
// Initialize player
player_init(&game->player);
// Initialize enemies
for (int i = 0; i < 10; i++) {
enemy_init(&game->enemies[i]);
}
// Initialize score and lives
game->score = 0;
game->lives = 3;
}
void game_update(Game* game) {
// Update player
player_update(&game->player);
// Update enemies
for (int i = 0; i < 10; i++) {
enemy_update(&game->enemies[i]);
}
// Check for collisions
for (int i = 0; i < 10; i++) {
if (check_collision(&game->player, &game->enemies[i])) {
// Handle collision
game->lives--;
}
}
}
void game_render(Game* game, SDL_Renderer* renderer) {
// Render level
level_render(&game->level, renderer);
// Render player
player_render(&game->player, renderer);
// Render enemies
for (int i = 0; i < 10; i++) {
enemy_render(&game->enemies[i], renderer);
}
}
void game_free(Game* game) {
// Free level resources
level_free(&game->level);
// Free player resources
player_free(&game->player);
// Free enemy resources
for (int i = 0; i < 10; i++) {
enemy_free(&game->enemies[i]);
}
}
player.h
#ifndef PLAYER_H
#define PLAYER_H
#include "SDL_utils.h"
typedef struct {
int x, y;
int velocity_x, velocity_y;
int health;
int attack_cooldown;
SDL_Texture* sprite;
} Player;
void player_init(Player* player);
void player_update(Player* player);
void player_render(Player* player, SDL_Renderer* renderer);
void player_free(Player* player);
void player_handle_input(Player* player, SDL_Event* event);
#endif // PLAYER_H
player.c
#include "player.h"
void player_init(Player* player) {
player->x = 100;
player->y = 100;
player->velocity_x = 0;
player->velocity_y = 0;
player->health = 100;
player->attack_cooldown = 0;
player->sprite = SDL_CreateTextureFromSurface(renderer, SDL_LoadBMP("player.bmp"));
}
void player_update(Player* player) {
// Update player position
player->x += player->velocity_x;
player->y += player->velocity_y;
// Update attack cooldown
if (player->attack_cooldown > 0) {
player->attack_cooldown--;
}
}
void player_render(Player* player, SDL_Renderer* renderer) {
// Render player sprite
SDL_RenderCopy(renderer, player->sprite, NULL, &(SDL_Rect){player->x, player->y, 32, 32});
}
void player_free(Player* player) {
SDL_DestroyTexture(player->sprite);
}
void player_handle_input(Player* player, SDL_Event* event) {
if (event->type == SDL_KEYDOWN) {
switch (event->key.keysym.sym) {
case SDLK_LEFT:
player->velocity_x = -5;
break;
case SDLK_RIGHT:
player->velocity_x = 5;
break;
case SDLK_UP:
player->velocity_y = -5;
break;
case SDLK_DOWN:
player->velocity_y = 5;
break;
case SDLK_SPACE:
if (player->attack_cooldown == 0) {
// Handle attack
player->attack_cooldown = 30;
}
break;
}
} else if (event->type == SDL_KEYUP) {
switch (event->key.keysym.sym) {
case SDLK_LEFT:
case SDLK_RIGHT:
player->velocity_x = 0;
break;
case SDLK_UP:
case SDLK_DOWN:
player->velocity_y = 0;
break;
}
}
}
enemy.h
#ifndef ENEMY_H
#define ENEMY_H
#include "SDL_utils.h"
typedef struct {
int x, y;
int velocity_x, velocity_y;
int health;
int attack_cooldown;
SDL_Texture* sprite;
} Enemy;
void enemy_init(Enemy* enemy);
void enemy_update(Enemy* enemy);
void enemy_render(Enemy* enemy, SDL_Renderer* renderer);
void enemy_free(Enemy* enemy);
#endif // ENEMY_H
enemy.c
void enemy_init(Enemy* enemy) {
enemy->x = 300;
enemy->y = 100;
enemy->velocity_x = 2;
enemy->velocity_y = 0;
enemy->health = 50;
enemy->attack_cooldown = 0;
enemy->sprite = SDL_CreateTextureFromSurface(renderer, SDL_LoadBMP("enemy.bmp"));
}
void enemy_update(Enemy* enemy) {
// Update enemy position
enemy->x += enemy->velocity_x;
enemy->y += enemy->velocity_y;
// Update attack cooldown
if (enemy->attack_cooldown > 0) {
enemy->attack_cooldown--;
}
}
void enemy_render(Enemy* enemy, SDL_Renderer* renderer) {
// Render enemy sprite
SDL_RenderCopy(renderer, enemy->sprite, NULL, &(SDL_Rect){enemy->x, enemy->y, 32, 32});
}
void enemy_free(Enemy* enemy) {
SDL_DestroyTexture(enemy->sprite);
}
level.h
#ifndef LEVEL_H
#define LEVEL_H
#include "SDL_utils.h"
typedef struct {
int width, height;
int** tile_map;
SDL_Texture* background;
} Level;
void level_init(Level* level);
void level_update(Level* level);
void level_render(Level* level, SDL_Renderer* renderer);
void level_free(Level* level);
#endif // LEVEL_H
level.c
#include "level.h"
void level_init(Level* level) {
level->width = 640;
level->height = 480;
level->tile_map = (int**)malloc(level->width * sizeof(int*));
for (int i = 0; i < level->width; i++) {
level->tile_map[i] = (int*)malloc(level->height * sizeof(int));
}
// Initialize tile map
for (int i = 0; i < level->width; i++) {
for (int j = 0; j < level->height; j++) {
level->tile_map[i][j] = 0; // 0 = empty, 1 = wall, 2 = platform
}
}
level->background = SDL_CreateTextureFromSurface(renderer,
SDL_LoadBMP("background.bmp"));
}
void level_update(Level* level) {
// Update level state
}
void level_render(Level* level, SDL_Renderer* renderer) {
// Render background
SDL_RenderCopy(renderer, level->background, NULL, &(SDL_Rect){0, 0, level->width, level->height});
// Render tiles
for (int i = 0; i < level->width; i++) {
for (int j = 0; j < level->height; j++) {
if (level->tile_map[i][j] == 1) {
// Render wall tile
SDL_RenderCopy(renderer, SDL_CreateTextureFromSurface(renderer, SDL_LoadBMP("wall.bmp")), NULL, &(SDL_Rect){i * 32, j * 32, 32, 32});
} else if (level->tile_map[i][j] == 2) {
// Render platform tile
SDL_RenderCopy(renderer, SDL_CreateTextureFromSurface(renderer, SDL_LoadBMP("platform.bmp")), NULL, &(SDL_Rect){i * 32, j * 32, 32, 32});
}
}
}
}
void level_free(Level* level) {
// Free tile map memory
for (int i = 0; i < level->width; i++) {
free(level->tile_map[i]);
}
free(level->tile_map);
SDL_DestroyTexture(level->background);
}
SDL_utils.h
#ifndef SDL_UTILS_H
#define SDL_UTILS_H
#include <SDL2/SDL.h>
void renderer_clear(SDL_Renderer* renderer);
void renderer_present(SDL_Renderer* renderer);
#endif // SDL_UTILS_H
SDL_utils.c
#include "SDL_utils.h"
void renderer_clear(SDL_Renderer* renderer) {
SDL_RenderClear(renderer);
}
void renderer_present(SDL_Renderer* renderer) {
SDL_RenderPresent(renderer);
}
代码简单讲解
这段代码提供了一个使用SDL2开发的横版格斗游戏的基本框架,它包含了以下几个组成部分:
Game结构体:表示游戏状态,其中包括玩家、敌人、关卡以及得分等内容。
Player结构体:表示玩家,其中包含了位置、速度、生命值以及攻击冷却时间等属性。
Enemy结构体:表示敌人,其中包含了位置、速度、生命值以及攻击冷却时间等属性。
Level结构体:表示关卡,其中包含了宽度、高度、瓦片地图以及背景纹理等属性。
game_init函数:用于初始化游戏状态。
game_update函数:用于更新游戏状态,包括玩家和敌人的移动、碰撞检测以及得分计算。
game_render函数:用于渲染游戏状态,包括玩家、敌人、关卡以及得分的展示。
player_init函数:用于初始化玩家角色。
player_update函数:用于更新玩家状态,包括移动和攻击冷却时间的处理。
player_render函数:用于渲染玩家角色。 enemy_init函数:用于初始化敌人角色。
enemy_update函数:用于更新敌人状态,包括移动和攻击冷却时间的处理。
enemy_render函数:用于渲染敌人角色。
level_init函数:用于初始化关卡。
level_update函数:用于更新关卡状态。
level_render函数:用于渲染关卡画面。
SDL_utils函数集:提供了一系列与SDL2相关的实用工具函数,包括清理和呈现渲染器等功能。
请注意,这只是构建游戏的一个起点,还需要添加更多功能和特性来完成一个完整的游戏,如创建一些必需的资源,图像和音效文件等。