实现手柄控制贪吃蛇
#include <SDL.h>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
// 屏幕的宽度和高度
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
// 方块的大小
const int BLOCK_SIZE = 20;
// 贪吃蛇的方向
enum Direction { UP, DOWN, LEFT, RIGHT };
// 贪吃蛇类
class Snake {
public:
Snake() : direction(RIGHT), grow(false) {
// 初始化贪吃蛇的位置
body.push_back({ SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 });
}
void handleInput(SDL_Joystick* joystick) {
// 读取摇杆输入
int x_axis = SDL_JoystickGetAxis(joystick, 0);
int y_axis = SDL_JoystickGetAxis(joystick, 1);
if (abs(x_axis) > 8000) {
if (x_axis > 0 && direction != LEFT) direction = RIGHT;
if (x_axis < 0 && direction != RIGHT) direction = LEFT;
}
if (abs(y_axis) > 8000) {
if (y_axis > 0 && direction != UP) direction = DOWN;
if (y_axis < 0 && direction != DOWN) direction = UP;
}
}
void move() {
// 计算新的蛇头位置
SDL_Point newHead = body.front();
switch (direction) {
case UP: newHead.y -= BLOCK_SIZE; break;
case DOWN: newHead.y += BLOCK_SIZE; break;
case LEFT: newHead.x -= BLOCK_SIZE; break;
case RIGHT: newHead.x += BLOCK_SIZE; break;
}
// 插入新的蛇头
body.insert(body.begin(), newHead);
// 如果需要成长,不删除尾部,否则删除尾部
if (grow) {
grow = false;
}
else {
body.pop_back();
}
}
void growSnake() {
grow = true;
}
bool checkCollision() const {
const SDL_Point& head = body.front();
// 检查是否撞到墙壁
if (head.x < 0 || head.x >= SCREEN_WIDTH || head.y < 0 || head.y >= SCREEN_HEIGHT) {
return true;
}
// 检查是否撞到自己
for (size_t i = 1; i < body.size(); ++i) {
if (body[i].x == head.x && body[i].y == head.y) {
return true;
}
}
return false;
}
const std::vector<SDL_Point>& getBody() const {
return body;
}
private:
std::vector<SDL_Point> body;
Direction direction;
bool grow;
};
// 食物类
class Food {
public:
Food() {
std::srand(std::time(nullptr));
spawn();
}
void spawn() {
x = (std::rand() % (SCREEN_WIDTH / BLOCK_SIZE)) * BLOCK_SIZE;
y = (std::rand() % (SCREEN_HEIGHT / BLOCK_SIZE)) * BLOCK_SIZE;
}
SDL_Point getPosition() const {
return { x, y };
}
private:
int x, y;
};
// 绘制方块
void drawBlock(SDL_Renderer* renderer, const SDL_Point& position, SDL_Color color) {
SDL_Rect rect = { position.x, position.y, BLOCK_SIZE, BLOCK_SIZE };
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_RenderFillRect(renderer, &rect);
}
int main(int argc, char* argv[]) {
// 初始化 SDL
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
std::cerr << "SDL 初始化失败: " << SDL_GetError() << std::endl;
return 1;
}
// 创建窗口
SDL_Window* window = SDL_CreateWindow("贪吃蛇游戏(手柄控制)",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN);
if (!window) {
std::cerr << "创建窗口失败: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
// 创建渲染器
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer) {
std::cerr << "创建渲染器失败: " << SDL_GetError() << std::endl;
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
// 打开第一个可用的手柄
if (SDL_NumJoysticks() < 1) {
std::cerr << "没有找到手柄" << std::endl;
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
SDL_Joystick* joystick = SDL_JoystickOpen(0);
if (!joystick) {
std::cerr << "无法打开手柄: " << SDL_GetError() << std::endl;
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
// 创建贪吃蛇和食物
Snake snake;
Food food;
bool running = true;
SDL_Event event;
Uint32 lastTime = SDL_GetTicks();
Uint32 currentTime;
const Uint32 FRAME_DELAY = 100; // 帧率控制(10 FPS)
while (running) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = false;
}
}
// 处理手柄输入
snake.handleInput(joystick);
// 控制帧率
currentTime = SDL_GetTicks();
if (currentTime - lastTime >= FRAME_DELAY) {
snake.move();
// 检查是否吃到食物
SDL_Point head = snake.getBody().front();
if (head.x == food.getPosition().x && head.y == food.getPosition().y) {
snake.growSnake();
food.spawn();
}
if (snake.checkCollision()) {// 检查碰撞
std::cout << "游戏结束!" << std::endl;
running = false;
}
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF);
for (const SDL_Point& block : snake.getBody()) {
drawBlock(renderer, block, { 0x00, 0xFF, 0x00, 0xFF });// 绘制贪吃蛇
}
SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF);
drawBlock(renderer, food.getPosition(), { 0xFF, 0x00, 0x00, 0xFF }); // 绘制食物
SDL_RenderPresent(renderer);
lastTime = currentTime;
}
SDL_Delay(10);
}
SDL_JoystickClose(joystick);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}