项目概述
本技术文档将指导开发一个使用 C++ 构建的简易 2D 游戏框架。该游戏是一个玩家控制角色收集随机生成的道具的小游戏,核心功能包括:
- 游戏循环:支持帧率控制和逻辑更新。
- 玩家控制:通过键盘控制角色上下左右移动。
- 道具生成与收集:随机生成道具,玩家接触道具后得分。
- 基本碰撞检测:检测角色与道具的碰撞。
开发环境:
- 语言:C++
- 工具库:使用 SDL2(Simple DirectMedia Layer)进行图形绘制和输入处理。
1. 项目结构
|-- Game/
|-- main.cpp # 程序入口
|-- Game.h # 游戏核心逻辑声明
|-- Game.cpp # 游戏核心逻辑实现
|-- Player.h # 玩家类声明
|-- Player.cpp # 玩家类实现
|-- Item.h # 道具类声明
|-- Item.cpp # 道具类实现
|-- Makefile # 构建脚本
2. 安装依赖
安装 SDL2
在使用该项目之前,需要确保安装了 SDL2 库。以下是在不同操作系统上安装 SDL2 的方法:
-
Ubuntu / Debian:
sudo apt update sudo apt install libsdl2-dev
-
MacOS (使用 Homebrew):
brew install sdl2
-
Windows:
下载 SDL2 库并配置 Visual Studio 或 MinGW。
3. 代码实现
3.1 游戏主循环
main.cpp
#include "Game.h"
int main(int argc, char* argv[]) {
Game game;
if (game.init("2D Game", 800, 600)) {
game.run();
}
game.cleanup();
return 0;
}
3.2 核心游戏类
Game.h
#ifndef GAME_H
#define GAME_H
#include <SDL2/SDL.h>
#include "Player.h"
#include "Item.h"
#include <vector>
class Game {
public:
bool init(const char* title, int width, int height);
void run();
void cleanup();
private:
void handleEvents();
void update();
void render();
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
bool isRunning = true;
Player* player = nullptr;
std::vector<Item*> items;
};
#endif // GAME_H
Game.cpp
#include "Game.h"
#include <cstdlib>
#include <ctime>
bool Game::init(const char* title, int width, int height) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) return false;
window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN);
if (!window) return false;
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer) return false;
player = new Player(width / 2, height / 2);
srand(static_cast<unsigned>(time(0)));
for (int i = 0; i < 5; ++i) {
items.push_back(new Item(rand() % width, rand() % height));
}
return true;
}
void Game::run() {
while (isRunning) {
handleEvents();
update();
render();
SDL_Delay(16); // 控制帧率
}
}
void Game::handleEvents() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
isRunning = false;
}
}
player->handleInput();
}
void Game::update() {
for (auto& item : items) {
if (player->checkCollision(*item)) {
item->resetPosition();
}
}
}
void Game::render() {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
player->render(renderer);
for (auto& item : items) {
item->render(renderer);
}
SDL_RenderPresent(renderer);
}
void Game::cleanup() {
delete player;
for (auto& item : items) {
delete item;
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
3.3 玩家类
Player.h
#ifndef PLAYER_H
#define PLAYER_H
#include <SDL2/SDL.h>
class Player {
public:
Player(int x, int y);
void handleInput();
void render(SDL_Renderer* renderer);
bool checkCollision(const SDL_Rect& other);
private:
SDL_Rect rect;
int speed = 5;
};
#endif // PLAYER_H
Player.cpp
#include "Player.h"
Player::Player(int x, int y) {
rect = {x, y, 50, 50};
}
void Player::handleInput() {
const Uint8* keystate = SDL_GetKeyboardState(nullptr);
if (keystate[SDL_SCANCODE_UP]) rect.y -= speed;
if (keystate[SDL_SCANCODE_DOWN]) rect.y += speed;
if (keystate[SDL_SCANCODE_LEFT]) rect.x -= speed;
if (keystate[SDL_SCANCODE_RIGHT]) rect.x += speed;
}
void Player::render(SDL_Renderer* renderer) {
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
SDL_RenderFillRect(renderer, &rect);
}
bool Player::checkCollision(const SDL_Rect& other) {
return SDL_HasIntersection(&rect, &other);
}
3.4 道具类
Item.h
#ifndef ITEM_H
#define ITEM_H
#include <SDL2/SDL.h>
class Item {
public:
Item(int x, int y);
void render(SDL_Renderer* renderer);
void resetPosition();
const SDL_Rect& getRect() const;
private:
SDL_Rect rect;
};
#endif // ITEM_H
Item.cpp
#include "Item.h"
#include <cstdlib>
Item::Item(int x, int y) {
rect = {x, y, 30, 30};
}
void Item::render(SDL_Renderer* renderer) {
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderFillRect(renderer, &rect);
}
void Item::resetPosition() {
rect.x = rand() % 800;
rect.y = rand() % 600;
}
const SDL_Rect& Item::getRect() const {
return rect;
}
4. 编译与运行
Makefile
CXX = g++
CXXFLAGS = -std=c++17 -Wall -I/usr/include/SDL2
LDFLAGS = -lSDL2
SRC = main.cpp Game.cpp Player.cpp Item.cpp
OBJ = $(SRC:.cpp=.o)
TARGET = game
all: $(TARGET)
$(TARGET): $(OBJ)
$(CXX) $(OBJ) -o $(TARGET) $(LDFLAGS)
clean:
rm -f $(OBJ) $(TARGET)
运行以下命令以编译并运行游戏:
make
./game
5. 项目总结
- 学习了 SDL2 的基本使用,包括窗口创建、渲染、事件处理等。
- 实现了一个简单的游戏循环以及核心的碰撞检测逻辑。
- 可扩展方向:增加计分功能、时间限制、更多关卡等。