mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +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:
312
resources/examples/raylib/raylib_arkanoid.c3
Normal file
312
resources/examples/raylib/raylib_arkanoid.c3
Normal file
@@ -0,0 +1,312 @@
|
||||
module arkanoid;
|
||||
/**
|
||||
*
|
||||
* raylib - classic game: arkanoid
|
||||
*
|
||||
* Sample game developed by Marc Palau and Ramon Santamaria
|
||||
* converted to C3 by Christoffer Lerno
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
*/
|
||||
|
||||
const int SCREEN_WIDTH = 800;
|
||||
const int SCREEN_HEIGHT = 450;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Some Defines
|
||||
//----------------------------------------------------------------------------------
|
||||
const PLAYER_MAX_LIFE = 5;
|
||||
const LINES_OF_BRICKS = 5;
|
||||
const BRICKS_PER_LINE = 20;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
enum GameScreen
|
||||
{
|
||||
LOGO,
|
||||
TITLE,
|
||||
GAMEPLAY,
|
||||
ENDING
|
||||
}
|
||||
|
||||
struct Player
|
||||
{
|
||||
Vector2 position;
|
||||
Vector2 size;
|
||||
int life;
|
||||
}
|
||||
|
||||
struct Ball
|
||||
{
|
||||
Vector2 position;
|
||||
Vector2 speed;
|
||||
int radius;
|
||||
bool active;
|
||||
}
|
||||
|
||||
struct Brick
|
||||
{
|
||||
Vector2 position;
|
||||
bool active;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Global Variables Declaration
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
bool game_over = false;
|
||||
bool pause = false;
|
||||
|
||||
Player player;
|
||||
Ball ball;
|
||||
Brick[BRICKS_PER_LINE][LINES_OF_BRICKS] brick;
|
||||
Vector2 brick_size;
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
fn void main()
|
||||
{
|
||||
// Initialization (Note windowTitle is unused on Android)
|
||||
//---------------------------------------------------------
|
||||
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: arkanoid");
|
||||
|
||||
init_game();
|
||||
|
||||
raylib::set_target_fps(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!raylib::window_should_close()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update and Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
update_draw_frame();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
unload_game(); // Unload loaded data (textures, sounds, models...)
|
||||
|
||||
raylib::close_window(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definitions (local)
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
// Initialize game variables
|
||||
fn void init_game()
|
||||
{
|
||||
brick_size = { raylib::get_screen_width() / BRICKS_PER_LINE, 40 };
|
||||
|
||||
// Initialize player
|
||||
player.position = { SCREEN_WIDTH/2, SCREEN_HEIGHT * 7 / 8 };
|
||||
player.size = { SCREEN_WIDTH / 10, 20 };
|
||||
player.life = PLAYER_MAX_LIFE;
|
||||
|
||||
// Initialize ball
|
||||
ball.position = { SCREEN_WIDTH / 2, SCREEN_HEIGHT * 7 / 8 - 30 };
|
||||
ball.speed = { 0, 0 };
|
||||
ball.radius = 7;
|
||||
ball.active = false;
|
||||
|
||||
// Initialize bricks
|
||||
int initial_down_position = 50;
|
||||
|
||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||
{
|
||||
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].active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update game (one frame)
|
||||
fn void update_game()
|
||||
{
|
||||
if (game_over)
|
||||
{
|
||||
if (raylib::is_key_pressed(keyboard::ENTER))
|
||||
{
|
||||
init_game();
|
||||
game_over = false;
|
||||
}
|
||||
}
|
||||
if (raylib::is_key_pressed((KeyboardKey)'P')) pause = !pause;
|
||||
|
||||
if (pause) return;
|
||||
// Player movement logic
|
||||
if (raylib::is_key_down(keyboard::LEFT)) player.position.x -= 5;
|
||||
if ((player.position.x - player.size.x/2) <= 0) player.position.x = player.size.x/2;
|
||||
if (raylib::is_key_down(keyboard::RIGHT)) player.position.x += 5;
|
||||
if ((player.position.x + player.size.x/2) >= SCREEN_WIDTH) player.position.x = SCREEN_WIDTH - player.size.x/2;
|
||||
|
||||
// Ball launching logic
|
||||
if (!ball.active)
|
||||
{
|
||||
if (raylib::is_key_pressed(keyboard::SPACE))
|
||||
{
|
||||
ball.active = true;
|
||||
ball.speed = { 0, -5 };
|
||||
}
|
||||
}
|
||||
|
||||
// Ball movement logic
|
||||
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
|
||||
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;
|
||||
if ((ball.position.y + ball.radius) >= SCREEN_HEIGHT)
|
||||
{
|
||||
ball.speed = { 0, 0 };
|
||||
ball.active = false;
|
||||
|
||||
player.life--;
|
||||
}
|
||||
|
||||
// Collision logic: ball vs player
|
||||
if (raylib::check_collision_circle_rec(ball.position, ball.radius,
|
||||
Rectangle{ player.position.x - player.size.x / 2, player.position.y - player.size.y / 2, player.size.x, player.size.y}))
|
||||
{
|
||||
if (ball.speed.y > 0)
|
||||
{
|
||||
ball.speed.y *= -1;
|
||||
ball.speed.x = (ball.position.x - player.position.x) / (player.size.x / 2) * 5;
|
||||
}
|
||||
}
|
||||
|
||||
// Collision logic: ball vs bricks
|
||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||
{
|
||||
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
||||
{
|
||||
if (brick[i][j].active)
|
||||
{
|
||||
// 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::fabs((double)ball.position.x - brick[i][j].position.x)) < (double)(brick_size.x / 2 + ball.radius * 2 / 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::fabs((double)ball.position.x - brick[i][j].position.x)) < (double)(brick_size.x/2 + ball.radius*2/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::fabs((double)ball.position.y - brick[i][j].position.y)) < (double)(brick_size.y/2 + ball.radius*2/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::fabs((double)ball.position.y - brick[i][j].position.y)) < (double)(brick_size.y/2 + ball.radius*2/3)) && (ball.speed.x < 0))
|
||||
{
|
||||
brick[i][j].active = false;
|
||||
ball.speed.x *= -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Game over logic
|
||||
if (player.life <= 0)
|
||||
{
|
||||
game_over = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
game_over = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw game (one frame)
|
||||
fn void draw_game()
|
||||
{
|
||||
raylib::begin_drawing();
|
||||
|
||||
raylib::clear_background(raylib::RAYWHITE);
|
||||
|
||||
if (!game_over)
|
||||
{
|
||||
// Draw player bar
|
||||
raylib::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, raylib::BLACK);
|
||||
|
||||
// Draw player lives
|
||||
for (int i = 0; i < player.life; i++) raylib::draw_rectangle(20 + 40*i, SCREEN_HEIGHT - 30, 35, 10, raylib::LIGHTGRAY);
|
||||
|
||||
// Draw ball
|
||||
raylib::draw_circle_v(ball.position, ball.radius, raylib::MAROON);
|
||||
|
||||
// Draw bricks
|
||||
for (int i = 0; i < LINES_OF_BRICKS; i++)
|
||||
{
|
||||
for (int j = 0; j < BRICKS_PER_LINE; j++)
|
||||
{
|
||||
if (brick[i][j].active)
|
||||
{
|
||||
if ((i + j) % 2 == 0)
|
||||
{
|
||||
raylib::draw_rectangle((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, raylib::GRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
raylib::draw_rectangle((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, raylib::DARKGRAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
793
resources/examples/raylib/raylib_tetris.c3
Normal file
793
resources/examples/raylib/raylib_tetris.c3
Normal file
@@ -0,0 +1,793 @@
|
||||
module tetris;
|
||||
/**
|
||||
* raylib - classic game: tetris
|
||||
*
|
||||
* Sample game developed by Marc Palau and Ramon Santamaria,
|
||||
* converted to C3 by Christoffer Lerno.
|
||||
*
|
||||
* This game has been created using raylib v1.3 (www.raylib.com)
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Some Defines
|
||||
//----------------------------------------------------------------------------------
|
||||
const SQUARE_SIZE = 20;
|
||||
const GRID_HORIZONTAL_SIZE = 12;
|
||||
const GRID_VERTICAL_SIZE = 20;
|
||||
|
||||
const LATERAL_SPEED = 10;
|
||||
const TURNING_SPEED = 12;
|
||||
const FAST_FALL_AWAIT_COUNTER = 30;
|
||||
const FADING_TIME = 33;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
enum GridSquare { EMPTY, MOVING, FULL, BLOCK, FADING }
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Global Variables Declaration
|
||||
//------------------------------------------------------------------------------------
|
||||
const int SCREEN_WIDTH = 800;
|
||||
const int SCREEN_HEIGHT = 450;
|
||||
|
||||
bool game_over = false;
|
||||
bool pause = false;
|
||||
|
||||
// Matrices
|
||||
GridSquare[GRID_VERTICAL_SIZE][GRID_HORIZONTAL_SIZE] grid;
|
||||
GridSquare[4][4] piece;
|
||||
GridSquare[4][4] incoming_piece;
|
||||
|
||||
struct IntVec
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
}
|
||||
// These variables keep track of the active piece position
|
||||
int piece_position_x = 0;
|
||||
int piece_position_y = 0;
|
||||
|
||||
// Game parameters
|
||||
Color fading_color;
|
||||
//int fallingSpeed; // In frames
|
||||
|
||||
bool begin_play = true; // This var is only true at the begining of the game, used for the first matrix creations
|
||||
bool piece_active = false;
|
||||
bool detection = false;
|
||||
bool line_to_delete = false;
|
||||
|
||||
// Statistics
|
||||
int level = 1;
|
||||
int lines = 0;
|
||||
|
||||
// Counters
|
||||
int gravity_movement_counter = 0;
|
||||
int lateral_movement_counter = 0;
|
||||
int turn_movement_counter = 0;
|
||||
int fast_fall_movement_counter = 0;
|
||||
|
||||
int fade_line_counter = 0;
|
||||
|
||||
// Based on level
|
||||
int gravity_speed = 30;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
fn void main()
|
||||
{
|
||||
// Initialization (Note windowTitle is unused on Android)
|
||||
//---------------------------------------------------------
|
||||
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: tetris");
|
||||
|
||||
init_game();
|
||||
|
||||
raylib::set_target_fps(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!raylib::window_should_close()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update and Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
update_draw_frame();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
unload_game(); // Unload loaded data (textures, sounds, models...)
|
||||
|
||||
raylib::close_window(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Game Module Functions Definition
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Initialize game variables
|
||||
fn void init_game()
|
||||
{
|
||||
// Initialize game statistics
|
||||
level = 1;
|
||||
lines = 0;
|
||||
|
||||
fading_color = raylib::GRAY;
|
||||
|
||||
piece_position_x = 0;
|
||||
piece_position_y = 0;
|
||||
|
||||
pause = false;
|
||||
|
||||
begin_play = true;
|
||||
piece_active = false;
|
||||
detection = false;
|
||||
line_to_delete = false;
|
||||
|
||||
// Counters
|
||||
gravity_movement_counter = 0;
|
||||
lateral_movement_counter = 0;
|
||||
turn_movement_counter = 0;
|
||||
fast_fall_movement_counter = 0;
|
||||
|
||||
fade_line_counter = 0;
|
||||
gravity_speed = 30;
|
||||
|
||||
// Initialize grid matrices
|
||||
for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++)
|
||||
{
|
||||
for (int j = 0; j < GRID_VERTICAL_SIZE; j++)
|
||||
{
|
||||
if ((j == GRID_VERTICAL_SIZE - 1) || (i == 0) || (i == GRID_HORIZONTAL_SIZE - 1))
|
||||
{
|
||||
grid[i][j] = BLOCK;
|
||||
}
|
||||
else
|
||||
{
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize incoming piece matrices
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j< 4; j++)
|
||||
{
|
||||
incoming_piece[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update game (one frame)
|
||||
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 (line_to_delete)
|
||||
{
|
||||
// Animation when deleting lines
|
||||
fade_line_counter++;
|
||||
|
||||
fading_color = fade_line_counter % 8 < 4 ? raylib::MAROON : raylib::GRAY;
|
||||
|
||||
if (fade_line_counter >= FADING_TIME)
|
||||
{
|
||||
lines += delete_complete_lines();
|
||||
fade_line_counter = 0;
|
||||
line_to_delete = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!piece_active)
|
||||
{
|
||||
// Get another piece
|
||||
piece_active = create_piece();
|
||||
|
||||
// We leave a little time before starting the fast falling down
|
||||
fast_fall_movement_counter = 0;
|
||||
}
|
||||
else // Piece falling
|
||||
{
|
||||
// Counters update
|
||||
fast_fall_movement_counter++;
|
||||
gravity_movement_counter++;
|
||||
lateral_movement_counter++;
|
||||
turn_movement_counter++;
|
||||
|
||||
// We make sure to move if we've pressed the key this frame
|
||||
if (raylib::is_key_pressed(keyboard::LEFT) || raylib::is_key_pressed(keyboard::RIGHT)) lateral_movement_counter = LATERAL_SPEED;
|
||||
if (raylib::is_key_pressed(keyboard::UP)) turn_movement_counter = TURNING_SPEED;
|
||||
|
||||
// Fall down
|
||||
if (raylib::is_key_down(keyboard::DOWN) && (fast_fall_movement_counter >= FAST_FALL_AWAIT_COUNTER))
|
||||
{
|
||||
// We make sure the piece is going to fall this frame
|
||||
gravity_movement_counter += gravity_speed;
|
||||
}
|
||||
|
||||
if (gravity_movement_counter >= gravity_speed)
|
||||
{
|
||||
// Basic falling movement
|
||||
if (check_detection()) detection = true;
|
||||
|
||||
// Check if the piece has collided with another piece or with the boundings
|
||||
resolve_falling_movement(&detection, &piece_active);
|
||||
|
||||
// Check if we fullfilled a line and if so, erase the line and pull down the the lines above
|
||||
check_completion(&line_to_delete);
|
||||
|
||||
gravity_movement_counter = 0;
|
||||
}
|
||||
|
||||
// Move laterally at player's will
|
||||
if (lateral_movement_counter >= LATERAL_SPEED)
|
||||
{
|
||||
// Update the lateral movement and if success, reset the lateral counter
|
||||
if (!resolve_lateral_movement()) lateral_movement_counter = 0;
|
||||
}
|
||||
|
||||
// Turn the piece at player's will
|
||||
if (turn_movement_counter >= TURNING_SPEED)
|
||||
{
|
||||
// Update the turning movement and reset the turning counter
|
||||
if (resolve_turn_movement()) turn_movement_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Game over logic
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.FULL)
|
||||
{
|
||||
game_over = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw game (one frame)
|
||||
fn void draw_game()
|
||||
{
|
||||
raylib::begin_drawing();
|
||||
|
||||
raylib::clear_background(raylib::RAYWHITE);
|
||||
|
||||
if (game_over)
|
||||
{
|
||||
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();
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw gameplay area
|
||||
IntVec offset = {
|
||||
SCREEN_WIDTH / 2 - (GRID_HORIZONTAL_SIZE * SQUARE_SIZE / 2) - 50,
|
||||
SCREEN_HEIGHT / 2 - ((GRID_VERTICAL_SIZE - 1) * SQUARE_SIZE / 2) + SQUARE_SIZE * 2
|
||||
};
|
||||
offset.y -= 50; // NOTE: Harcoded position!
|
||||
|
||||
int controller = offset.x;
|
||||
|
||||
for (int j = 0; j < GRID_VERTICAL_SIZE; j++)
|
||||
{
|
||||
for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++)
|
||||
{
|
||||
// Draw each square of the grid
|
||||
switch (grid[i][j])
|
||||
{
|
||||
case EMPTY:
|
||||
raylib::draw_line(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
offset.x += SQUARE_SIZE;
|
||||
case FULL:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::GRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case MOVING:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::DARKGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case BLOCK:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case FADING:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, fading_color);
|
||||
offset.x += SQUARE_SIZE;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
offset.x = controller;
|
||||
offset.y += SQUARE_SIZE;
|
||||
}
|
||||
|
||||
// Draw incoming piece (hardcoded)
|
||||
offset.x = 500;
|
||||
offset.y = 45;
|
||||
|
||||
controller = offset.x;
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
switch (incoming_piece[i][j])
|
||||
{
|
||||
case EMPTY:
|
||||
raylib::draw_line(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case MOVING:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::GRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
offset.x = controller;
|
||||
offset.y += SQUARE_SIZE;
|
||||
}
|
||||
|
||||
raylib::draw_text("INCOMING:", offset.x, offset.y - 100, 10, raylib::GRAY);
|
||||
raylib::draw_text(raylib::text_format("LINES: %04i", lines), offset.x, offset.y + 20, 10, raylib::GRAY);
|
||||
|
||||
if (pause)
|
||||
{
|
||||
raylib::draw_text("GAME PAUSED", SCREEN_WIDTH / 2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, 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();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Additional module functions
|
||||
//--------------------------------------------------------------------------------------
|
||||
fn bool create_piece()
|
||||
{
|
||||
piece_position_x = (int)((GRID_HORIZONTAL_SIZE - 4)/2);
|
||||
piece_position_y = 0;
|
||||
|
||||
// If the game is starting and you are going to create the first piece, we create an extra one
|
||||
if (begin_play)
|
||||
{
|
||||
get_random_piece();
|
||||
begin_play = false;
|
||||
}
|
||||
|
||||
// We assign the incoming piece to the actual piece
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j< 4; j++)
|
||||
{
|
||||
piece[i][j] = incoming_piece[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// We assign a random piece to the incoming one
|
||||
get_random_piece();
|
||||
|
||||
// Assign the piece to the grid
|
||||
for (int i = piece_position_x; i < piece_position_x + 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (piece[i - (int)piece_position_x][j] == GridSquare.MOVING) grid[i][j] = MOVING;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void get_random_piece()
|
||||
{
|
||||
int random = raylib::get_random_value(0, 6);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
incoming_piece[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
switch (random)
|
||||
{
|
||||
case 0:
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][2] = MOVING; //Cube
|
||||
case 1:
|
||||
incoming_piece[1][0] = MOVING;
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][2] = MOVING; //L
|
||||
case 2:
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][0] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[2][2] = MOVING; //L inversa
|
||||
case 3:
|
||||
incoming_piece[0][1] = MOVING;
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[3][1] = MOVING; //Recta
|
||||
case 4:
|
||||
incoming_piece[1][0] = MOVING;
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][1] = MOVING; //Creu tallada
|
||||
case 5:
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[2][2] = MOVING;
|
||||
incoming_piece[3][2] = MOVING; //S
|
||||
case 6:
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][2] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[3][1] = MOVING; //S inversa
|
||||
default:
|
||||
@unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
fn void resolve_falling_movement(bool* detection_ref, bool* piece_active_ref)
|
||||
{
|
||||
// If we finished moving this piece, we stop it
|
||||
if (*detection_ref)
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j] = FULL;
|
||||
*detection_ref = false;
|
||||
*piece_active_ref = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // We move down the piece
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j+1] = MOVING;
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
piece_position_y++;
|
||||
}
|
||||
}
|
||||
|
||||
fn bool resolve_lateral_movement()
|
||||
{
|
||||
bool collision = false;
|
||||
|
||||
// Piece movement
|
||||
if (raylib::is_key_down(keyboard::LEFT)) // Move left
|
||||
{
|
||||
// Check if is possible to move to left
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
// Check if we are touching the left wall or we have a full square at the left
|
||||
if ((i-1 == 0) || (grid[i-1][j] == GridSquare.FULL)) collision = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If able, move left
|
||||
if (!collision)
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) // We check the matrix from left to right
|
||||
{
|
||||
// Move everything to the left
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i-1][j] = MOVING;
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
piece_position_x--;
|
||||
}
|
||||
}
|
||||
else if (raylib::is_key_down(keyboard::RIGHT)) // Move right
|
||||
{
|
||||
// Check if is possible to move to right
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
// Check if we are touching the right wall or we have a full square at the right
|
||||
if ((i+1 == GRID_HORIZONTAL_SIZE - 1) || (grid[i+1][j] == GridSquare.FULL))
|
||||
{
|
||||
collision = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If able move right
|
||||
if (!collision)
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = GRID_HORIZONTAL_SIZE - 1; i >= 1; i--) // We check the matrix from right to left
|
||||
{
|
||||
// Move everything to the right
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i+1][j] = MOVING;
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
piece_position_x++;
|
||||
}
|
||||
}
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
fn bool resolve_turn_movement()
|
||||
{
|
||||
// Input for turning the piece
|
||||
if (raylib::is_key_down(keyboard::UP))
|
||||
{
|
||||
GridSquare aux;
|
||||
bool checker = false;
|
||||
|
||||
// Check all turning possibilities
|
||||
if ((grid[piece_position_x + 3][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 3][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 3][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 3][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if (!checker)
|
||||
{
|
||||
aux = piece[0][0];
|
||||
piece[0][0] = piece[3][0];
|
||||
piece[3][0] = piece[3][3];
|
||||
piece[3][3] = piece[0][3];
|
||||
piece[0][3] = aux;
|
||||
|
||||
aux = piece[1][0];
|
||||
piece[1][0] = piece[3][1];
|
||||
piece[3][1] = piece[2][3];
|
||||
piece[2][3] = piece[0][2];
|
||||
piece[0][2] = aux;
|
||||
|
||||
aux = piece[2][0];
|
||||
piece[2][0] = piece[3][2];
|
||||
piece[3][2] = piece[1][3];
|
||||
piece[1][3] = piece[0][1];
|
||||
piece[0][1] = aux;
|
||||
|
||||
aux = piece[1][1];
|
||||
piece[1][1] = piece[2][1];
|
||||
piece[2][1] = piece[2][2];
|
||||
piece[2][2] = piece[1][2];
|
||||
piece[1][2] = aux;
|
||||
}
|
||||
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = piece_position_x; i < piece_position_x + 4; i++)
|
||||
{
|
||||
for (int j = piece_position_y; j < piece_position_y + 4; j++)
|
||||
{
|
||||
if (piece[i - piece_position_x][j - piece_position_y] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j] = MOVING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn bool check_detection()
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if ((grid[i][j] == GridSquare.MOVING) && ((grid[i][j+1] == GridSquare.FULL)
|
||||
|| (grid[i][j+1] == GridSquare.BLOCK))) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void check_completion(bool *line_to_delete_ref)
|
||||
{
|
||||
int calculator = 0;
|
||||
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
calculator = 0;
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
// Count each square of the line
|
||||
if (grid[i][j] == GridSquare.FULL)
|
||||
{
|
||||
calculator++;
|
||||
}
|
||||
|
||||
// Check if we completed the whole line
|
||||
if (calculator == GRID_HORIZONTAL_SIZE - 2)
|
||||
{
|
||||
*line_to_delete_ref = true;
|
||||
calculator = 0;
|
||||
// points++;
|
||||
|
||||
// Mark the completed line
|
||||
for (int z = 1; z < GRID_HORIZONTAL_SIZE - 1; z++)
|
||||
{
|
||||
grid[z][j] = FADING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn int delete_complete_lines()
|
||||
{
|
||||
int lines_to_erase = 0;
|
||||
// Erase the completed line
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
while (grid[1][j] == GridSquare.FADING)
|
||||
{
|
||||
lines_to_erase++;
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
grid[i][j] = GridSquare.EMPTY;
|
||||
}
|
||||
|
||||
for (int j2 = j-1; j2 >= 0; j2--)
|
||||
{
|
||||
for (int i2 = 1; i2 < GRID_HORIZONTAL_SIZE - 1; i2++)
|
||||
{
|
||||
switch (grid[i2][j2])
|
||||
{
|
||||
case FULL:
|
||||
grid[i2][j2+1] = GridSquare.FULL;
|
||||
grid[i2][j2] = GridSquare.EMPTY;
|
||||
case FADING:
|
||||
grid[i2][j2+1] = GridSquare.FADING;
|
||||
grid[i2][j2] = GridSquare.EMPTY;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return lines_to_erase;
|
||||
}
|
||||
|
||||
@@ -1,167 +1,791 @@
|
||||
module foo;
|
||||
extern fn void printf(char*, ...);
|
||||
module tetris;
|
||||
/**
|
||||
* raylib - classic game: tetris
|
||||
*
|
||||
* Sample game developed by Marc Palau and Ramon Santamaria,
|
||||
* converted to C3 by Christoffer Lerno.
|
||||
*
|
||||
* This game has been created using raylib v1.3 (www.raylib.com)
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
*/
|
||||
|
||||
enum Foo : int (int offset, char* extra_name, double x)
|
||||
//----------------------------------------------------------------------------------
|
||||
// Some Defines
|
||||
//----------------------------------------------------------------------------------
|
||||
const SQUARE_SIZE = 20;
|
||||
const GRID_HORIZONTAL_SIZE = 12;
|
||||
const GRID_VERTICAL_SIZE = 20;
|
||||
|
||||
const LATERAL_SPEED = 10;
|
||||
const TURNING_SPEED = 12;
|
||||
const FAST_FALL_AWAIT_COUNTER = 30;
|
||||
const FADING_TIME = 33;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
enum GridSquare { EMPTY, MOVING, FULL, BLOCK, FADING }
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Global Variables Declaration
|
||||
//------------------------------------------------------------------------------------
|
||||
const int SCREEN_WIDTH = 800;
|
||||
const int SCREEN_HEIGHT = 450;
|
||||
|
||||
bool game_over = false;
|
||||
bool pause = false;
|
||||
|
||||
// Matrices
|
||||
GridSquare[GRID_VERTICAL_SIZE][GRID_HORIZONTAL_SIZE] grid;
|
||||
GridSquare[4][4] piece;
|
||||
GridSquare[4][4] incoming_piece;
|
||||
|
||||
struct IntVec
|
||||
{
|
||||
BAZ(12, "hello", 3.0),
|
||||
BOO(33, "oekfe", 4.0) = 3,
|
||||
int x;
|
||||
int y;
|
||||
}
|
||||
// These variables keep track of the active piece position
|
||||
int piece_position_x = 0;
|
||||
int piece_position_y = 0;
|
||||
|
||||
// Game parameters
|
||||
Color fading_color;
|
||||
//int fallingSpeed; // In frames
|
||||
|
||||
bool begin_play = true; // This var is only true at the begining of the game, used for the first matrix creations
|
||||
bool piece_active = false;
|
||||
bool detection = false;
|
||||
bool line_to_delete = false;
|
||||
|
||||
// Statistics
|
||||
int level = 1;
|
||||
int lines = 0;
|
||||
|
||||
// Counters
|
||||
int gravity_movement_counter = 0;
|
||||
int lateral_movement_counter = 0;
|
||||
int turn_movement_counter = 0;
|
||||
int fast_fall_movement_counter = 0;
|
||||
|
||||
int fade_line_counter = 0;
|
||||
|
||||
// Based on level
|
||||
int gravity_speed = 30;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
fn void main()
|
||||
{
|
||||
int screenWidth = 800;
|
||||
int screenHeight = 450;
|
||||
// Initialization (Note windowTitle is unused on Android)
|
||||
//---------------------------------------------------------
|
||||
raylib::init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "classic game: tetris");
|
||||
|
||||
raylib::init_window(screenWidth, screenHeight, "raylib [core] example - keyboard input");
|
||||
init_game();
|
||||
|
||||
Vector2 ballPosition = { (float)screenWidth/2, (float)screenHeight/2 };
|
||||
|
||||
raylib::set_target_fps(60); // Set our game to run at 60 frames-per-second
|
||||
raylib::set_target_fps(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
foo2::tester(screenHeight);
|
||||
|
||||
// Main game loop
|
||||
while (!raylib::window_should_close()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
// Update and Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
if (raylib::is_key_down(KeyboardKey.RIGHT)) ballPosition.x += 2.0f;
|
||||
if (raylib::is_key_down(KeyboardKey.LEFT)) ballPosition.x -= 2.0f;
|
||||
if (raylib::is_key_down(KeyboardKey.UP)) ballPosition.y -= 2.0f;
|
||||
if (raylib::is_key_down(KeyboardKey.DOWN)) ballPosition.y += 2.0f;
|
||||
update_draw_frame();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
unload_game(); // Unload loaded data (textures, sounds, models...)
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
raylib::close_window(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Game Module Functions Definition
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Initialize game variables
|
||||
fn void init_game()
|
||||
{
|
||||
// Initialize game statistics
|
||||
level = 1;
|
||||
lines = 0;
|
||||
|
||||
fading_color = raylib::GRAY;
|
||||
|
||||
piece_position_x = 0;
|
||||
piece_position_y = 0;
|
||||
|
||||
pause = false;
|
||||
|
||||
begin_play = true;
|
||||
piece_active = false;
|
||||
detection = false;
|
||||
line_to_delete = false;
|
||||
|
||||
// Counters
|
||||
gravity_movement_counter = 0;
|
||||
lateral_movement_counter = 0;
|
||||
turn_movement_counter = 0;
|
||||
fast_fall_movement_counter = 0;
|
||||
|
||||
fade_line_counter = 0;
|
||||
gravity_speed = 30;
|
||||
|
||||
// Initialize grid matrices
|
||||
for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++)
|
||||
{
|
||||
for (int j = 0; j < GRID_VERTICAL_SIZE; j++)
|
||||
{
|
||||
if ((j == GRID_VERTICAL_SIZE - 1) || (i == 0) || (i == GRID_HORIZONTAL_SIZE - 1))
|
||||
{
|
||||
grid[i][j] = BLOCK;
|
||||
}
|
||||
else
|
||||
{
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize incoming piece matrices
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j< 4; j++)
|
||||
{
|
||||
incoming_piece[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update game (one frame)
|
||||
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 (line_to_delete)
|
||||
{
|
||||
// Animation when deleting lines
|
||||
fade_line_counter++;
|
||||
|
||||
fading_color = fade_line_counter % 8 < 4 ? raylib::MAROON : raylib::GRAY;
|
||||
|
||||
if (fade_line_counter >= FADING_TIME)
|
||||
{
|
||||
lines += delete_complete_lines();
|
||||
fade_line_counter = 0;
|
||||
line_to_delete = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!piece_active)
|
||||
{
|
||||
// Get another piece
|
||||
piece_active = create_piece();
|
||||
|
||||
// We leave a little time before starting the fast falling down
|
||||
fast_fall_movement_counter = 0;
|
||||
}
|
||||
else // Piece falling
|
||||
{
|
||||
// Counters update
|
||||
fast_fall_movement_counter++;
|
||||
gravity_movement_counter++;
|
||||
lateral_movement_counter++;
|
||||
turn_movement_counter++;
|
||||
|
||||
// We make sure to move if we've pressed the key this frame
|
||||
if (raylib::is_key_pressed(keyboard::LEFT) || raylib::is_key_pressed(keyboard::RIGHT)) lateral_movement_counter = LATERAL_SPEED;
|
||||
if (raylib::is_key_pressed(keyboard::UP)) turn_movement_counter = TURNING_SPEED;
|
||||
|
||||
// Fall down
|
||||
if (raylib::is_key_down(keyboard::DOWN) && (fast_fall_movement_counter >= FAST_FALL_AWAIT_COUNTER))
|
||||
{
|
||||
// We make sure the piece is going to fall this frame
|
||||
gravity_movement_counter += gravity_speed;
|
||||
}
|
||||
|
||||
if (gravity_movement_counter >= gravity_speed)
|
||||
{
|
||||
// Basic falling movement
|
||||
check_detection(&detection);
|
||||
|
||||
// Check if the piece has collided with another piece or with the boundings
|
||||
resolve_falling_movement(&detection, &piece_active);
|
||||
|
||||
// Check if we fullfilled a line and if so, erase the line and pull down the the lines above
|
||||
check_completion(&line_to_delete);
|
||||
|
||||
gravity_movement_counter = 0;
|
||||
}
|
||||
|
||||
// Move laterally at player's will
|
||||
if (lateral_movement_counter >= LATERAL_SPEED)
|
||||
{
|
||||
// Update the lateral movement and if success, reset the lateral counter
|
||||
if (!resolve_lateral_movement()) lateral_movement_counter = 0;
|
||||
}
|
||||
|
||||
// Turn the piece at player's will
|
||||
if (turn_movement_counter >= TURNING_SPEED)
|
||||
{
|
||||
// Update the turning movement and reset the turning counter
|
||||
if (resolve_turn_movement()) turn_movement_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Game over logic
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.FULL)
|
||||
{
|
||||
game_over = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw game (one frame)
|
||||
fn void draw_game()
|
||||
{
|
||||
raylib::begin_drawing();
|
||||
|
||||
raylib::clear_background(raylib::RAYWHITE);
|
||||
|
||||
raylib::draw_text("move the ball with arrow keys", 10, 10, 20, raylib::DARKGRAY);
|
||||
|
||||
raylib::draw_circle_v(ballPosition, 50, raylib::MAROON);
|
||||
|
||||
if (game_over)
|
||||
{
|
||||
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();
|
||||
//----------------------------------------------------------------------------------
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw gameplay area
|
||||
IntVec offset = {
|
||||
SCREEN_WIDTH / 2 - (GRID_HORIZONTAL_SIZE * SQUARE_SIZE / 2) - 50,
|
||||
SCREEN_HEIGHT / 2 - ((GRID_VERTICAL_SIZE - 1) * SQUARE_SIZE / 2) + SQUARE_SIZE * 2
|
||||
};
|
||||
offset.y -= 50; // NOTE: Harcoded position!
|
||||
|
||||
int controller = offset.x;
|
||||
|
||||
for (int j = 0; j < GRID_VERTICAL_SIZE; j++)
|
||||
{
|
||||
for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++)
|
||||
{
|
||||
// Draw each square of the grid
|
||||
switch (grid[i][j])
|
||||
{
|
||||
case EMPTY:
|
||||
raylib::draw_line(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
raylib::draw_line(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY );
|
||||
offset.x += SQUARE_SIZE;
|
||||
case FULL:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::GRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case MOVING:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::DARKGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case BLOCK:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case FADING:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, fading_color);
|
||||
offset.x += SQUARE_SIZE;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
offset.x = controller;
|
||||
offset.y += SQUARE_SIZE;
|
||||
}
|
||||
|
||||
// Draw incoming piece (hardcoded)
|
||||
offset.x = 500;
|
||||
offset.y = 45;
|
||||
|
||||
controller = offset.x;
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
switch (incoming_piece[i][j])
|
||||
{
|
||||
case EMPTY:
|
||||
raylib::draw_line(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
raylib::draw_line(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, raylib::LIGHTGRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
case MOVING:
|
||||
raylib::draw_rectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, raylib::GRAY);
|
||||
offset.x += SQUARE_SIZE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
offset.x = controller;
|
||||
offset.y += SQUARE_SIZE;
|
||||
}
|
||||
|
||||
raylib::draw_text("INCOMING:", offset.x, offset.y - 100, 10, raylib::GRAY);
|
||||
raylib::draw_text(raylib::text_format("LINES: %04i", lines), offset.x, offset.y + 20, 10, raylib::GRAY);
|
||||
|
||||
if (pause)
|
||||
{
|
||||
raylib::draw_text("GAME PAUSED", SCREEN_WIDTH / 2 - raylib::measure_text("GAME PAUSED", 40)/2, SCREEN_HEIGHT/2 - 40, 40, 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();
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
raylib::close_window(); // Close window and OpenGL context
|
||||
// Additional module functions
|
||||
//--------------------------------------------------------------------------------------
|
||||
}
|
||||
/*
|
||||
struct Game
|
||||
fn bool create_piece()
|
||||
{
|
||||
int answer;
|
||||
bool done;
|
||||
int guesses;
|
||||
int high;
|
||||
}
|
||||
piece_position_x = (int)((GRID_HORIZONTAL_SIZE - 4)/2);
|
||||
piece_position_y = 0;
|
||||
|
||||
int err_count = 0;
|
||||
|
||||
|
||||
import "core:bufio"
|
||||
import "core:fmt"
|
||||
import "core:io"
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:strconv"
|
||||
import "core:time"
|
||||
import "core:math/rand"
|
||||
|
||||
Game :: struct {
|
||||
answer: int,
|
||||
done: bool,
|
||||
guesses: int,
|
||||
high: int,
|
||||
}
|
||||
|
||||
int err_count = 0;
|
||||
*/
|
||||
/*
|
||||
fn int ask_guess(int high)
|
||||
// If the game is starting and you are going to create the first piece, we create an extra one
|
||||
if (begin_play)
|
||||
{
|
||||
libc::printf("Guess a number between 1 and %d: ", high);
|
||||
|
||||
}
|
||||
ask_guess :: proc(high: int) -> (result: int, ok: bool) {
|
||||
fmt.printf("Guess a number between 1 and %d: ", high)
|
||||
if text, ok := read_line(); ok {
|
||||
defer mem.delete(text)
|
||||
return strconv.parse_int(s = text, base = 10)
|
||||
}
|
||||
return
|
||||
get_random_piece();
|
||||
begin_play = false;
|
||||
}
|
||||
|
||||
ask_guess_multi :: proc(high: int) -> int {
|
||||
for {
|
||||
if result, ok := ask_guess(high); ok {
|
||||
return result
|
||||
}
|
||||
fmt.println("I didn't understand")
|
||||
err_count += 1
|
||||
}
|
||||
}
|
||||
|
||||
pick_answer :: proc(high: int, r: ^rand.Rand) -> int {
|
||||
return rand.int_max(high, r) + 1
|
||||
}
|
||||
|
||||
play :: proc(game: ^Game) {
|
||||
for !game.done {
|
||||
guess := ask_guess_multi(game.high)
|
||||
report(game^, guess)
|
||||
game^ = update(game^, guess)
|
||||
}
|
||||
}
|
||||
|
||||
read_line :: proc() -> (result: string, ok: bool) {
|
||||
// See also:
|
||||
// - https://github.com/odin-lang/Odin/issues/1214
|
||||
// - https://p.teknik.io/Raw/IT996
|
||||
s := os.stream_from_handle(os.stdin)
|
||||
r: bufio.Reader
|
||||
bufio.reader_init(&r, io.Reader{s})
|
||||
defer bufio.reader_destroy(&r)
|
||||
if line, err := bufio.reader_read_string(&r, '\n'); err == .None {
|
||||
return line[:len(line) - 1], true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
report :: proc(game: Game, guess: int) {
|
||||
// game.done = true
|
||||
// fmt.println(&game)
|
||||
description := (
|
||||
"too low" if guess < game.answer else
|
||||
"too high" if guess > game.answer else
|
||||
"the answer!"
|
||||
)
|
||||
fmt.println(guess, "is", description)
|
||||
}
|
||||
|
||||
update :: proc(game: Game, guess: int) -> (next: Game) {
|
||||
next = game
|
||||
next.done = guess == game.answer
|
||||
next.guesses += 1
|
||||
return
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
high :: 100
|
||||
r := rand.create(transmute(u64)time.now())
|
||||
// Or use nil for default random.
|
||||
answer := pick_answer(high, &r)
|
||||
game := Game {answer = answer, done = false, guesses = 0, high = high}
|
||||
play(&game)
|
||||
fmt.println("Finished in", game.guesses, "guesses");
|
||||
fmt.println("Total input errors:", err_count)
|
||||
}
|
||||
*/
|
||||
|
||||
module foo2;
|
||||
fn void tester(int x)
|
||||
// We assign the incoming piece to the actual piece
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
assert(x > 1000, "Shit!");
|
||||
for (int j = 0; j< 4; j++)
|
||||
{
|
||||
piece[i][j] = incoming_piece[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// We assign a random piece to the incoming one
|
||||
get_random_piece();
|
||||
|
||||
// Assign the piece to the grid
|
||||
for (int i = piece_position_x; i < piece_position_x + 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (piece[i - (int)piece_position_x][j] == GridSquare.MOVING) grid[i][j] = MOVING;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void get_random_piece()
|
||||
{
|
||||
int random = raylib::get_random_value(0, 6);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
incoming_piece[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
switch (random)
|
||||
{
|
||||
case 0:
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][2] = MOVING; //Cube
|
||||
case 1:
|
||||
incoming_piece[1][0] = MOVING;
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][2] = MOVING; //L
|
||||
case 2:
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][0] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[2][2] = MOVING; //L inversa
|
||||
case 3:
|
||||
incoming_piece[0][1] = MOVING;
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[3][1] = MOVING; //Recta
|
||||
case 4:
|
||||
incoming_piece[1][0] = MOVING;
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][1] = MOVING; //Creu tallada
|
||||
case 5:
|
||||
incoming_piece[1][1] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[2][2] = MOVING;
|
||||
incoming_piece[3][2] = MOVING; //S
|
||||
case 6:
|
||||
incoming_piece[1][2] = MOVING;
|
||||
incoming_piece[2][2] = MOVING;
|
||||
incoming_piece[2][1] = MOVING;
|
||||
incoming_piece[3][1] = MOVING; //S inversa
|
||||
default:
|
||||
@unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
fn void resolve_falling_movement(bool* detection_ref, bool* piece_active_ref)
|
||||
{
|
||||
// If we finished moving this piece, we stop it
|
||||
if (*detection_ref)
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j] = FULL;
|
||||
*detection_ref = false;
|
||||
*piece_active_ref = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // We move down the piece
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j+1] = MOVING;
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
piece_position_y++;
|
||||
}
|
||||
}
|
||||
|
||||
fn bool resolve_lateral_movement()
|
||||
{
|
||||
bool collision = false;
|
||||
|
||||
// Piece movement
|
||||
if (raylib::is_key_down(keyboard::LEFT)) // Move left
|
||||
{
|
||||
// Check if is possible to move to left
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
// Check if we are touching the left wall or we have a full square at the left
|
||||
if ((i-1 == 0) || (grid[i-1][j] == GridSquare.FULL)) collision = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If able, move left
|
||||
if (!collision)
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) // We check the matrix from left to right
|
||||
{
|
||||
// Move everything to the left
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i-1][j] = MOVING;
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
piece_position_x--;
|
||||
}
|
||||
}
|
||||
else if (raylib::is_key_down(keyboard::RIGHT)) // Move right
|
||||
{
|
||||
// Check if is possible to move to right
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
// Check if we are touching the right wall or we have a full square at the right
|
||||
if ((i+1 == GRID_HORIZONTAL_SIZE - 1) || (grid[i+1][j] == GridSquare.FULL))
|
||||
{
|
||||
collision = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If able move right
|
||||
if (!collision)
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = GRID_HORIZONTAL_SIZE - 1; i >= 1; i--) // We check the matrix from right to left
|
||||
{
|
||||
// Move everything to the right
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i+1][j] = MOVING;
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
piece_position_x++;
|
||||
}
|
||||
}
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
fn bool resolve_turn_movement()
|
||||
{
|
||||
// Input for turning the piece
|
||||
if (raylib::is_key_down(keyboard::UP))
|
||||
{
|
||||
GridSquare aux;
|
||||
bool checker = false;
|
||||
|
||||
// Check all turning possibilities
|
||||
if ((grid[piece_position_x + 3][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 3][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 3][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 3][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y + 3] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 3][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 3] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 3] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y + 1] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 1][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 2][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 1] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 1] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if ((grid[piece_position_x + 1][piece_position_y + 2] == GridSquare.MOVING) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 2] != GridSquare.EMPTY) &&
|
||||
(grid[piece_position_x + 2][piece_position_y + 2] != GridSquare.MOVING)) checker = true;
|
||||
|
||||
if (!checker)
|
||||
{
|
||||
aux = piece[0][0];
|
||||
piece[0][0] = piece[3][0];
|
||||
piece[3][0] = piece[3][3];
|
||||
piece[3][3] = piece[0][3];
|
||||
piece[0][3] = aux;
|
||||
|
||||
aux = piece[1][0];
|
||||
piece[1][0] = piece[3][1];
|
||||
piece[3][1] = piece[2][3];
|
||||
piece[2][3] = piece[0][2];
|
||||
piece[0][2] = aux;
|
||||
|
||||
aux = piece[2][0];
|
||||
piece[2][0] = piece[3][2];
|
||||
piece[3][2] = piece[1][3];
|
||||
piece[1][3] = piece[0][1];
|
||||
piece[0][1] = aux;
|
||||
|
||||
aux = piece[1][1];
|
||||
piece[1][1] = piece[2][1];
|
||||
piece[2][1] = piece[2][2];
|
||||
piece[2][2] = piece[1][2];
|
||||
piece[1][2] = aux;
|
||||
}
|
||||
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if (grid[i][j] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = piece_position_x; i < piece_position_x + 4; i++)
|
||||
{
|
||||
for (int j = piece_position_y; j < piece_position_y + 4; j++)
|
||||
{
|
||||
if (piece[i - piece_position_x][j - piece_position_y] == GridSquare.MOVING)
|
||||
{
|
||||
grid[i][j] = MOVING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void check_detection(bool *detection_ref)
|
||||
{
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
if ((grid[i][j] == GridSquare.MOVING) && ((grid[i][j+1] == GridSquare.FULL) || (grid[i][j+1] == GridSquare.BLOCK))) *detection_ref = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void check_completion(bool *line_to_delete_ref)
|
||||
{
|
||||
int calculator = 0;
|
||||
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
calculator = 0;
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
// Count each square of the line
|
||||
if (grid[i][j] == GridSquare.FULL)
|
||||
{
|
||||
calculator++;
|
||||
}
|
||||
|
||||
// Check if we completed the whole line
|
||||
if (calculator == GRID_HORIZONTAL_SIZE - 2)
|
||||
{
|
||||
*line_to_delete_ref = true;
|
||||
calculator = 0;
|
||||
// points++;
|
||||
|
||||
// Mark the completed line
|
||||
for (int z = 1; z < GRID_HORIZONTAL_SIZE - 1; z++)
|
||||
{
|
||||
grid[z][j] = FADING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn int delete_complete_lines()
|
||||
{
|
||||
int lines_to_erase = 0;
|
||||
// Erase the completed line
|
||||
for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
|
||||
{
|
||||
while (grid[1][j] == GridSquare.FADING)
|
||||
{
|
||||
lines_to_erase++;
|
||||
for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
|
||||
{
|
||||
grid[i][j] = GridSquare.EMPTY;
|
||||
}
|
||||
|
||||
for (int j2 = j-1; j2 >= 0; j2--)
|
||||
{
|
||||
for (int i2 = 1; i2 < GRID_HORIZONTAL_SIZE - 1; i2++)
|
||||
{
|
||||
switch (grid[i2][j2])
|
||||
{
|
||||
case FULL:
|
||||
grid[i2][j2+1] = GridSquare.FULL;
|
||||
grid[i2][j2] = GridSquare.EMPTY;
|
||||
case FADING:
|
||||
grid[i2][j2+1] = GridSquare.FADING;
|
||||
grid[i2][j2] = GridSquare.EMPTY;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return lines_to_erase;
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ LLVMValueRef llvm_emit_coerce_alignment(GenContext *c, BEValue *be_value, LLVMTy
|
||||
LLVMValueRef target = LLVMBuildBitCast(c->builder, cast, LLVMPointerType(coerce_type, 0), "");
|
||||
llvm_store_value_aligned(c, target, be_value, target_alignment);
|
||||
*resulting_alignment = target_alignment;
|
||||
return cast;
|
||||
return target;
|
||||
}
|
||||
*resulting_alignment = be_value->alignment;
|
||||
return LLVMBuildBitCast(c->builder, be_value->value, LLVMPointerType(coerce_type, 0), "");
|
||||
|
||||
@@ -191,6 +191,7 @@ bool float_const_fits_type(const ExprConst *expr_const, TypeKind kind)
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
assert(expr_const->const_kind == CONST_FLOAT);
|
||||
return expr_const->fxx.f >= -lo_limit && expr_const->fxx.f <= hi_limit;
|
||||
}
|
||||
|
||||
|
||||
@@ -671,6 +671,16 @@ bool may_convert_float_const_implicit(Expr *expr, Type *to_type)
|
||||
bool may_convert_int_const_implicit(Expr *expr, Type *to_type)
|
||||
{
|
||||
Type *to_type_flat = type_flatten(to_type);
|
||||
switch (to_type_flat->type_kind)
|
||||
{
|
||||
case ALL_FLOATS:
|
||||
case TYPE_BOOL:
|
||||
return true;
|
||||
case ALL_INTS:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (expr_const_will_overflow(&expr->const_expr, to_type_flat->type_kind))
|
||||
{
|
||||
sema_error_const_int_out_of_range(expr, expr, to_type);
|
||||
|
||||
@@ -883,15 +883,17 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
|
||||
Decl *private_symbol = NULL;
|
||||
|
||||
DEBUG_LOG("Now resolving %s", expr->identifier_expr.ident);
|
||||
|
||||
// Just start with inference
|
||||
if (!expr->identifier_expr.path && to)
|
||||
{
|
||||
if (find_possible_inferred_identifier(to, expr)) return true;
|
||||
}
|
||||
|
||||
Decl *decl = sema_find_path_symbol(context, expr->identifier_expr.ident, expr->identifier_expr.path);
|
||||
// Is this a broken decl?
|
||||
if (!decl_ok(decl)) return false;
|
||||
|
||||
// Just no real way to find it, try inference
|
||||
if (!decl && !expr->identifier_expr.path && to)
|
||||
{
|
||||
if (find_possible_inferred_identifier(to, expr)) return true;
|
||||
}
|
||||
|
||||
// Rerun if we can't do inference.
|
||||
if (!decl)
|
||||
@@ -3051,6 +3053,7 @@ static inline void expr_replace_with_enum_array(Expr *enum_array_expr, Decl *enu
|
||||
Expr *expr = expr_new(EXPR_CONST, span);
|
||||
expr->const_expr.const_kind = CONST_ENUM;
|
||||
expr->const_expr.enum_val = decl;
|
||||
assert(decl_ok(decl));
|
||||
expr->type = kind;
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
vec_add(element_values, expr);
|
||||
|
||||
@@ -187,13 +187,8 @@ static Decl *sema_resolve_path_symbol(SemaContext *context, NameResolve *name_re
|
||||
return decl ? decl : sema_find_decl_in_global(&global_context.symbols, global_context.module_list, name_resolve, false);
|
||||
}
|
||||
|
||||
static Decl *sema_resolve_no_path_symbol(SemaContext *context, NameResolve *name_resolve)
|
||||
static inline Decl *sema_find_local(SemaContext *context, const char *symbol)
|
||||
{
|
||||
Decl *decl = NULL;
|
||||
|
||||
const char *symbol = name_resolve->symbol;
|
||||
assert(name_resolve->path == NULL);
|
||||
|
||||
Decl **locals = context->locals;
|
||||
if (context->active_scope.current_local > 0)
|
||||
{
|
||||
@@ -210,7 +205,7 @@ static Decl *sema_resolve_no_path_symbol(SemaContext *context, NameResolve *name
|
||||
VarDeclKind kind = cur->var.kind;
|
||||
|
||||
// In this case, we erase the value from parent scopes, so it isn't visible here.
|
||||
if (kind == VARDECL_ERASE) goto JUMP_ERASED;
|
||||
if (kind == VARDECL_ERASE) return NULL;
|
||||
if (kind == VARDECL_REWRAPPED) return cur->var.alias;
|
||||
}
|
||||
return cur;
|
||||
@@ -218,7 +213,18 @@ static Decl *sema_resolve_no_path_symbol(SemaContext *context, NameResolve *name
|
||||
current--;
|
||||
}
|
||||
}
|
||||
JUMP_ERASED:;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Decl *sema_resolve_no_path_symbol(SemaContext *context, NameResolve *name_resolve)
|
||||
{
|
||||
Decl *decl = NULL;
|
||||
|
||||
const char *symbol = name_resolve->symbol;
|
||||
assert(name_resolve->path == NULL);
|
||||
|
||||
Decl *found = sema_find_local(context, symbol);
|
||||
if (found) return found;
|
||||
|
||||
CompilationUnit *unit = context->unit;
|
||||
|
||||
@@ -507,7 +513,8 @@ bool sema_add_local(SemaContext *context, Decl *decl)
|
||||
// Ignore synthetic locals.
|
||||
if (!decl->name) return true;
|
||||
if (decl->decl_kind == DECL_VAR && decl->var.shadow) goto ADD_VAR;
|
||||
Decl *other = sema_find_symbol(context, decl->name);
|
||||
|
||||
Decl *other = sema_find_local(context, decl->name);
|
||||
assert(!other || other->module);
|
||||
if (other && (other->module == current_module || other->is_autoimport))
|
||||
{
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.2.0"
|
||||
#define COMPILER_VERSION "0.2.1"
|
||||
47
test/test_suite/abi/sysv_direct_coerce.c3t
Normal file
47
test/test_suite/abi/sysv_direct_coerce.c3t
Normal file
@@ -0,0 +1,47 @@
|
||||
// #target: macos-x64
|
||||
module foo;
|
||||
|
||||
struct Rectangle
|
||||
{
|
||||
float x; // Rectangle top-left corner position x
|
||||
float y; // Rectangle top-left corner position y
|
||||
float width; // Rectangle width
|
||||
float height; // Rectangle height
|
||||
}
|
||||
|
||||
fn void test(Rectangle r)
|
||||
{
|
||||
test(Rectangle { 1, 2, 3, 4 });
|
||||
}
|
||||
|
||||
/* #expect: foo.ll
|
||||
|
||||
define void @foo.test(<2 x float> %0, <2 x float> %1) #0 {
|
||||
entry:
|
||||
%r = alloca %Rectangle, align 4
|
||||
%literal = alloca %Rectangle, align 4
|
||||
%coerce = alloca %Rectangle, align 8
|
||||
%pair = bitcast %Rectangle* %r to { <2 x float>, <2 x float> }*
|
||||
%2 = getelementptr inbounds { <2 x float>, <2 x float> }, { <2 x float>, <2 x float> }* %pair, i32 0, i32 0
|
||||
store <2 x float> %0, <2 x float>* %2, align 4
|
||||
%3 = getelementptr inbounds { <2 x float>, <2 x float> }, { <2 x float>, <2 x float> }* %pair, i32 0, i32 1
|
||||
store <2 x float> %1, <2 x float>* %3, align 4
|
||||
%4 = getelementptr inbounds %Rectangle, %Rectangle* %literal, i32 0, i32 0
|
||||
store float 1.000000e+00, float* %4, align 4
|
||||
%5 = getelementptr inbounds %Rectangle, %Rectangle* %literal, i32 0, i32 1
|
||||
store float 2.000000e+00, float* %5, align 4
|
||||
%6 = getelementptr inbounds %Rectangle, %Rectangle* %literal, i32 0, i32 2
|
||||
store float 3.000000e+00, float* %6, align 4
|
||||
%7 = getelementptr inbounds %Rectangle, %Rectangle* %literal, i32 0, i32 3
|
||||
store float 4.000000e+00, float* %7, align 4
|
||||
%8 = bitcast %Rectangle* %coerce to { <2 x float>, <2 x float> }*
|
||||
%9 = bitcast { <2 x float>, <2 x float> }* %8 to i8*
|
||||
%10 = bitcast %Rectangle* %literal to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %9, i8* align 4 %10, i32 16, i1 false)
|
||||
%11 = getelementptr inbounds { <2 x float>, <2 x float> }, { <2 x float>, <2 x float> }* %8, i32 0, i32 0
|
||||
%lo = load <2 x float>, <2 x float>* %11, align 8
|
||||
%12 = getelementptr inbounds { <2 x float>, <2 x float> }, { <2 x float>, <2 x float> }* %8, i32 0, i32 1
|
||||
%hi = load <2 x float>, <2 x float>* %12, align 8
|
||||
call void @foo.test(<2 x float> %lo, <2 x float> %hi)
|
||||
ret void
|
||||
}
|
||||
24
test/test_suite/floats/convert_float.c3t
Normal file
24
test/test_suite/floats/convert_float.c3t
Normal file
@@ -0,0 +1,24 @@
|
||||
// #target: macos-x64
|
||||
module foo;
|
||||
|
||||
fn void test()
|
||||
{
|
||||
float x = 12;
|
||||
x *= -1;
|
||||
double y = x;
|
||||
}
|
||||
|
||||
/* #expect: foo.ll
|
||||
define void @foo.test() #0 {
|
||||
entry:
|
||||
%x = alloca float, align 4
|
||||
%y = alloca double, align 8
|
||||
store float 1.200000e+01, float* %x, align 4
|
||||
%0 = load float, float* %x, align 4
|
||||
%fmul = fmul float %0, -1.000000e+00
|
||||
store float %fmul, float* %x, align 4
|
||||
%1 = load float, float* %x, align 4
|
||||
%fpfpext = fpext float %1 to double
|
||||
store double %fpfpext, double* %y, align 8
|
||||
ret void
|
||||
}
|
||||
10
test/test_suite/symbols/allow_local_shadowing.c3
Normal file
10
test/test_suite/symbols/allow_local_shadowing.c3
Normal file
@@ -0,0 +1,10 @@
|
||||
int foo;
|
||||
|
||||
fn void x()
|
||||
{
|
||||
double foo = 123;
|
||||
}
|
||||
|
||||
fn void y(int foo)
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user