Upload files to "/"
This commit is contained in:
commit
83ace1f915
173
snake.cpp
Normal file
173
snake.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/**************************************************************
|
||||
* 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;
|
||||
}
|
||||
185
snake_ported.cpp
Normal file
185
snake_ported.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/**************************************************************
|
||||
* SNAKE SDL + OpenGL Test Game to be ported to UWP
|
||||
* How to build (mingw mysys):
|
||||
* g++ -shared snake_ported.cpp -o snake_ported.dll \
|
||||
-lmingw32 -lSDL2main -lSDL2 -lopengl32 -mwindows
|
||||
* ----------------------------------------------------------
|
||||
**************************************************************/
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_opengl.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DLL_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define DLL_EXPORT
|
||||
#endif
|
||||
|
||||
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 };
|
||||
|
||||
extern "C" {
|
||||
struct ControllerInput {
|
||||
float left_x;
|
||||
float left_y;
|
||||
float right_x;
|
||||
float right_y;
|
||||
bool button_a;
|
||||
bool button_b;
|
||||
};
|
||||
|
||||
static float g_left_x = 0.0f;
|
||||
static float g_left_y = 0.0f;
|
||||
static Direction g_dir = RIGHT;
|
||||
static bool g_running = false;
|
||||
|
||||
// Update controller thumbstick values, map them to direction
|
||||
DLL_EXPORT void update_controller_input(ControllerInput input) {
|
||||
g_left_x = input.left_x;
|
||||
g_left_y = input.left_y;
|
||||
}
|
||||
|
||||
// Forward declaration so external_entry can call it
|
||||
static int snake_main();
|
||||
|
||||
// This is the exported entry point that the host app calls
|
||||
// It calls our internal snake_main()
|
||||
DLL_EXPORT int external_entry() {
|
||||
return snake_main();
|
||||
}
|
||||
}
|
||||
|
||||
// The core Snake game logic
|
||||
static int snake_main() {
|
||||
//SDL_GL_GetCurrentContext() will be your best friend.
|
||||
if (!SDL_GL_GetCurrentContext()) {
|
||||
std::cerr << "No active GL context found. Exiting.\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
glViewport(0, 0, GRID_WIDTH * WINDOW_SCALE, GRID_HEIGHT * WINDOW_SCALE);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0, (double)(GRID_WIDTH * WINDOW_SCALE),
|
||||
(double)(GRID_HEIGHT * WINDOW_SCALE), 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});
|
||||
g_dir = RIGHT;
|
||||
int foodX = std::rand() % GRID_WIDTH;
|
||||
int foodY = std::rand() % GRID_HEIGHT;
|
||||
const float MOVE_INTERVAL = 0.15f;
|
||||
float timer = 0.0f;
|
||||
g_running = true;
|
||||
Uint32 lastTicks = SDL_GetTicks();
|
||||
int score = 0;
|
||||
|
||||
while (g_running) {
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
if (e.type == SDL_QUIT) {
|
||||
g_running = false;
|
||||
} else if (e.type == SDL_KEYDOWN) {
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_ESCAPE: g_running = false; break;
|
||||
case SDLK_UP: if (g_dir != DOWN) g_dir = UP; break;
|
||||
case SDLK_DOWN: if (g_dir != UP) g_dir = DOWN; break;
|
||||
case SDLK_LEFT: if (g_dir != RIGHT) g_dir = LEFT; break;
|
||||
case SDLK_RIGHT: if (g_dir != LEFT) g_dir = RIGHT; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle controller direction via left thumbstick
|
||||
{
|
||||
float deadzone = 0.5f;
|
||||
Direction nextDir = g_dir;
|
||||
if (g_left_y > deadzone && g_dir != DOWN) nextDir = UP;
|
||||
if (g_left_y < -deadzone && g_dir != UP) nextDir = DOWN;
|
||||
if (g_left_x > deadzone && g_dir != LEFT) nextDir = RIGHT;
|
||||
if (g_left_x < -deadzone && g_dir != RIGHT) nextDir = LEFT;
|
||||
g_dir = nextDir;
|
||||
}
|
||||
|
||||
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 (g_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! Final score: " << score << std::endl;
|
||||
g_running = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (g_running) {
|
||||
snake.insert(snake.begin(), head);
|
||||
if (head.x == foodX && head.y == foodY) {
|
||||
score++;
|
||||
foodX = std::rand() % GRID_WIDTH;
|
||||
foodY = std::rand() % GRID_HEIGHT;
|
||||
} else {
|
||||
snake.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_running) break;
|
||||
|
||||
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();
|
||||
|
||||
// Since the host created the window & context, we swap via the current window
|
||||
SDL_GL_SwapWindow(SDL_GL_GetCurrentWindow());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user