Snake/snake.cpp
2025-02-03 20:55:27 +00:00

174 lines
5.9 KiB
C++

/**************************************************************
* SNAKE SDL + OpenGL Test Game to be ported to UWP
* ----------------------------------------------------------
* How to build (mingw mysys):
* g++ snake.cpp -o snake -lmingw32 -lSDL2main -lSDL2 -lopengl32 -mwindows
*
* Controls:
* Arrow Keys to move the snake.
* ESC or close window to quit.
**************************************************************/
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
static const int GRID_WIDTH = 20;
static const int GRID_HEIGHT = 15;
static const int WINDOW_SCALE = 32;
struct Segment {
int x, y;
};
enum Direction {
UP,
DOWN,
LEFT,
RIGHT
};
int main(int argc, char* argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "Failed to initialize SDL: " << SDL_GetError() << std::endl;
return 1;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
int windowWidth = GRID_WIDTH * WINDOW_SCALE;
int windowHeight = GRID_HEIGHT * WINDOW_SCALE;
SDL_Window* window = SDL_CreateWindow(
"Snake (SDL2 + OpenGL)",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
windowWidth,
windowHeight,
SDL_WINDOW_OPENGL
);
if (!window) {
std::cerr << "Failed to create window: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_GLContext glContext = SDL_GL_CreateContext(window);
if (!glContext) {
std::cerr << "Failed to create GL context: " << SDL_GetError() << std::endl;
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
SDL_GL_SetSwapInterval(1);
glViewport(0, 0, windowWidth, windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (GLdouble)windowWidth, (GLdouble)windowHeight, 0.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.f, 0.f, 0.f, 1.f);
std::srand((unsigned int)std::time(nullptr));
std::vector<Segment> snake;
snake.push_back({GRID_WIDTH / 2, GRID_HEIGHT / 2});
Direction dir = RIGHT;
int foodX = rand() % GRID_WIDTH;
int foodY = rand() % GRID_HEIGHT;
const float MOVE_INTERVAL = 0.15f;
float timer = 0.0f;
bool running = true;
Uint32 lastTicks = SDL_GetTicks();
int score = 0;
while (running) {
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
running = false;
} else if (e.type == SDL_KEYDOWN) {
switch (e.key.keysym.sym) {
case SDLK_ESCAPE:
running = false;
break;
case SDLK_UP:
if (dir != DOWN) dir = UP;
break;
case SDLK_DOWN:
if (dir != UP) dir = DOWN;
break;
case SDLK_LEFT:
if (dir != RIGHT) dir = LEFT;
break;
case SDLK_RIGHT:
if (dir != LEFT) dir = RIGHT;
break;
default:
break;
}
}
}
Uint32 currentTicks = SDL_GetTicks();
float deltaTime = (currentTicks - lastTicks) / 1000.0f;
lastTicks = currentTicks;
timer += deltaTime;
if (timer >= MOVE_INTERVAL) {
timer -= MOVE_INTERVAL;
Segment head = snake.front();
switch (dir) {
case UP: head.y -= 1; break;
case DOWN: head.y += 1; break;
case LEFT: head.x -= 1; break;
case RIGHT: head.x += 1; break;
}
if (head.x < 0) head.x = GRID_WIDTH - 1;
else if (head.x >= GRID_WIDTH) head.x = 0;
if (head.y < 0) head.y = GRID_HEIGHT - 1;
else if (head.y >= GRID_HEIGHT) head.y = 0;
for (size_t i = 0; i < snake.size(); i++) {
if (snake[i].x == head.x && snake[i].y == head.y) {
std::cout << "Game Over! You ate yourself. Final score: " << score << std::endl;
running = false;
break;
}
}
if (running) {
snake.insert(snake.begin(), head);
if (head.x == foodX && head.y == foodY) {
score++;
foodX = rand() % GRID_WIDTH;
foodY = rand() % GRID_HEIGHT;
} else {
snake.pop_back();
}
}
}
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_QUADS);
float fx = (float)foodX * WINDOW_SCALE;
float fy = (float)foodY * WINDOW_SCALE;
glVertex2f(fx, fy);
glVertex2f(fx + WINDOW_SCALE, fy);
glVertex2f(fx + WINDOW_SCALE, fy + WINDOW_SCALE);
glVertex2f(fx, fy + WINDOW_SCALE);
glEnd();
glColor3f(0.0f, 1.0f, 0.0f);
glBegin(GL_QUADS);
for (auto &seg : snake) {
float sx = (float)seg.x * WINDOW_SCALE;
float sy = (float)seg.y * WINDOW_SCALE;
glVertex2f(sx, sy);
glVertex2f(sx + WINDOW_SCALE, sy);
glVertex2f(sx + WINDOW_SCALE, sy + WINDOW_SCALE);
glVertex2f(sx, sy + WINDOW_SCALE);
}
glEnd();
SDL_GL_SwapWindow(window);
}
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}