mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Update raylib examples.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
module arkanoid;
|
module arkanoid;
|
||||||
import raylib5;
|
import raylib55;
|
||||||
import std::math;
|
import std::math;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -34,23 +34,23 @@ enum GameScreen
|
|||||||
|
|
||||||
struct Player
|
struct Player
|
||||||
{
|
{
|
||||||
Vector2 position;
|
RLVector2 position;
|
||||||
Vector2 size;
|
RLVector2 size;
|
||||||
int life;
|
int life;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Ball
|
struct Ball
|
||||||
{
|
{
|
||||||
Vector2 position;
|
RLVector2 position;
|
||||||
Vector2 speed;
|
RLVector2 speed;
|
||||||
int radius;
|
int radius;
|
||||||
bool active;
|
bool active;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Brick
|
struct Brick
|
||||||
{
|
{
|
||||||
Vector2 position;
|
RLVector2 position;
|
||||||
bool active;
|
bool active;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
@@ -63,36 +63,36 @@ bool pause = false;
|
|||||||
Player player;
|
Player player;
|
||||||
Ball ball;
|
Ball ball;
|
||||||
Brick[BRICKS_PER_LINE][LINES_OF_BRICKS] brick;
|
Brick[BRICKS_PER_LINE][LINES_OF_BRICKS] brick;
|
||||||
Vector2 brick_size;
|
RLVector2 brick_size;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Program main entry point
|
// Program main entry point
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
// Initialization (Note windowTitle is unused on Android)
|
// Initialization (Note windowTitle is unused on Android)
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
rl::initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: arkanoid");
|
rl::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: arkanoid");
|
||||||
|
|
||||||
init_game();
|
init_game();
|
||||||
|
|
||||||
rl::setTargetFPS(60);
|
rl::set_target_fps(60);
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Main game loop
|
// Main game loop
|
||||||
while (!rl::windowShouldClose()) // Detect window close button or ESC key
|
while (!rl::window_should_close()) // Detect window close button or ESC key
|
||||||
{
|
{
|
||||||
// Update and Draw
|
// Update and Draw
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
update_draw_frame();
|
update_draw_frame();
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
}
|
}
|
||||||
// De-Initialization
|
// De-Initialization
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
unload_game(); // Unload loaded data (textures, sounds, models...)
|
unload_game(); // Unload loaded data (textures, sounds, models...)
|
||||||
|
|
||||||
rl::closeWindow(); // Close window and OpenGL context
|
rl::close_window(); // Close window and OpenGL context
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,30 +103,30 @@ fn void main()
|
|||||||
// Initialize game variables
|
// Initialize game variables
|
||||||
fn void init_game()
|
fn void init_game()
|
||||||
{
|
{
|
||||||
brick_size = { (float)rl::getScreenWidth() / BRICKS_PER_LINE, 40 };
|
brick_size = { (float)rl::get_screen_width() / BRICKS_PER_LINE, 40 };
|
||||||
|
|
||||||
// Initialize player
|
// Initialize player
|
||||||
player.position = { SCREEN_WIDTH/2, SCREEN_HEIGHT * 7 / 8 };
|
player.position = { SCREEN_WIDTH / 2, SCREEN_HEIGHT * 7 / 8 };
|
||||||
player.size = { SCREEN_WIDTH / 10, 20 };
|
player.size = { SCREEN_WIDTH / 10, 20 };
|
||||||
player.life = PLAYER_MAX_LIFE;
|
player.life = PLAYER_MAX_LIFE;
|
||||||
|
|
||||||
// Initialize ball
|
// Initialize ball
|
||||||
ball.position = { SCREEN_WIDTH / 2, SCREEN_HEIGHT * 7 / 8 - 30 };
|
ball.position = { SCREEN_WIDTH / 2, SCREEN_HEIGHT * 7 / 8 - 30 };
|
||||||
ball.speed = { 0, 0 };
|
ball.speed = { 0, 0 };
|
||||||
ball.radius = 7;
|
ball.radius = 7;
|
||||||
ball.active = false;
|
ball.active = false;
|
||||||
|
|
||||||
// Initialize bricks
|
// Initialize bricks
|
||||||
int initial_down_position = 50;
|
int initial_down_position = 50;
|
||||||
|
|
||||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
||||||
{
|
{
|
||||||
brick[i][j].position = { j * brick_size.x + brick_size.x / 2, i * brick_size.y + initial_down_position };
|
brick[i][j].position = { j * brick_size.x + brick_size.x / 2, i * brick_size.y + initial_down_position };
|
||||||
brick[i][j].active = true;
|
brick[i][j].active = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update game (one frame)
|
// Update game (one frame)
|
||||||
@@ -134,178 +134,187 @@ fn void update_game()
|
|||||||
{
|
{
|
||||||
if (game_over)
|
if (game_over)
|
||||||
{
|
{
|
||||||
if (rl::isKeyPressed(rl::KEY_ENTER))
|
if (rl::is_key_pressed(ENTER))
|
||||||
{
|
{
|
||||||
init_game();
|
init_game();
|
||||||
game_over = false;
|
game_over = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rl::isKeyPressed((KeyboardKey)'P')) pause = !pause;
|
if (rl::is_key_pressed(P)) pause = !pause;
|
||||||
|
|
||||||
if (pause) return;
|
if (pause) return;
|
||||||
// Player movement logic
|
// Player movement logic
|
||||||
if (rl::isKeyDown(rl::KEY_LEFT)) player.position.x -= 5;
|
if (rl::is_key_down(LEFT)) player.position.x -= 5;
|
||||||
if ((player.position.x - player.size.x/2) <= 0) player.position.x = player.size.x/2;
|
if ((player.position.x - player.size.x / 2) <= 0) player.position.x = player.size.x / 2;
|
||||||
if (rl::isKeyDown(rl::KEY_RIGHT)) player.position.x += 5;
|
if (rl::is_key_down(RIGHT)) player.position.x += 5;
|
||||||
if ((player.position.x + player.size.x/2) >= SCREEN_WIDTH) player.position.x = SCREEN_WIDTH - player.size.x/2;
|
if ((player.position.x + player.size.x / 2) >= SCREEN_WIDTH) player.position.x = SCREEN_WIDTH - player.size.x / 2;
|
||||||
|
|
||||||
// Ball launching logic
|
// Ball launching logic
|
||||||
if (!ball.active)
|
if (!ball.active)
|
||||||
{
|
{
|
||||||
if (rl::isKeyPressed(rl::KEY_SPACE))
|
if (rl::is_key_pressed(SPACE))
|
||||||
{
|
{
|
||||||
ball.active = true;
|
ball.active = true;
|
||||||
ball.speed = { 0, -5 };
|
ball.speed = { 0, -5 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ball movement logic
|
// Ball movement logic
|
||||||
if (ball.active)
|
if (ball.active)
|
||||||
{
|
{
|
||||||
ball.position.x += ball.speed.x;
|
|
||||||
ball.position.y += ball.speed.y;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ball.position = { player.position.x, SCREEN_HEIGHT * 7 / 8 - 30 };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collision logic: ball vs walls
|
ball.position += ball.speed;
|
||||||
if (((ball.position.x + ball.radius) >= SCREEN_WIDTH) || ((ball.position.x - ball.radius) <= 0)) ball.speed.x *= -1;
|
}
|
||||||
if ((ball.position.y - ball.radius) <= 0) ball.speed.y *= -1;
|
else
|
||||||
if ((ball.position.y + ball.radius) >= SCREEN_HEIGHT)
|
{
|
||||||
{
|
ball.position = { player.position.x, SCREEN_HEIGHT * 7 / 8 - 30 };
|
||||||
ball.speed = { 0, 0 };
|
}
|
||||||
ball.active = false;
|
|
||||||
|
|
||||||
player.life--;
|
// Collision logic: ball vs walls
|
||||||
}
|
|
||||||
|
|
||||||
// Collision logic: ball vs player
|
if ((ball.position.x + ball.radius >= SCREEN_WIDTH) || (ball.position.x - ball.radius <= 0)) ball.speed.x *= -1;
|
||||||
if (rl::checkCollisionCircleRec(ball.position, ball.radius, { player.position.x - player.size.x / 2, player.position.y - player.size.y / 2, player.size.x, player.size.y}))
|
if (ball.position.y - ball.radius <= 0) ball.speed.y *= -1;
|
||||||
{
|
if (ball.position.y + ball.radius >= SCREEN_HEIGHT)
|
||||||
if (ball.speed.y > 0)
|
{
|
||||||
{
|
ball.speed = { 0, 0 };
|
||||||
ball.speed.y *= -1;
|
ball.active = false;
|
||||||
ball.speed.x = (ball.position.x - player.position.x) / (player.size.x / 2) * 5;
|
player.life--;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Collision logic: ball vs bricks
|
// Collision logic: ball vs player
|
||||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
if (rl::check_collision_circle_rec(ball.position, ball.radius, { player.position.x - player.size.x / 2, player.position.y - player.size.y / 2, player.size.x, player.size.y}))
|
||||||
{
|
{
|
||||||
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
if (ball.speed.y > 0)
|
||||||
{
|
{
|
||||||
if (brick[i][j].active)
|
ball.speed.y *= -1;
|
||||||
{
|
ball.speed.x = (ball.position.x - player.position.x) / (player.size.x / 2) * 5;
|
||||||
// Hit below
|
}
|
||||||
if (((ball.position.y - ball.radius) <= (brick[i][j].position.y + brick_size.y / 2)) &&
|
}
|
||||||
((ball.position.y - ball.radius) > (brick[i][j].position.y + brick_size.y / 2 + ball.speed.y)) &&
|
|
||||||
((math::abs(ball.position.x - brick[i][j].position.x)) < (brick_size.x / 2 + ball.radius * 2.0f / 3)) && (ball.speed.y < 0))
|
|
||||||
{
|
|
||||||
brick[i][j].active = false;
|
|
||||||
ball.speed.y *= -1;
|
|
||||||
}
|
|
||||||
// Hit above
|
|
||||||
else if (((ball.position.y + ball.radius) >= (brick[i][j].position.y - brick_size.y/2)) &&
|
|
||||||
((ball.position.y + ball.radius) < (brick[i][j].position.y - brick_size.y/2 + ball.speed.y)) &&
|
|
||||||
((math::abs(ball.position.x - brick[i][j].position.x)) < (brick_size.x / 2 + ball.radius * 2.0f / 3)) && (ball.speed.y > 0))
|
|
||||||
{
|
|
||||||
brick[i][j].active = false;
|
|
||||||
ball.speed.y *= -1;
|
|
||||||
}
|
|
||||||
// Hit left
|
|
||||||
else if (((ball.position.x + ball.radius) >= (brick[i][j].position.x - brick_size.x/2)) &&
|
|
||||||
((ball.position.x + ball.radius) < (brick[i][j].position.x - brick_size.x/2 + ball.speed.x)) &&
|
|
||||||
((math::abs(ball.position.y - brick[i][j].position.y)) < (brick_size.y / 2 + ball.radius * 2.0f / 3)) && (ball.speed.x > 0))
|
|
||||||
{
|
|
||||||
brick[i][j].active = false;
|
|
||||||
ball.speed.x *= -1;
|
|
||||||
}
|
|
||||||
// Hit right
|
|
||||||
else if (((ball.position.x - ball.radius) <= (brick[i][j].position.x + brick_size.x/2)) &&
|
|
||||||
((ball.position.x - ball.radius) > (brick[i][j].position.x + brick_size.x/2 + ball.speed.x)) &&
|
|
||||||
((math::abs(ball.position.y - brick[i][j].position.y)) < (brick_size.y / 2 + ball.radius * 2.0f / 3)) && (ball.speed.x < 0))
|
|
||||||
{
|
|
||||||
brick[i][j].active = false;
|
|
||||||
ball.speed.x *= -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Game over logic
|
// Collision logic: ball vs bricks
|
||||||
if (player.life <= 0)
|
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||||
{
|
{
|
||||||
game_over = true;
|
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
||||||
}
|
{
|
||||||
else
|
if (brick[i][j].active)
|
||||||
{
|
{
|
||||||
game_over = true;
|
// Hit below
|
||||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
|
||||||
{
|
if (ball.position.y - ball.radius <= brick[i][j].position.y + brick_size.y / 2
|
||||||
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
&& ball.position.y - ball.radius > brick[i][j].position.y + brick_size.y / 2 + ball.speed.y
|
||||||
{
|
&& math::abs(ball.position.x - brick[i][j].position.x) < brick_size.x / 2 + ball.radius * 2.0f / 3
|
||||||
if (brick[i][j].active) game_over = false;
|
&& ball.speed.y < 0)
|
||||||
}
|
{
|
||||||
}
|
brick[i][j].active = false;
|
||||||
}
|
ball.speed.y *= -1;
|
||||||
|
}
|
||||||
|
// Hit above
|
||||||
|
else if (ball.position.y + ball.radius >= brick[i][j].position.y - brick_size.y / 2
|
||||||
|
&& ball.position.y + ball.radius < brick[i][j].position.y - brick_size.y/2 + ball.speed.y
|
||||||
|
&& math::abs(ball.position.x - brick[i][j].position.x) < brick_size.x / 2 + ball.radius * 2.0f / 3
|
||||||
|
&& ball.speed.y > 0)
|
||||||
|
{
|
||||||
|
brick[i][j].active = false;
|
||||||
|
ball.speed.y *= -1;
|
||||||
|
}
|
||||||
|
// Hit left
|
||||||
|
else if (ball.position.x + ball.radius >= brick[i][j].position.x - brick_size.x / 2
|
||||||
|
&& ball.position.x + ball.radius < brick[i][j].position.x - brick_size.x / 2 + ball.speed.x
|
||||||
|
&& math::abs(ball.position.y - brick[i][j].position.y) < brick_size.y / 2 + ball.radius * 2.0f / 3
|
||||||
|
&& ball.speed.x > 0)
|
||||||
|
{
|
||||||
|
brick[i][j].active = false;
|
||||||
|
ball.speed.x *= -1;
|
||||||
|
}
|
||||||
|
// Hit right
|
||||||
|
else if (ball.position.x - ball.radius <= brick[i][j].position.x + brick_size.x / 2
|
||||||
|
&& ball.position.x - ball.radius > brick[i][j].position.x + brick_size.x / 2 + ball.speed.x
|
||||||
|
&& math::abs(ball.position.y - brick[i][j].position.y) < brick_size.y / 2 + ball.radius * 2.0f / 3
|
||||||
|
&& ball.speed.x < 0)
|
||||||
|
{
|
||||||
|
brick[i][j].active = false;
|
||||||
|
ball.speed.x *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Game over logic
|
||||||
|
if (player.life <= 0)
|
||||||
|
{
|
||||||
|
game_over = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
||||||
|
{
|
||||||
|
if (brick[i][j].active)
|
||||||
|
{
|
||||||
|
game_over = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
game_over = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw game (one frame)
|
// Draw game (one frame)
|
||||||
fn void draw_game()
|
fn void draw_game()
|
||||||
{
|
{
|
||||||
rl::beginDrawing();
|
rl::begin_drawing();
|
||||||
defer rl::endDrawing();
|
defer rl::end_drawing();
|
||||||
rl::clearBackground(rl::RAYWHITE);
|
|
||||||
|
|
||||||
if (!game_over)
|
rl::clear_background(rl::RAYWHITE);
|
||||||
{
|
|
||||||
// Draw player bar
|
|
||||||
rl::drawRectangle((int)(player.position.x - player.size.x/2), (int)(player.position.y - player.size.y/2), (int)player.size.x, (int)player.size.y, rl::BLACK);
|
|
||||||
|
|
||||||
// Draw player lives
|
if (!game_over)
|
||||||
for (int i = 0; i < player.life; i++) rl::drawRectangle(20 + 40*i, SCREEN_HEIGHT - 30, 35, 10, rl::LIGHTGRAY);
|
{
|
||||||
|
// Draw player bar
|
||||||
|
rl::draw_rectangle((int)(player.position.x - player.size.x/2), (int)(player.position.y - player.size.y/2), (int)player.size.x, (int)player.size.y, rl::BLACK);
|
||||||
|
|
||||||
// Draw ball
|
// Draw player lives
|
||||||
rl::drawCircleV(ball.position, ball.radius, rl::MAROON);
|
for (int i = 0; i < player.life; i++) rl::draw_rectangle(20 + 40*i, SCREEN_HEIGHT - 30, 35, 10, rl::LIGHTGRAY);
|
||||||
|
|
||||||
// Draw bricks
|
// Draw ball
|
||||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
rl::draw_circle_v(ball.position, ball.radius, rl::MAROON);
|
||||||
{
|
|
||||||
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
|
||||||
{
|
|
||||||
if (brick[i][j].active)
|
|
||||||
{
|
|
||||||
if ((i + j) % 2 == 0)
|
|
||||||
{
|
|
||||||
rl::drawRectangle((int)(brick[i][j].position.x - brick_size.x/2), (int)(brick[i][j].position.y - brick_size.y/2), (int)brick_size.x, (int)brick_size.y, rl::GRAY);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rl::drawRectangle((int)(brick[i][j].position.x - brick_size.x/2), (int)(brick[i][j].position.y - brick_size.y/2), (int)brick_size.x, (int)brick_size.y, rl::DARKGRAY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pause) rl::drawText("GAME PAUSED", SCREEN_WIDTH/2 - rl::measureText("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, rl::GRAY);
|
// Draw bricks
|
||||||
}
|
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||||
else
|
{
|
||||||
{
|
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
||||||
rl::drawText("PRESS [ENTER] TO PLAY AGAIN", rl::getScreenWidth()/2 - rl::measureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, rl::getScreenHeight()/2 - 50, 20, rl::GRAY);
|
{
|
||||||
}
|
if (brick[i][j].active)
|
||||||
|
{
|
||||||
|
RLVector2 brick_pos = brick[i][j].position - brick_size / 2;
|
||||||
|
if ((i + j) % 2 == 0)
|
||||||
|
{
|
||||||
|
rl::draw_rectangle((int)brick_pos.x, (int)brick_pos.y, (int)brick_size.x, (int)brick_size.y, rl::GRAY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rl::draw_rectangle((int)brick_pos.x, (int)brick_pos.y, (int)brick_size.x, (int)brick_size.y, rl::DARKGRAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pause) rl::draw_text("GAME PAUSED", SCREEN_WIDTH / 2 - rl::measure_text("GAME PAUSED", 40) / 2, SCREEN_HEIGHT / 2 - 40, 40, rl::GRAY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rl::draw_text("PRESS [ENTER] TO PLAY AGAIN", rl::get_screen_width()/2 - rl::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20) / 2, rl::get_screen_height() / 2 - 50, 20, rl::GRAY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unload game variables
|
// Unload game variables
|
||||||
fn void unload_game()
|
fn void unload_game()
|
||||||
{
|
{
|
||||||
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
|
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update and Draw (one frame)
|
// Update and Draw (one frame)
|
||||||
fn void update_draw_frame()
|
fn void update_draw_frame()
|
||||||
{
|
{
|
||||||
update_game();
|
update_game();
|
||||||
draw_game();
|
draw_game();
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
module snake;
|
module snake;
|
||||||
import raylib5;
|
import raylib55;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* raylib - classic game: snake
|
* raylib - classic game: snake
|
||||||
@@ -16,26 +16,26 @@ const SQUARE_SIZE = 32;
|
|||||||
const int SCREEN_WIDTH = 800;
|
const int SCREEN_WIDTH = 800;
|
||||||
const int SCREEN_HEIGHT = 450;
|
const int SCREEN_HEIGHT = 450;
|
||||||
|
|
||||||
enum SnakeDirection
|
enum SnakeDirection : (RLVector2 dir)
|
||||||
{
|
{
|
||||||
RIGHT,
|
RIGHT = { SQUARE_SIZE, 0 },
|
||||||
DOWN,
|
DOWN = { 0, SQUARE_SIZE },
|
||||||
LEFT,
|
LEFT = { -SQUARE_SIZE, 0 },
|
||||||
UP
|
UP = { 0, -SQUARE_SIZE }
|
||||||
}
|
}
|
||||||
struct Snake
|
struct Snake
|
||||||
{
|
{
|
||||||
Vector2 position;
|
RLVector2 position;
|
||||||
Vector2 size;
|
RLVector2 size;
|
||||||
Color color;
|
RLColor color;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Food
|
struct Food
|
||||||
{
|
{
|
||||||
Vector2 position;
|
RLVector2 position;
|
||||||
Vector2 size;
|
RLVector2 size;
|
||||||
bool active;
|
bool active;
|
||||||
Color color;
|
RLColor color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -46,201 +46,169 @@ bool pause = false;
|
|||||||
Food fruit;
|
Food fruit;
|
||||||
SnakeDirection snake_direction;
|
SnakeDirection snake_direction;
|
||||||
Snake[SNAKE_LENGTH] snake;
|
Snake[SNAKE_LENGTH] snake;
|
||||||
Vector2[SNAKE_LENGTH] snake_position;
|
RLVector2[SNAKE_LENGTH] snake_position;
|
||||||
bool allow_move = false;
|
bool allow_move = false;
|
||||||
Vector2 offset;
|
RLVector2 offset;
|
||||||
int counter_tail = 0;
|
int counter_tail = 0;
|
||||||
|
|
||||||
fn void main()
|
fn void main()
|
||||||
{
|
{
|
||||||
rl::initWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: snake");
|
rl::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: snake");
|
||||||
init_game();
|
init_game();
|
||||||
rl::setTargetFPS(60);
|
rl::set_target_fps(60);
|
||||||
|
|
||||||
while (!rl::windowShouldClose()) // Detect window close button or ESC key
|
while (!rl::window_should_close()) // Detect window close button or ESC key
|
||||||
{
|
{
|
||||||
update_draw_frame();
|
update_draw_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
unload_game();
|
unload_game();
|
||||||
|
|
||||||
rl::closeWindow();
|
rl::close_window();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize game variables
|
// Initialize game variables
|
||||||
fn void init_game()
|
fn void init_game()
|
||||||
{
|
{
|
||||||
frames_counter = 0;
|
frames_counter = 0;
|
||||||
game_over = false;
|
game_over = false;
|
||||||
pause = false;
|
pause = false;
|
||||||
|
|
||||||
counter_tail = 1;
|
counter_tail = 1;
|
||||||
allow_move = false;
|
allow_move = false;
|
||||||
snake_direction = RIGHT;
|
snake_direction = RIGHT;
|
||||||
offset.x = SCREEN_WIDTH % SQUARE_SIZE;
|
offset.x = SCREEN_WIDTH % SQUARE_SIZE;
|
||||||
offset.y = SCREEN_HEIGHT % SQUARE_SIZE;
|
offset.y = SCREEN_HEIGHT % SQUARE_SIZE;
|
||||||
|
foreach (i, &s : snake)
|
||||||
|
{
|
||||||
|
s.position = offset / 2;
|
||||||
|
s.size = (RLVector2)SQUARE_SIZE;
|
||||||
|
s.color = i ? rl::BLUE : rl::DARKBLUE;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < SNAKE_LENGTH; i++)
|
foreach (&pos : snake_position)
|
||||||
{
|
{
|
||||||
snake[i].position = { offset.x / 2, offset.y / 2 };
|
*pos = { 0, 0 };
|
||||||
snake[i].size = { SQUARE_SIZE, SQUARE_SIZE };
|
}
|
||||||
|
|
||||||
if (i == 0)
|
fruit = { .size = (RLVector2)SQUARE_SIZE, .color = rl::SKYBLUE, .active = false };
|
||||||
{
|
|
||||||
snake[i].color = rl::DARKBLUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
snake[i].color = rl::BLUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < SNAKE_LENGTH; i++)
|
|
||||||
{
|
|
||||||
snake_position[i] = { 0.0f, 0.0f };
|
|
||||||
}
|
|
||||||
|
|
||||||
fruit.size = { SQUARE_SIZE, SQUARE_SIZE };
|
|
||||||
fruit.color = rl::SKYBLUE;
|
|
||||||
fruit.active = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn RLVector2 random_fruit_position()
|
||||||
|
{
|
||||||
|
return offset / 2 + { (float)rl::get_random_value(0, SCREEN_WIDTH / SQUARE_SIZE - 1) * SQUARE_SIZE, (float)rl::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE };
|
||||||
|
}
|
||||||
|
|
||||||
fn void update_game()
|
fn void update_game()
|
||||||
{
|
{
|
||||||
if (game_over)
|
if (game_over)
|
||||||
{
|
{
|
||||||
if (rl::isKeyPressed(rl::KEY_ENTER))
|
if (rl::is_key_pressed(ENTER))
|
||||||
{
|
{
|
||||||
init_game();
|
init_game();
|
||||||
game_over = false;
|
game_over = false;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rl::isKeyPressed((KeyboardKey)'P')) pause = !pause;
|
if (rl::is_key_pressed(P)) pause = !pause;
|
||||||
|
|
||||||
if (pause) return;
|
if (pause) return;
|
||||||
|
|
||||||
if (rl::isKeyPressed(rl::KEY_RIGHT) && allow_move)
|
if (rl::is_key_pressed(RIGHT) && allow_move)
|
||||||
{
|
|
||||||
snake_direction = SnakeDirection.from_ordinal((snake_direction.ordinal + 1) % 4);
|
|
||||||
allow_move = false;
|
|
||||||
}
|
|
||||||
if (rl::isKeyPressed(rl::KEY_LEFT) && allow_move)
|
|
||||||
{
|
|
||||||
snake_direction = SnakeDirection.from_ordinal((snake_direction.ordinal + 3) % 4);
|
|
||||||
allow_move = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snake movement
|
|
||||||
for (int i = 0; i < counter_tail; i++) snake_position[i] = snake[i].position;
|
|
||||||
|
|
||||||
if (frames_counter++ % 5 != 0) return;
|
|
||||||
|
|
||||||
allow_move = true;
|
|
||||||
switch (snake_direction)
|
|
||||||
{
|
{
|
||||||
case RIGHT:
|
snake_direction = SnakeDirection.from_ordinal((snake_direction.ordinal + 1) % 4);
|
||||||
snake[0].position.x += SQUARE_SIZE;
|
allow_move = false;
|
||||||
snake[0].position.y += 0;
|
}
|
||||||
case UP:
|
if (rl::is_key_pressed(LEFT) && allow_move)
|
||||||
snake[0].position.x += 0;
|
{
|
||||||
snake[0].position.y += -SQUARE_SIZE;
|
snake_direction = SnakeDirection.from_ordinal((snake_direction.ordinal + 3) % 4);
|
||||||
case DOWN:
|
allow_move = false;
|
||||||
snake[0].position.x += 0;
|
|
||||||
snake[0].position.y += SQUARE_SIZE;
|
|
||||||
case LEFT:
|
|
||||||
snake[0].position.x += -SQUARE_SIZE;
|
|
||||||
snake[0].position.y += 0;
|
|
||||||
default:
|
|
||||||
unreachable();
|
|
||||||
}
|
}
|
||||||
for (int i = 1; i < counter_tail; i++)
|
|
||||||
{
|
|
||||||
snake[i].position = snake_position[i - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wall behaviour
|
// Snake movement
|
||||||
if (((snake[0].position.x) > (SCREEN_WIDTH - offset.x)) ||
|
foreach (i, &sp : snake_position[:counter_tail]) *sp = snake[i].position;
|
||||||
((snake[0].position.y) > (SCREEN_HEIGHT - offset.y)) ||
|
|
||||||
(snake[0].position.x < 0) || (snake[0].position.y < 0))
|
|
||||||
{
|
|
||||||
game_over = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collision with yourself
|
if (frames_counter++ % 20 != 0) return;
|
||||||
for (int i = 1; i < counter_tail; i++)
|
|
||||||
{
|
|
||||||
if ((snake[0].position.x == snake[i].position.x) && (snake[0].position.y == snake[i].position.y)) game_over = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fruit position calculation
|
allow_move = true;
|
||||||
if (!fruit.active)
|
snake[0].position += snake_direction.dir;
|
||||||
{
|
foreach (i, &s : snake[1 .. counter_tail - 1]) s.position = snake_position[i];
|
||||||
fruit.active = true;
|
|
||||||
fruit.position = { (float)rl::getRandomValue(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x / 2, (float)rl::getRandomValue(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
|
||||||
|
|
||||||
for (int i = 0; i < counter_tail; i++)
|
// Wall behaviour
|
||||||
{
|
if (snake[0].position.comp_ge({SCREEN_WIDTH - offset.x, SCREEN_HEIGHT - offset.y}).or() || snake[0].position.comp_lt({ 0, 0 }).or())
|
||||||
while ((fruit.position.x == snake[i].position.x) && (fruit.position.y == snake[i].position.y))
|
{
|
||||||
{
|
game_over = true;
|
||||||
fruit.position = { (float)rl::getRandomValue(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, (float)rl::getRandomValue(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
}
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collision
|
// Collision with yourself
|
||||||
if ((snake[0].position.x < (fruit.position.x + fruit.size.x) && (snake[0].position.x + snake[0].size.x) > fruit.position.x) &&
|
for (int i = 1; i < counter_tail; i++)
|
||||||
(snake[0].position.y < (fruit.position.y + fruit.size.y) && (snake[0].position.y + snake[0].size.y) > fruit.position.y))
|
{
|
||||||
{
|
if (snake[0].position == snake[i].position) game_over = true;
|
||||||
snake[counter_tail].position = snake_position[counter_tail - 1];
|
}
|
||||||
counter_tail += 1;
|
|
||||||
fruit.active = false;
|
// Fruit position calculation
|
||||||
}
|
if (!fruit.active)
|
||||||
|
{
|
||||||
|
fruit.active = true;
|
||||||
|
fruit.position = random_fruit_position();
|
||||||
|
|
||||||
|
for (int i = 0; i < counter_tail; i++)
|
||||||
|
{
|
||||||
|
while (fruit.position == snake[i].position)
|
||||||
|
{
|
||||||
|
fruit.position = random_fruit_position();
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collision
|
||||||
|
if (snake[0].position.comp_lt(fruit.position + fruit.size).and() && fruit.position.comp_lt(snake[0].position + snake[0].size).and())
|
||||||
|
{
|
||||||
|
snake[counter_tail].position = snake_position[counter_tail - 1];
|
||||||
|
counter_tail += 1;
|
||||||
|
fruit.active = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw game (one frame)
|
// Draw game (one frame)
|
||||||
fn void draw_game()
|
fn void draw_game()
|
||||||
{
|
{
|
||||||
rl::beginDrawing();
|
rl::begin_drawing();
|
||||||
|
|
||||||
rl::clearBackground(rl::RAYWHITE);
|
rl::clear_background(rl::RAYWHITE);
|
||||||
|
|
||||||
if (!game_over)
|
defer rl::end_drawing();
|
||||||
{
|
if (game_over)
|
||||||
// Draw grid lines
|
{
|
||||||
for (int i = 0; i < SCREEN_WIDTH / SQUARE_SIZE + 1; i++)
|
rl::draw_text("PRESS [ENTER] TO PLAY AGAIN", rl::get_screen_width() / 2 - rl::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20)/2, rl::get_screen_height() / 2 - 50, 20, rl::GRAY);
|
||||||
{
|
return;
|
||||||
rl::drawLineV({(float)SQUARE_SIZE * i + offset.x/2, offset.y/2}, {(float)SQUARE_SIZE * i + offset.x/2, SCREEN_HEIGHT - offset.y/2}, rl::LIGHTGRAY);
|
}
|
||||||
}
|
// Draw grid lines
|
||||||
|
for (int i = 0; i < SCREEN_WIDTH / SQUARE_SIZE + 1; i++)
|
||||||
|
{
|
||||||
|
rl::draw_line_v(offset / 2 + { (float)SQUARE_SIZE * i, 0}, {(float)SQUARE_SIZE * i + offset.x / 2, SCREEN_HEIGHT - offset.y / 2}, rl::LIGHTGRAY);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < SCREEN_HEIGHT/SQUARE_SIZE + 1; i++)
|
for (int i = 0; i < SCREEN_HEIGHT/SQUARE_SIZE + 1; i++)
|
||||||
{
|
{
|
||||||
rl::drawLineV({offset.x/2, (float)SQUARE_SIZE * i + offset.y / 2 }, { SCREEN_WIDTH - offset.x/2, (float)SQUARE_SIZE * i + offset.y / 2 }, rl::LIGHTGRAY);
|
rl::draw_line_v(offset / 2 + { 0, (float)SQUARE_SIZE * i }, { SCREEN_WIDTH - offset.x/2, (float)SQUARE_SIZE * i + offset.y / 2 }, rl::LIGHTGRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw snake
|
// Draw snake
|
||||||
for (int i = 0; i < counter_tail; i++) rl::drawRectangleV(snake[i].position, snake[i].size, snake[i].color);
|
foreach (&s : snake[:counter_tail]) rl::draw_rectangle_v(s.position, s.size, s.color);
|
||||||
|
|
||||||
// Draw fruit to pick
|
// Draw fruit to pick
|
||||||
rl::drawRectangleV(fruit.position, fruit.size, fruit.color);
|
rl::draw_rectangle_v(fruit.position, fruit.size, fruit.color);
|
||||||
|
|
||||||
if (pause) rl::drawText("GAME PAUSED", SCREEN_WIDTH/2 - rl::measureText("GAME PAUSED", 40)/2, SCREEN_HEIGHT / 2 - 40, 40, rl::GRAY);
|
if (pause) rl::draw_text("GAME PAUSED", SCREEN_WIDTH / 2 - rl::measure_text("GAME PAUSED", 40) / 2, SCREEN_HEIGHT / 2 - 40, 40, rl::GRAY);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rl::drawText("PRESS [ENTER] TO PLAY AGAIN", rl::getScreenWidth()/2 - rl::measureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, rl::getScreenHeight()/2 - 50, 20, rl::GRAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
rl::endDrawing();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unload game variables
|
// Unload game variables
|
||||||
fn void unload_game()
|
fn void unload_game()
|
||||||
{
|
{
|
||||||
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
|
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update and Draw (one frame)
|
// Update and Draw (one frame)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user