mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
0.2.1 SysV ABI fix for passing certain things by struct. Fix implicitly converting to float in the case of myfloat *= -1. Prefer inferred constant over global. Allow locals to shadow global variables.
This commit is contained in:
251
resources/examples/raylib/raylib_snake.c3
Normal file
251
resources/examples/raylib/raylib_snake.c3
Normal file
@@ -0,0 +1,251 @@
|
||||
module snake;
|
||||
/**
|
||||
*
|
||||
* raylib - classic game: snake
|
||||
*
|
||||
* Sample game developed by Ian Eito, Albert Martos and Ramon Santamaria,
|
||||
* converted to C3 and modified by Christoffer Lerno
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
*/
|
||||
|
||||
const SNAKE_LENGTH = 256;
|
||||
const SQUARE_SIZE = 32;
|
||||
const int SCREEN_WIDTH = 800;
|
||||
const int SCREEN_HEIGHT = 450;
|
||||
|
||||
enum SnakeDirection
|
||||
{
|
||||
RIGHT,
|
||||
DOWN,
|
||||
LEFT,
|
||||
UP
|
||||
}
|
||||
struct Snake
|
||||
{
|
||||
Vector2 position;
|
||||
Vector2 size;
|
||||
Color color;
|
||||
}
|
||||
|
||||
struct Food
|
||||
{
|
||||
Vector2 position;
|
||||
Vector2 size;
|
||||
bool active;
|
||||
Color color;
|
||||
}
|
||||
|
||||
|
||||
int frames_counter = 0;
|
||||
bool game_over = false;
|
||||
bool pause = false;
|
||||
|
||||
Food fruit;
|
||||
SnakeDirection snake_direction;
|
||||
Snake[SNAKE_LENGTH] snake;
|
||||
Vector2[SNAKE_LENGTH] snake_position;
|
||||
bool allow_move = false;
|
||||
Vector2 offset;
|
||||
int counter_tail = 0;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: snake");
|
||||
init_game();
|
||||
raylib::set_target_fps(60);
|
||||
|
||||
while (!raylib::window_should_close()) // Detect window close button or ESC key
|
||||
{
|
||||
update_draw_frame();
|
||||
}
|
||||
|
||||
unload_game();
|
||||
|
||||
raylib::close_window();
|
||||
}
|
||||
|
||||
// Initialize game variables
|
||||
fn void init_game()
|
||||
{
|
||||
frames_counter = 0;
|
||||
game_over = false;
|
||||
pause = false;
|
||||
|
||||
counter_tail = 1;
|
||||
allow_move = false;
|
||||
snake_direction = SnakeDirection.RIGHT;
|
||||
offset.x = SCREEN_WIDTH % SQUARE_SIZE;
|
||||
offset.y = SCREEN_HEIGHT % SQUARE_SIZE;
|
||||
|
||||
for (int i = 0; i < SNAKE_LENGTH; i++)
|
||||
{
|
||||
snake[i].position = { offset.x / 2, offset.y / 2 };
|
||||
snake[i].size = { SQUARE_SIZE, SQUARE_SIZE };
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
snake[i].color = raylib::DARKBLUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
snake[i].color = raylib::BLUE;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < SNAKE_LENGTH; i++)
|
||||
{
|
||||
snake_position[i] = { 0.0f, 0.0f };
|
||||
}
|
||||
|
||||
fruit.size = { SQUARE_SIZE, SQUARE_SIZE };
|
||||
fruit.color = raylib::SKYBLUE;
|
||||
fruit.active = false;
|
||||
}
|
||||
|
||||
|
||||
fn void update_game()
|
||||
{
|
||||
if (game_over)
|
||||
{
|
||||
if (raylib::is_key_pressed(keyboard::ENTER))
|
||||
{
|
||||
init_game();
|
||||
game_over = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
|
||||
|
||||
if (pause) return;
|
||||
|
||||
if (raylib::is_key_pressed(keyboard::RIGHT) && allow_move)
|
||||
{
|
||||
snake_direction = (SnakeDirection)((snake_direction + 1) % 4);
|
||||
allow_move = false;
|
||||
}
|
||||
if (raylib::is_key_pressed(keyboard::LEFT) && allow_move)
|
||||
{
|
||||
snake_direction = (SnakeDirection)((snake_direction + 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[0].position.x += SQUARE_SIZE;
|
||||
snake[0].position.y += 0;
|
||||
case UP:
|
||||
snake[0].position.x += 0;
|
||||
snake[0].position.y += -SQUARE_SIZE;
|
||||
case DOWN:
|
||||
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
|
||||
if (((snake[0].position.x) > (SCREEN_WIDTH - offset.x)) ||
|
||||
((snake[0].position.y) > (SCREEN_HEIGHT - offset.y)) ||
|
||||
(snake[0].position.x < 0) || (snake[0].position.y < 0))
|
||||
{
|
||||
game_over = true;
|
||||
}
|
||||
|
||||
// Collision with yourself
|
||||
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
|
||||
if (!fruit.active)
|
||||
{
|
||||
fruit.active = true;
|
||||
fruit.position = { raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
|
||||
for (int i = 0; i < counter_tail; i++)
|
||||
{
|
||||
while ((fruit.position.x == snake[i].position.x) && (fruit.position.y == snake[i].position.y))
|
||||
{
|
||||
fruit.position = { raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collision
|
||||
if ((snake[0].position.x < (fruit.position.x + fruit.size.x) && (snake[0].position.x + snake[0].size.x) > fruit.position.x) &&
|
||||
(snake[0].position.y < (fruit.position.y + fruit.size.y) && (snake[0].position.y + snake[0].size.y) > fruit.position.y))
|
||||
{
|
||||
snake[counter_tail].position = snake_position[counter_tail - 1];
|
||||
counter_tail += 1;
|
||||
fruit.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw game (one frame)
|
||||
fn void draw_game()
|
||||
{
|
||||
raylib::begin_drawing();
|
||||
|
||||
raylib::clear_background(raylib::RAYWHITE);
|
||||
|
||||
if (!game_over)
|
||||
{
|
||||
// Draw grid lines
|
||||
for (int i = 0; i < SCREEN_WIDTH / SQUARE_SIZE + 1; i++)
|
||||
{
|
||||
raylib::draw_line_v({SQUARE_SIZE * i + offset.x/2, offset.y/2}, {SQUARE_SIZE * i + offset.x/2, SCREEN_HEIGHT - offset.y/2}, raylib::LIGHTGRAY);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SCREEN_HEIGHT/SQUARE_SIZE + 1; i++)
|
||||
{
|
||||
raylib::draw_line_v({offset.x/2, SQUARE_SIZE * i + offset.y / 2 }, { SCREEN_WIDTH - offset.x/2, SQUARE_SIZE * i + offset.y / 2 }, raylib::LIGHTGRAY);
|
||||
}
|
||||
|
||||
// Draw snake
|
||||
for (int i = 0; i < counter_tail; i++) raylib::draw_rectangle_v(snake[i].position, snake[i].size, snake[i].color);
|
||||
|
||||
// Draw fruit to pick
|
||||
raylib::draw_rectangle_v(fruit.position, fruit.size, fruit.color);
|
||||
|
||||
if (pause) raylib::draw_text("GAME PAUSED", SCREEN_WIDTH/2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT / 2 - 40, 40, raylib::GRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
raylib::draw_text("PRESS [ENTER] TO PLAY AGAIN", raylib::get_screen_width()/2 - raylib::measure_text("PRESS [ENTER] TO PLAY AGAIN", 20)/2, raylib::get_screen_height()/2 - 50, 20, raylib::GRAY);
|
||||
}
|
||||
|
||||
raylib::end_drawing();
|
||||
}
|
||||
|
||||
// Unload game variables
|
||||
fn void unload_game()
|
||||
{
|
||||
// TODO: Unload all dynamic loaded data (textures, sounds, models...)
|
||||
}
|
||||
|
||||
// Update and Draw (one frame)
|
||||
fn void update_draw_frame()
|
||||
{
|
||||
update_game();
|
||||
draw_game();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user