Created
November 15, 2025 02:13
-
-
Save jbevain/97dde36af5c7b1e957ce7235b80aa84a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #:package [email protected] | |
| // Ported from https://github.com/raysan5/raylib-games/blob/master/classics/src/arkanoid.c | |
| // Sample game developed by Marc Palau and Ramon Santamaria | |
| // Copyright (c) 2015 Ramon Santamaria (@raysan5) | |
| using System.Numerics; | |
| using Raylib_cs; | |
| using static Raylib_cs.Raylib; | |
| const int PlayerMaxLife = 5; | |
| const int LinesOfBricks = 5; | |
| const int BricksPerLine = 20; | |
| const int screenWidth = 800; | |
| const int screenHeight = 450; | |
| bool gameOver = false; | |
| bool pause = false; | |
| Vector2 brickSize; | |
| Player player; | |
| Ball ball; | |
| Brick[,] brick; | |
| InitWindow(screenWidth, screenHeight, "Arkanoid - Raylib-cs"); | |
| SetTargetFPS(60); | |
| Init(); | |
| while (!WindowShouldClose()) | |
| { | |
| Update(); | |
| Draw(); | |
| } | |
| CloseWindow(); | |
| void Init() | |
| { | |
| brickSize = new(screenWidth / BricksPerLine, 40); | |
| player = new() | |
| { | |
| Position = new(screenWidth / 2, screenHeight * 7 / 8), | |
| Size = new(screenWidth / 10, 20), | |
| Life = PlayerMaxLife | |
| }; | |
| ball = new() | |
| { | |
| Position = new(player.Position.X, player.Position.Y - player.Size.Y / 2 - 7), | |
| Radius = 7, | |
| Active = false, | |
| }; | |
| int initialDownPosition = 50; | |
| brick = new Brick[LinesOfBricks, BricksPerLine]; | |
| for (int i = 0; i < LinesOfBricks; i++) | |
| { | |
| for (int j = 0; j < BricksPerLine; j++) | |
| { | |
| brick[i, j].Position = new(j*brickSize.X + brickSize.X/2, i*brickSize.Y + initialDownPosition); | |
| brick[i, j].Active = true; | |
| } | |
| } | |
| } | |
| void Update() | |
| { | |
| if (gameOver) | |
| { | |
| if (IsKeyPressed(KeyboardKey.Enter)) | |
| { | |
| gameOver = false; | |
| Init(); | |
| } | |
| return; | |
| } | |
| if (IsKeyPressed(KeyboardKey.P)) | |
| { | |
| pause = !pause; | |
| } | |
| if (pause) | |
| { | |
| return; | |
| } | |
| if (IsKeyDown(KeyboardKey.Left)) | |
| { | |
| player.Position.X -= 5; | |
| } | |
| if ((player.Position.X - player.Size.X/2) <= 0) | |
| { | |
| player.Position.X = player.Size.X/2; | |
| } | |
| if (IsKeyDown(KeyboardKey.Right)) | |
| { | |
| player.Position.X += 5; | |
| } | |
| if ((player.Position.X + player.Size.X/2) >= screenWidth) | |
| { | |
| player.Position.X = screenWidth - player.Size.X/2; | |
| } | |
| if (!ball.Active && IsKeyPressed(KeyboardKey.Space)) | |
| { | |
| ball.Active = true; | |
| ball.Speed = new(0, -5); | |
| } | |
| if (ball.Active) | |
| { | |
| ball.Position.X += ball.Speed.X; | |
| ball.Position.Y += ball.Speed.Y; | |
| } | |
| else | |
| { | |
| ball.Position = new(player.Position.X, player.Position.Y - player.Size.Y/2 - ball.Radius); | |
| } | |
| if (((ball.Position.X + ball.Radius) >= screenWidth) || ((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) >= screenHeight) | |
| { | |
| ball.Speed = new(0, 0); | |
| ball.Active = false; | |
| player.Life--; | |
| } | |
| if (CheckCollisionCircleRec(ball.Position, ball.Radius, new(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; | |
| } | |
| } | |
| for (int i = 0; i < LinesOfBricks; i++) | |
| { | |
| for (int j = 0; j < BricksPerLine; j++) | |
| { | |
| if (brick[i, j].Active) | |
| { | |
| // Hit below | |
| if (((ball.Position.Y - ball.Radius) <= (brick[i, j].Position.Y + brickSize.Y/2)) && | |
| ((ball.Position.Y - ball.Radius) > (brick[i, j].Position.Y + brickSize.Y/2 + ball.Speed.Y)) && | |
| (MathF.Abs(ball.Position.X - brick[i, j].Position.X) < (brickSize.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 - brickSize.Y/2)) && | |
| ((ball.Position.Y + ball.Radius) < (brick[i, j].Position.Y - brickSize.Y/2 + ball.Speed.Y)) && | |
| (MathF.Abs(ball.Position.X - brick[i, j].Position.X) < (brickSize.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 - brickSize.X/2)) && | |
| ((ball.Position.X + ball.Radius) < (brick[i, j].Position.X - brickSize.X/2 + ball.Speed.X)) && | |
| (MathF.Abs(ball.Position.Y - brick[i, j].Position.Y) < (brickSize.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 + brickSize.X/2)) && | |
| ((ball.Position.X - ball.Radius) > (brick[i, j].Position.X + brickSize.X/2 + ball.Speed.X)) && | |
| (MathF.Abs(ball.Position.Y - brick[i, j].Position.Y) < (brickSize.Y/2 + ball.Radius*2/3)) && (ball.Speed.X < 0)) | |
| { | |
| brick[i, j].Active = false; | |
| ball.Speed.X *= -1; | |
| } | |
| } | |
| } | |
| } | |
| if (player.Life <= 0) | |
| { | |
| gameOver = true; | |
| } | |
| else | |
| { | |
| gameOver = true; | |
| for (int i = 0; i < LinesOfBricks; i++) | |
| { | |
| for (int j = 0; j < BricksPerLine; j++) | |
| { | |
| if (brick[i, j].Active) gameOver = false; | |
| } | |
| } | |
| } | |
| } | |
| void Draw() | |
| { | |
| BeginDrawing(); | |
| ClearBackground(Color.RayWhite); | |
| if (gameOver) | |
| { | |
| DrawText("PRESS [ENTER] TO PLAY AGAIN", | |
| GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, | |
| GetScreenHeight()/2 - 50, 20, | |
| Color.Gray); | |
| EndDrawing(); | |
| return; | |
| } | |
| DrawRectangleF(player.Position.X - player.Size.X/2, player.Position.Y - player.Size.Y/2, player.Size.X, player.Size.Y, Color.Black); | |
| for (int i = 0; i < player.Life; i++) | |
| { | |
| DrawRectangle(20 + 40*i, screenHeight - 30, 35, 10, Color.LightGray); | |
| } | |
| DrawCircleV(ball.Position, ball.Radius, Color.Maroon); | |
| for (int i = 0; i < LinesOfBricks; i++) | |
| { | |
| for (int j = 0; j < BricksPerLine; j++) | |
| { | |
| if (brick[i, j].Active) | |
| { | |
| if ((i + j) % 2 == 0) | |
| DrawRectangleF(brick[i, j].Position.X - brickSize.X/2, brick[i, j].Position.Y - brickSize.Y/2, brickSize.X, brickSize.Y, Color.Gray); | |
| else | |
| DrawRectangleF(brick[i, j].Position.X - brickSize.X/2, brick[i, j].Position.Y - brickSize.Y/2, brickSize.X, brickSize.Y, Color.DarkGray); | |
| } | |
| } | |
| } | |
| EndDrawing(); | |
| } | |
| static void DrawRectangleF(float x, float y, float width, float height, Color color) =>DrawRectangle((int)x, (int)y, (int)width, (int)height, color); | |
| struct Player | |
| { | |
| public Vector2 Position; | |
| public Vector2 Size; | |
| public int Life; | |
| } | |
| struct Ball | |
| { | |
| public Vector2 Position; | |
| public Vector2 Speed; | |
| public int Radius; | |
| public bool Active; | |
| } | |
| struct Brick | |
| { | |
| public Vector2 Position; | |
| public bool Active; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment