C++ 贪吃蛇(Snake),SDL, bug
C++ 贪吃蛇(Snake),SDL,bug
g++ .\Untitled-2.cpp -lmingw32 -lSDL2main -lSDL2 -lSDL2_ttf
SDL
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <iostream>
#include <deque>
#include <cstdlib>
#include <ctime>
using namespace std;
// Define constants
const int WINDOW_WIDTH = 640;
const int WINDOW_HEIGHT = 480;
const int CELL_SIZE = 20;
const int NUM_CELLS_X = WINDOW_WIDTH / CELL_SIZE;
const int NUM_CELLS_Y = WINDOW_HEIGHT / CELL_SIZE;
const std::string FONT_PATH = "arial.ttf";
const int FONT_SIZE = 20;
// Declare functions
void init();
void update();
void draw();
void handleInput();
void placeFood();
bool checkCollision(int x, int y);
// Declare global variables
SDL_Window *window;
SDL_Renderer *renderer;
TTF_Font *font;
std::deque<std::pair<int, int>> snake;
std::pair<int, int> food;
int direction = 0;
int score = 0;
int main(int argc, char *argv[])
{
// Initialize SDL
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
// Create a window and renderer
window = SDL_CreateWindow("Snake", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, 0);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// Load the font
font = TTF_OpenFont(FONT_PATH.c_str(), FONT_SIZE);
if (!font)
{
std::cout << "Failed to load font: " << TTF_GetError() << std::endl;
exit(1);
}
// Initialize the snake
snake.push_back(std::make_pair(NUM_CELLS_X / 2, NUM_CELLS_Y / 2));
placeFood();
// Main loop
bool quit = false;
while (!quit)
{
handleInput();
update();
draw();
SDL_Delay(100);
}
// Clean up and exit
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
void update()
{
// Move the snake
int x = snake.front().first;
int y = snake.front().second;
if (direction == 0)
y -= 1;
if (direction == 1)
x += 1;
if (direction == 2)
y += 1;
if (direction == 3)
x -= 1;
if (x < 0)
x = NUM_CELLS_X - 1;
if (x >= NUM_CELLS_X)
x = 0;
if (y < 0)
y = NUM_CELLS_Y - 1;
if (y >= NUM_CELLS_Y)
y = 0;
if (checkCollision(x, y))
{
std::cout << "Game over! Score: " << score << std::endl;
SDL_Delay(1000);
exit(0);
}
snake.push_front(std::make_pair(x, y));
if (x == food.first && y == food.second)
{
placeFood();
score++;
}
else
{
snake.pop_back();
}
}
void draw()
{
// Clear the screen
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
// Draw the snake
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
for (std::pair<int, int> cell : snake)
{
SDL_Rect rect = {cell.first * CELL_SIZE, cell.second * CELL_SIZE,
CELL_SIZE, CELL_SIZE};
SDL_RenderFillRect(renderer, &rect);
}
// Draw the food
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_Rect rect = {food.first * CELL_SIZE, food.second * CELL_SIZE,
CELL_SIZE, CELL_SIZE};
SDL_RenderFillRect(renderer, &rect);
// Draw the score
std::string scoreText = "Score: " + std::to_string(score);
SDL_Color color = {255, 255, 255, 255};
SDL_Surface *surface = TTF_RenderText_Solid(font, scoreText.c_str(), color);
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_Rect scoreRect = {10, 10, surface->w, surface->h};
SDL_RenderCopy(renderer, texture, NULL, &scoreRect);
SDL_FreeSurface(surface);
SDL_DestroyTexture(texture);
// Update the screen
SDL_RenderPresent(renderer);
}
void handleInput()
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
cout << event.type << '\t';
if (event.type == SDL_QUIT)
{
exit(0);
}
else if (event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_UP:
if (direction != 2)
direction = 0;
break;
case SDLK_RIGHT:
if (direction != 3)
direction = 1;
break;
case SDLK_DOWN:
if (direction != 0)
direction = 2;
break;
case SDLK_LEFT:
if (direction != 1)
direction = 3;
break;
default:
break;
}
}
else if (event.type == SDL_TEXTEDITING)
{
// Handle text input
printf("Unicode character: %s\n", event.text.text);
SDL_FlushEvent(SDL_TEXTEDITING);
SDL_PumpEvents();
}
}
}
void placeFood()
{
// Generate a random position for the food
srand(time(0));
int x = rand() % NUM_CELLS_X;
int y = rand() % NUM_CELLS_Y;
food = std::make_pair(x, y);
// Check that the food doesn't overlap with the snake
while (checkCollision(food.first, food.second))
{
x = rand() % NUM_CELLS_X;
y = rand() % NUM_CELLS_Y;
food = std::make_pair(x, y);
}
}
bool checkCollision(int x, int y)
{
// Check if the given position collides with the snake
for (std::pair<int, int> cell : snake)
{
if (cell.first == x && cell.second == y)
{
return true;
}
}
return false;
}
这是一个可玩的贪吃蛇,但是如果我们切换为中文输入法。
那么event.type == SDL_TEXTEDITING,所有键盘都失灵了。
This is a playable Snake game, but if we switch our input method to the Chinese input method.
Then event.type == SDL_TEXTEDITING, and all keys including Arrow keys stuck.
许多人问过这个问题,包括德语输入法的用户。这也是为什么在有些游戏只能使用英文输入法。
Many people have asked this question, including German input method users. This may be also why somebody can only use the English input method in some games.
找不到简单的解决方案。
Unable to find a simple solution.
Edit:
Solution 1:
else if (event.type == SDL_TEXTEDITING)
{
if (!textInput)
{
SDL_StopTextInput();
SDL_FlushEvent(SDL_TEXTEDITING);
break;
}
}