Watch
2
0
Fork
You've already forked raylib-cs
0

WASM examples (+ backports of new official examples) (#344)

* chg: New build system that uses the officially distributed binaries, bumped version to 8.0.0, simplified git workflow, removed deprecated OpenGL 1.1 functionality.

* chg: Modernize CI workflow, enable SourceLink

- Bump workflow actions to latest majors (Node 24); drop deprecated softprops/action-gh-release@v1
- Trigger push builds on main instead of master
- Create local nuget feed dir before pack (fixes NU1301)
- Enable Microsoft.SourceLink.GitHub for debugging symbols (ref PR #340)

* fix: centralized version data in Directory.build.props, and fixed various interop details that had incorrect function signatures

* chore: updated readme

* fix: version the native extract marker and chain download via DependsOnTargets

The .extracted marker now includes the raylib package name, so bumping
TargetRaylibTag re-extracts the new archive instead of silently keeping
(and packing/copying) the previous version's files.

_PrepareNativeLibrary and _StageWasmNative now depend directly on
_DownloadAndExtractInternal instead of CallTarget-ing it; dependency
targets run in the same project instance, so the resolved properties
(RaylibPackageName etc.) propagate naturally.

* fix: let the binding build for browser-wasm on both net8.0 and net10.0

The net8-era wasm workload (Microsoft.NET.Runtime.WebAssembly.Sdk 8.0.x,
auto-imported for RID browser-wasm) treats every browser-wasm project as
a wasm app: it forces OutputType=Exe after project evaluation (CS5001
for a classlib) and hooks its app-bundle build after Build, which errors
because a library has no assemblies to bundle. Opt Raylib-cs out via
DisableAutoWasmBuildApp (props time, before the workload defaults its
trigger) and pin OutputType back to Library in Directory.Build.targets
(evaluated after the workload props, so the assignment wins). net10's
wasm SDK needs neither workaround.

* chore: readme updated

* chg: simplifying build logic - a simple line in the documentation should save us the code here

* fix: Wrong signature of FrameBufferComplete

* chore: readme update

* feat: samples default to local project reference, and can optionally use the nuget package

* feat: backporting existing raylib-cs examples and new official raylib examples to WASM, adopting raylib's original code style

* chore: readme, gitignore, and targets backport.

* fix: Examples.csproj runs the download task when building locally

* feat: backporting existing raylib-cs examples and new official raylib examples to WASM, adopting raylib's original code style

* chore: readme, gitignore, and targets backport.

* chore: clean up linter warnings

* feat: html harness focuses the example and allows quick navigation with J/K instead.

* chore: readme mentions the property to use nuget vs. the local project reference

* feat: replaced the J/K navigation with good old HTML buttons

* chore: run dotnet format scoped default (was previously scoped to just 'style')
This commit is contained in:
tiger tiger tiger 2026-07-30 19:34:34 +02:00 committed by GitHub
commit 8c22e68c2a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
236 changed files with 40405 additions and 10896 deletions

View file

@ -0,0 +1,278 @@
/*******************************************************************************************
*
* raylib [shapes] example - ball physics
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.0
*
* Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 David Buzatto (@davidbuzatto)
*
********************************************************************************************/
using static Raylib_cs.Raymath;
namespace Examples.Shapes;
public partial class BallPhysics : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int MAX_BALLS = 5000; // Maximum quantity of balls
public string Name => "Shapes / Ball Physics";
public string Title => "raylib [shapes] example - ball physics";
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Ball data type
private struct Ball
{
public Vector2 position;
public Vector2 speed;
public Vector2 prevPosition;
public float radius;
public float friction;
public float elasticity;
public Color color;
public bool grabbed;
}
private Ball[] balls;
private int ballCount;
private int grabbedBallIndex; // Index of the current ball that is grabbed (-1 if none)
private Vector2 pressOffset; // Mouse press offset relative to the ball that grabbedd
private float gravity; // World gravity
private Vector2 windowPosition;
public void Init()
{
balls = new Ball[MAX_BALLS];
// Init first ball in the array
balls[0] = new Ball
{
position = new Vector2(GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f),
speed = new Vector2(200, 200),
prevPosition = new Vector2(0, 0),
radius = 40,
friction = 0.99f,
elasticity = 0.9f,
color = Color.Blue,
grabbed = false
};
ballCount = 1;
grabbedBallIndex = -1; // A reference to the current ball that is grabbed
pressOffset = new Vector2(0, 0); // Mouse press offset relative to the ball that grabbedd
gravity = 100; // World gravity
windowPosition = GetWindowPosition();
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
float delta = GetFrameTime();
Vector2 mousePos = GetMousePosition();
// Checks if a ball was grabbed
if (IsMouseButtonPressed(MouseButton.Left))
{
for (int i = ballCount - 1; i >= 0; i--)
{
pressOffset.X = mousePos.X - balls[i].position.X;
pressOffset.Y = mousePos.Y - balls[i].position.Y;
// If the distance between the ball position and the mouse press position
// is less than or equal to the ball radius, the event occurred inside the ball
if (MathF.Sqrt(pressOffset.X * pressOffset.X + pressOffset.Y * pressOffset.Y) <= balls[i].radius)
{
balls[i].grabbed = true;
grabbedBallIndex = i;
break;
}
}
}
// Releases any ball the was grabbed
if (IsMouseButtonReleased(MouseButton.Left))
{
if (grabbedBallIndex != -1)
{
balls[grabbedBallIndex].grabbed = false;
grabbedBallIndex = -1;
}
}
// Creates a new ball
if (IsMouseButtonPressed(MouseButton.Right) || (IsKeyDown(KeyboardKey.LeftControl) && IsMouseButtonDown(MouseButton.Right)))
{
if (ballCount < MAX_BALLS)
{
balls[ballCount++] = new Ball
{
position = mousePos,
speed = new Vector2(GetRandomValue(-300, 300), GetRandomValue(-300, 300)),
prevPosition = new Vector2(0, 0),
radius = 20.0f + GetRandomValue(0, 30),
friction = 0.99f,
elasticity = 0.9f,
color = new Color(GetRandomValue(0, 255), GetRandomValue(0, 255), GetRandomValue(0, 255), 255),
grabbed = false
};
}
}
// Get window position change for shaking
Vector2 windowPositionDelta = Vector2Subtract(windowPosition, GetWindowPosition());
if (Vector2Length(windowPositionDelta) > 5.0f)
{
for (int i = 0; i < ballCount; i++)
{
if (!balls[i].grabbed)
{
balls[i].speed = Vector2Add(balls[i].speed, Vector2Scale(windowPositionDelta, 10.0f));
}
}
}
// Shake balls
if (IsMouseButtonPressed(MouseButton.Middle))
{
for (int i = 0; i < ballCount; i++)
{
if (!balls[i].grabbed)
{
balls[i].speed = new Vector2(GetRandomValue(-2000, 2000), GetRandomValue(-2000, 2000));
}
}
}
// Changes gravity
gravity += GetMouseWheelMove() * 5;
// Updates each ball state
for (int i = 0; i < ballCount; i++)
{
// The ball is not grabbed
if (!balls[i].grabbed)
{
// Ball repositioning using the velocity
balls[i].position.X += balls[i].speed.X * delta;
balls[i].position.Y += balls[i].speed.Y * delta;
// Does the ball hit the screen right boundary?
if ((balls[i].position.X + balls[i].radius) >= screenWidth)
{
balls[i].position.X = screenWidth - balls[i].radius; // Ball repositioning
balls[i].speed.X = -balls[i].speed.X * balls[i].elasticity; // Elasticity makes the ball lose 10% of its velocity on hit
}
// Does the ball hit the screen left boundary?
else if ((balls[i].position.X - balls[i].radius) <= 0)
{
balls[i].position.X = balls[i].radius;
balls[i].speed.X = -balls[i].speed.X * balls[i].elasticity;
}
// The same for y axis
if ((balls[i].position.Y + balls[i].radius) >= screenHeight)
{
balls[i].position.Y = screenHeight - balls[i].radius;
balls[i].speed.Y = -balls[i].speed.Y * balls[i].elasticity;
}
else if ((balls[i].position.Y - balls[i].radius) <= 0)
{
balls[i].position.Y = balls[i].radius;
balls[i].speed.Y = -balls[i].speed.Y * balls[i].elasticity;
}
// Friction makes the ball lose 1% of its velocity each frame
balls[i].speed.X = balls[i].speed.X * balls[i].friction;
// Gravity affects only the y axis
balls[i].speed.Y = balls[i].speed.Y * balls[i].friction + gravity;
}
else
{
// Ball repositioning using the mouse position
balls[i].position.X = mousePos.X - pressOffset.X;
balls[i].position.Y = mousePos.Y - pressOffset.Y;
// While the ball is grabbed, recalculates its velocity
balls[i].speed.X = (balls[i].position.X - balls[i].prevPosition.X) / delta;
balls[i].speed.Y = (balls[i].position.Y - balls[i].prevPosition.Y) / delta;
balls[i].prevPosition = balls[i].position;
}
}
windowPosition = GetWindowPosition();
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
for (int i = 0; i < ballCount; i++)
{
DrawCircleV(balls[i].position, balls[i].radius, balls[i].color);
DrawCircleLinesV(balls[i].position, balls[i].radius, Color.Black);
}
DrawText("grab a ball by pressing with the mouse and throw it by releasing", 10, 10, 10, Color.DarkGray);
DrawText("right click to create new balls (keep left control pressed to create a lot)", 10, 30, 10, Color.DarkGray);
DrawText("use mouse wheel to change gravity", 10, 50, 10, Color.DarkGray);
DrawText("middle click to shake", 10, 70, 10, Color.DarkGray);
DrawText($"BALL COUNT: {ballCount}", 10, GetScreenHeight() - 70, 20, Color.Black);
DrawText($"GRAVITY: {gravity:F2}", 10, GetScreenHeight() - 40, 20, Color.Black);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - ball physics");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new BallPhysics();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,79 +1,115 @@
/*******************************************************************************************
*
* raylib [shapes] example - Draw basic shapes 2d (rectangle, circle, line...)
* raylib [shapes] example - basic shapes
*
* This example has been created using raylib 1.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 1/4
*
* Copyright (c) 2014 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.0, last time updated with raylib 4.2
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class BasicShapes
public partial class BasicShapes : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Basic Shapes";
public string Title => "raylib [shapes] example - basic shapes";
private float rotation;
public void Init()
{
rotation = 0.0f;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
rotation += 0.2f;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("some basic shapes available on raylib", 20, 20, 20, Color.DarkGray);
// Circle shapes and lines
DrawCircle(screenWidth / 5, 120, 35, Color.DarkBlue);
DrawCircleGradient(new Vector2(screenWidth / 5.0f, 220.0f), 60, Color.Green, Color.SkyBlue);
DrawCircleLines(screenWidth / 5, 340, 80, Color.DarkBlue);
DrawEllipse(screenWidth / 5, 120, 25, 20, Color.Yellow);
DrawEllipseLines(screenWidth / 5, 120, 30, 25, Color.Yellow);
// Rectangle shapes and lines
DrawRectangle(screenWidth / 4 * 2 - 60, 100, 120, 60, Color.Red);
DrawRectangleGradientH(screenWidth / 4 * 2 - 90, 170, 180, 130, Color.Maroon, Color.Gold);
DrawRectangleLines(screenWidth / 4 * 2 - 40, 320, 80, 60, Color.Orange); // NOTE: Uses QUADS internally, not lines
// Triangle shapes and lines
DrawTriangle(
new Vector2(screenWidth / 4.0f * 3.0f, 80.0f),
new Vector2(screenWidth / 4.0f * 3.0f - 60.0f, 150.0f),
new Vector2(screenWidth / 4.0f * 3.0f + 60.0f, 150.0f), Color.Violet
);
DrawTriangleLines(
new Vector2(screenWidth / 4.0f * 3.0f, 160.0f),
new Vector2(screenWidth / 4.0f * 3.0f - 20.0f, 230.0f),
new Vector2(screenWidth / 4.0f * 3.0f + 20.0f, 230.0f), Color.DarkBlue
);
// Polygon shapes and lines
DrawPoly(new Vector2(screenWidth / 4.0f * 3, 330), 6, 80, rotation, Color.Brown);
DrawPolyLines(new Vector2(screenWidth / 4.0f * 3, 330), 6, 90, rotation, Color.Brown);
DrawPolyLinesEx(new Vector2(screenWidth / 4.0f * 3, 330), 6, 85, rotation, 6, Color.Beige);
// NOTE: We draw all LINES based shapes together to optimize internal drawing,
// this way, all LINES are rendered in a single draw pass
DrawLine(18, 42, screenWidth - 18, 42, Color.Black);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - basic shapes");
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - basic shapes drawing");
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new BasicShapes();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update your variables here
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("some basic shapes available on raylib", 20, 20, 20, Color.DarkGray);
DrawLine(18, 42, screenWidth - 18, 42, Color.Black);
DrawCircle(screenWidth / 4, 120, 35, Color.DarkBlue);
DrawCircleGradient(new Vector2(screenWidth / 4, 220), 60, Color.Green, Color.SkyBlue);
DrawCircleLines(screenWidth / 4, 340, 80, Color.DarkBlue);
DrawRectangle(screenWidth / 4 * 2 - 60, 100, 120, 60, Color.Red);
DrawRectangleGradientH(screenWidth / 4 * 2 - 90, 170, 180, 130, Color.Maroon, Color.Gold);
DrawRectangleLines(screenWidth / 4 * 2 - 40, 320, 80, 60, Color.Orange);
DrawTriangle(
new Vector2(screenWidth / 4 * 3, 80),
new Vector2(screenWidth / 4 * 3 - 60, 150),
new Vector2(screenWidth / 4 * 3 + 60, 150), Color.Violet
);
DrawTriangleLines(
new Vector2(screenWidth / 4 * 3, 160),
new Vector2(screenWidth / 4 * 3 - 20, 230),
new Vector2(screenWidth / 4 * 3 + 20, 230), Color.DarkBlue
);
DrawPoly(new Vector2(screenWidth / 4 * 3, 320), 6, 80, 0, Color.Brown);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -2,95 +2,151 @@
*
* raylib [shapes] example - bouncing ball
*
* This example has been created using raylib 1.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 1/4
*
* Copyright (c) 2013 Ramon Santamaria (@raysan5)
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example contributed by Ramon Santamaria (@raysan5), reviewed by Jopestpe (@jopestpe)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class BouncingBall
public partial class BouncingBall : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Bouncing Ball";
public string Title => "raylib [shapes] example - bouncing ball";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
private Vector2 ballPosition;
private Vector2 ballSpeed;
private int ballRadius;
private float gravity;
private bool useGravity;
private bool pause;
private int framesCounter;
public void Init()
{
ballPosition = new(GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f);
ballSpeed = new(5.0f, 4.0f);
ballRadius = 20;
gravity = 0.2f;
useGravity = true;
pause = false;
framesCounter = 0;
}
public void Update()
{
// Update
//-----------------------------------------------------
if (IsKeyPressed(KeyboardKey.G))
{
useGravity = !useGravity;
}
if (IsKeyPressed(KeyboardKey.Space))
{
pause = !pause;
}
if (!pause)
{
ballPosition.X += ballSpeed.X;
ballPosition.Y += ballSpeed.Y;
if (useGravity)
{
ballSpeed.Y += gravity;
}
// Check walls collision for bouncing
if ((ballPosition.X >= (GetScreenWidth() - ballRadius)) || (ballPosition.X <= ballRadius))
{
ballSpeed.X *= -1.0f;
}
if ((ballPosition.Y >= (GetScreenHeight() - ballRadius)) || (ballPosition.Y <= ballRadius))
{
ballSpeed.Y *= -0.95f;
}
}
else
{
framesCounter++;
}
//-----------------------------------------------------
// Draw
//-----------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawCircleV(ballPosition, (float)ballRadius, Color.Maroon);
DrawText("PRESS SPACE to PAUSE BALL MOVEMENT", 10, GetScreenHeight() - 25, 20, Color.LightGray);
if (useGravity)
{
DrawText("GRAVITY: ON (Press G to disable)", 10, GetScreenHeight() - 50, 20, Color.DarkGreen);
}
else
{
DrawText("GRAVITY: OFF (Press G to enable)", 10, GetScreenHeight() - 50, 20, Color.Red);
}
// On pause, we draw a blinking message
if (pause && ((framesCounter / 30) % 2) != 0)
{
DrawText("PAUSED", 350, 200, 30, Color.Gray);
}
DrawFPS(10, 10);
EndDrawing();
//-----------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//---------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - bouncing ball");
Vector2 ballPosition = new(GetScreenWidth() / 2, GetScreenHeight() / 2);
Vector2 ballSpeed = new(5.0f, 4.0f);
int ballRadius = 20;
bool pause = false;
int framesCounter = 0;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//----------------------------------------------------------
var game = new BouncingBall();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//-----------------------------------------------------
if (IsKeyPressed(KeyboardKey.Space))
{
pause = !pause;
}
if (!pause)
{
ballPosition.X += ballSpeed.X;
ballPosition.Y += ballSpeed.Y;
// Check walls collision for bouncing
if ((ballPosition.X >= (GetScreenWidth() - ballRadius)) || (ballPosition.X <= ballRadius))
{
ballSpeed.X *= -1.0f;
}
if ((ballPosition.Y >= (GetScreenHeight() - ballRadius)) || (ballPosition.Y <= ballRadius))
{
ballSpeed.Y *= -1.0f;
}
}
else
{
framesCounter += 1;
}
//-----------------------------------------------------
// Draw
//-----------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawCircleV(ballPosition, ballRadius, Color.Maroon);
DrawText("PRESS SPACE to PAUSE BALL MOVEMENT", 10, GetScreenHeight() - 25, 20, Color.LightGray);
// On pause, we draw a blinking message
if (pause && ((framesCounter / 30) % 2) == 0)
{
DrawText("PAUSED", 350, 200, 30, Color.Gray);
}
DrawFPS(10, 10);
EndDrawing();
//-----------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//---------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//----------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,319 @@
/*******************************************************************************************
*
* raylib [shapes] example - bullet hell
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 5.6, last time updated with raylib 5.6
*
* Example contributed by Zero (@zerohorsepower) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Zero (@zerohorsepower)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class BulletHell : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int MAX_BULLETS = 500000; // Max bullets to be processed
public string Name => "Shapes / Bullet Hell";
public string Title => "raylib [shapes] example - bullet hell";
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
private struct Bullet
{
public Vector2 position; // Bullet position on screen
public Vector2 acceleration; // Amount of pixels to be incremented to position every frame
public bool disabled; // Skip processing and draw case out of screen
public Color color; // Bullet color
}
// Bullets definition
private Bullet[] bullets;
private int bulletCount;
private int bulletDisabledCount; // Used to calculate how many bullets are on screen
private int bulletRadius;
private float bulletSpeed;
private int bulletRows;
private Color[] bulletColor;
// Spawner variables
private float baseDirection;
private int angleIncrement; // After spawn all bullet rows, increment this value on the baseDirection for next the frame
private float spawnCooldown;
private float spawnCooldownTimer;
// Magic circle
private float magicCircleRotation;
// Used on performance drawing
private RenderTexture2D bulletTexture;
private bool drawInPerformanceMode; // Switch between DrawCircle() and DrawTexture()
public void Init()
{
// Bullets definition
bullets = new Bullet[MAX_BULLETS]; // Bullets array
bulletCount = 0;
bulletDisabledCount = 0;
bulletRadius = 10;
bulletSpeed = 3.0f;
bulletRows = 6;
bulletColor = new[] { Color.Red, Color.Blue };
// Spawner variables
baseDirection = 0;
angleIncrement = 5;
spawnCooldown = 2;
spawnCooldownTimer = spawnCooldown;
// Magic circle
magicCircleRotation = 0;
// Used on performance drawing
bulletTexture = LoadRenderTexture(24, 24);
// Draw circle to bullet texture, then draw bullet using DrawTexture()
// NOTE: This is done to improve the performance, since DrawCircle() is very slow
BeginTextureMode(bulletTexture);
DrawCircle(12, 12, (float)bulletRadius, Color.White);
DrawCircleLines(12, 12, (float)bulletRadius, Color.Black);
EndTextureMode();
drawInPerformanceMode = true;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Reset the bullet index
// New bullets will replace the old ones that are already disabled due to out-of-screen
if (bulletCount >= MAX_BULLETS)
{
bulletCount = 0;
bulletDisabledCount = 0;
}
spawnCooldownTimer--;
if (spawnCooldownTimer < 0)
{
spawnCooldownTimer = spawnCooldown;
// Spawn bullets
float degreesPerRow = 360.0f / bulletRows;
for (int row = 0; row < bulletRows; row++)
{
if (bulletCount < MAX_BULLETS)
{
bullets[bulletCount].position = new Vector2((float)screenWidth / 2, (float)screenHeight / 2);
bullets[bulletCount].disabled = false;
bullets[bulletCount].color = bulletColor[row % 2];
float bulletDirection = baseDirection + (degreesPerRow * row);
// Bullet speed*bullet direction, this will determine how much pixels will be incremented/decremented
// from the bullet position every frame. Since the bullets doesn't change its direction and speed,
// only need to calculate it at the spawning time
// 0 degrees = right, 90 degrees = down, 180 degrees = left and 270 degrees = up, basically clockwise
// Case you want it to be anti-clockwise, add "* -1" at the y acceleration
bullets[bulletCount].acceleration = new Vector2(
bulletSpeed * MathF.Cos(bulletDirection * DEG2RAD),
bulletSpeed * MathF.Sin(bulletDirection * DEG2RAD)
);
bulletCount++;
}
}
baseDirection += angleIncrement;
}
// Update bullets position based on its acceleration
for (int i = 0; i < bulletCount; i++)
{
// Only update bullet if inside the screen
if (!bullets[i].disabled)
{
bullets[i].position.X += bullets[i].acceleration.X;
bullets[i].position.Y += bullets[i].acceleration.Y;
// Disable bullet if out of screen
if ((bullets[i].position.X < -bulletRadius * 2) ||
(bullets[i].position.X > screenWidth + bulletRadius * 2) ||
(bullets[i].position.Y < -bulletRadius * 2) ||
(bullets[i].position.Y > screenHeight + bulletRadius * 2))
{
bullets[i].disabled = true;
bulletDisabledCount++;
}
}
}
// Input logic
if ((IsKeyPressed(KeyboardKey.Right) || IsKeyPressed(KeyboardKey.D)) && (bulletRows < 359))
{
bulletRows++;
}
if ((IsKeyPressed(KeyboardKey.Left) || IsKeyPressed(KeyboardKey.A)) && (bulletRows > 1))
{
bulletRows--;
}
if (IsKeyPressed(KeyboardKey.Up) || IsKeyPressed(KeyboardKey.W))
{
bulletSpeed += 0.25f;
}
if ((IsKeyPressed(KeyboardKey.Down) || IsKeyPressed(KeyboardKey.S)) && (bulletSpeed > 0.50f))
{
bulletSpeed -= 0.25f;
}
if (IsKeyPressed(KeyboardKey.Z) && (spawnCooldown > 1))
{
spawnCooldown--;
}
if (IsKeyPressed(KeyboardKey.X))
{
spawnCooldown++;
}
if (IsKeyPressed(KeyboardKey.Enter))
{
drawInPerformanceMode = !drawInPerformanceMode;
}
if (IsKeyDown(KeyboardKey.Space))
{
angleIncrement += 1;
angleIncrement %= 360;
}
if (IsKeyPressed(KeyboardKey.C))
{
bulletCount = 0;
bulletDisabledCount = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw magic circle
magicCircleRotation++;
DrawRectanglePro(new Rectangle((float)screenWidth / 2, (float)screenHeight / 2, 120, 120),
new Vector2(60.0f, 60.0f), magicCircleRotation, Color.Purple);
DrawRectanglePro(new Rectangle((float)screenWidth / 2, (float)screenHeight / 2, 120, 120),
new Vector2(60.0f, 60.0f), magicCircleRotation + 45, Color.Purple);
DrawCircleLines(screenWidth / 2, screenHeight / 2, 70, Color.Black);
DrawCircleLines(screenWidth / 2, screenHeight / 2, 50, Color.Black);
DrawCircleLines(screenWidth / 2, screenHeight / 2, 30, Color.Black);
// Draw bullets
if (drawInPerformanceMode)
{
// Draw bullets using pre-rendered texture containing circle
for (int i = 0; i < bulletCount; i++)
{
// Do not draw disabled bullets (out of screen)
if (!bullets[i].disabled)
{
DrawTexture(bulletTexture.Texture,
(int)(bullets[i].position.X - bulletTexture.Texture.Width * 0.5f),
(int)(bullets[i].position.Y - bulletTexture.Texture.Height * 0.5f),
bullets[i].color);
}
}
}
else
{
// Draw bullets using DrawCircle(), less performant
for (int i = 0; i < bulletCount; i++)
{
// Do not draw disabled bullets (out of screen)
if (!bullets[i].disabled)
{
DrawCircleV(bullets[i].position, (float)bulletRadius, bullets[i].color);
DrawCircleLinesV(bullets[i].position, (float)bulletRadius, Color.Black);
}
}
}
// Draw UI
DrawRectangle(10, 10, 280, 150, new Color(0, 0, 0, 200));
DrawText("Controls:", 20, 20, 10, Color.LightGray);
DrawText("- Right/Left or A/D: Change rows number", 40, 40, 10, Color.LightGray);
DrawText("- Up/Down or W/S: Change bullet speed", 40, 60, 10, Color.LightGray);
DrawText("- Z or X: Change spawn cooldown", 40, 80, 10, Color.LightGray);
DrawText("- Space (Hold): Change the angle increment", 40, 100, 10, Color.LightGray);
DrawText("- Enter: Switch draw method (Performance)", 40, 120, 10, Color.LightGray);
DrawText("- C: Clear bullets", 40, 140, 10, Color.LightGray);
DrawRectangle(610, 10, 170, 30, new Color(0, 0, 0, 200));
if (drawInPerformanceMode)
{
DrawText("Draw method: DrawTexture(*)", 620, 20, 10, Color.Green);
}
else
{
DrawText("Draw method: DrawCircle(*)", 620, 20, 10, Color.Red);
}
DrawRectangle(135, 410, 530, 30, new Color(0, 0, 0, 200));
DrawText($"[ FPS: {GetFPS()}, Bullets: {bulletCount - bulletDisabledCount}, Rows: {bulletRows}, Bullet speed: {bulletSpeed:F2}, Angle increment per frame: {angleIncrement}, Cooldown: {spawnCooldown:F0} ]",
155, 420, 10, Color.Green);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadRenderTexture(bulletTexture); // Unload bullet texture
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - bullet hell");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new BulletHell();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,251 @@
/*******************************************************************************************
*
* raylib [shapes] example - clock of clocks
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.5, last time updated with raylib 6.0
*
* Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 JP Mortiboys (@themushroompirates)
*
********************************************************************************************/
using static Raylib_cs.Raymath; // Required for: Lerp(), Clamp()
namespace Examples.Shapes;
public partial class ClockOfClocks : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Clock of Clocks";
public string Title => "raylib [shapes] example - clock of clocks";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
private Color bgColor;
private Color handsColor;
private const float clockFaceSize = 24;
private const float clockFaceSpacing = 8.0f;
private const float sectionSpacing = 16.0f;
private static readonly Vector2 TL = new(0.0f, 90.0f); // Top-left corner
private static readonly Vector2 TR = new(90.0f, 180.0f); // Top-right corner
private static readonly Vector2 BR = new(180.0f, 270.0f); // Bottom-right corner
private static readonly Vector2 BL = new(0.0f, 270.0f); // Bottom-left corner
private static readonly Vector2 HH = new(0.0f, 180.0f); // Horizontal line
private static readonly Vector2 VV = new(90.0f, 270.0f); // Vertical line
private static readonly Vector2 ZZ = new(135.0f, 135.0f); // Not relevant
private Vector2[,] digitAngles;
// Time for the hands to move to the new position (in seconds); this must be <1s
private const float handsMoveDuration = 0.5f;
private int prevSeconds;
private Vector2[,] currentAngles;
private Vector2[,] srcAngles;
private Vector2[,] dstAngles;
private float handsMoveTimer;
private int hourMode;
public void Init()
{
bgColor = ColorLerp(Color.DarkBlue, Color.Black, 0.75f);
handsColor = ColorLerp(Color.Yellow, Color.RayWhite, .25f);
digitAngles = new Vector2[10, 24]
{
/* 0 */ { TL, HH, HH, TR, /* */ VV, TL, TR, VV, /* */ VV, VV, VV, VV, /* */ VV, VV, VV, VV, /* */ VV, BL, BR, VV, /* */ BL, HH, HH, BR },
/* 1 */ { TL, HH, TR, ZZ, /* */ BL, TR, VV, ZZ, /* */ ZZ, VV, VV, ZZ, /* */ ZZ, VV, VV, ZZ, /* */ TL, BR, BL, TR, /* */ BL, HH, HH, BR },
/* 2 */ { TL, HH, HH, TR, /* */ BL, HH, TR, VV, /* */ TL, HH, BR, VV, /* */ VV, TL, HH, BR, /* */ VV, BL, HH, TR, /* */ BL, HH, HH, BR },
/* 3 */ { TL, HH, HH, TR, /* */ BL, HH, TR, VV, /* */ TL, HH, BR, VV, /* */ BL, HH, TR, VV, /* */ TL, HH, BR, VV, /* */ BL, HH, HH, BR },
/* 4 */ { TL, TR, TL, TR, /* */ VV, VV, VV, VV, /* */ VV, BL, BR, VV, /* */ BL, HH, TR, VV, /* */ ZZ, ZZ, VV, VV, /* */ ZZ, ZZ, BL, BR },
/* 5 */ { TL, HH, HH, TR, /* */ VV, TL, HH, BR, /* */ VV, BL, HH, TR, /* */ BL, HH, TR, VV, /* */ TL, HH, BR, VV, /* */ BL, HH, HH, BR },
/* 6 */ { TL, HH, HH, TR, /* */ VV, TL, HH, BR, /* */ VV, BL, HH, TR, /* */ VV, TL, TR, VV, /* */ VV, BL, BR, VV, /* */ BL, HH, HH, BR },
/* 7 */ { TL, HH, HH, TR, /* */ BL, HH, TR, VV, /* */ ZZ, ZZ, VV, VV, /* */ ZZ, ZZ, VV, VV, /* */ ZZ, ZZ, VV, VV, /* */ ZZ, ZZ, BL, BR },
/* 8 */ { TL, HH, HH, TR, /* */ VV, TL, TR, VV, /* */ VV, BL, BR, VV, /* */ VV, TL, TR, VV, /* */ VV, BL, BR, VV, /* */ BL, HH, HH, BR },
/* 9 */ { TL, HH, HH, TR, /* */ VV, TL, TR, VV, /* */ VV, BL, BR, VV, /* */ BL, HH, TR, VV, /* */ TL, HH, BR, VV, /* */ BL, HH, HH, BR },
};
prevSeconds = -1;
currentAngles = new Vector2[6, 24];
srcAngles = new Vector2[6, 24];
dstAngles = new Vector2[6, 24];
handsMoveTimer = 0.0f;
hourMode = 24;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Get the current time
DateTime timeinfo = DateTime.Now;
if (timeinfo.Second != prevSeconds)
{
// The time has changed, so we need to move the hands to the new positions
prevSeconds = timeinfo.Second;
// Format the current time so we can access the individual digits
string clockDigits = $"{timeinfo.Hour % hourMode:D2}{timeinfo.Minute:D2}{timeinfo.Second:D2}";
// Fetch where we want all the hands to be
for (int digit = 0; digit < 6; digit++)
{
for (int cell = 0; cell < 24; cell++)
{
srcAngles[digit, cell] = currentAngles[digit, cell];
dstAngles[digit, cell] = digitAngles[clockDigits[digit] - '0', cell];
// Quick exception for 12h mode
if ((digit == 0) && (hourMode == 12) && (clockDigits[0] == '0'))
{
dstAngles[digit, cell] = ZZ;
}
if (srcAngles[digit, cell].X > dstAngles[digit, cell].X)
{
srcAngles[digit, cell].X -= 360.0f;
}
if (srcAngles[digit, cell].Y > dstAngles[digit, cell].Y)
{
srcAngles[digit, cell].Y -= 360.0f;
}
}
}
// Reset the timer
handsMoveTimer = -GetFrameTime();
}
// Now let's animate all the hands if we need to
if (handsMoveTimer < handsMoveDuration)
{
// Increase the timer but don't go above the maximum
handsMoveTimer = Clamp(handsMoveTimer + GetFrameTime(), 0, handsMoveDuration);
// Calculate the % completion of the animation
float t = handsMoveTimer / handsMoveDuration;
// A little cheeky smoothstep
t = t * t * (3.0f - 2.0f * t);
for (int digit = 0; digit < 6; digit++)
{
for (int cell = 0; cell < 24; cell++)
{
currentAngles[digit, cell].X = Lerp(srcAngles[digit, cell].X, dstAngles[digit, cell].X, t);
currentAngles[digit, cell].Y = Lerp(srcAngles[digit, cell].Y, dstAngles[digit, cell].Y, t);
}
}
}
// Handle input
if (IsKeyPressed(KeyboardKey.Space))
{
hourMode = 36 - hourMode; // Toggle between 12 and 24 hour mode with space
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(bgColor);
DrawText($"{hourMode}-h mode, space to change", 10, 30, 20, Color.RayWhite);
float xOffset = 4.0f;
for (int digit = 0; digit < 6; digit++)
{
for (int row = 0; row < 6; row++)
{
for (int col = 0; col < 4; col++)
{
Vector2 centre = new(
xOffset + col * (clockFaceSize + clockFaceSpacing) + clockFaceSize * 0.5f,
100 + row * (clockFaceSize + clockFaceSpacing) + clockFaceSize * 0.5f
);
DrawRing(centre, clockFaceSize * 0.5f - 2.0f, clockFaceSize * 0.5f, 0, 360, 24, Color.DarkGray);
// Big hand
DrawRectanglePro(
new Rectangle(centre.X, centre.Y, clockFaceSize * 0.5f + 4.0f, 4.0f),
new Vector2(2.0f, 2.0f),
currentAngles[digit, row * 4 + col].X,
handsColor
);
// Little hand
DrawRectanglePro(
new Rectangle(centre.X, centre.Y, clockFaceSize * 0.5f + 2.0f, 4.0f),
new Vector2(2.0f, 2.0f),
currentAngles[digit, row * 4 + col].Y,
handsColor
);
}
}
xOffset += (clockFaceSize + clockFaceSpacing) * 4;
if (digit % 2 == 1)
{
DrawRing(new Vector2(xOffset + 4.0f, 160.0f), 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor);
DrawRing(new Vector2(xOffset + 4.0f, 225.0f), 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor);
xOffset += sectionSpacing;
}
}
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - clock of clocks");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new ClockOfClocks();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -2,135 +2,169 @@
*
* raylib [shapes] example - collision area
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5)
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class CollisionArea
public partial class CollisionArea : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Collision Area";
public string Title => "raylib [shapes] example - collision area";
private Rectangle boxA;
private int boxASpeedX;
private Rectangle boxB;
private Rectangle boxCollision;
private int screenUpperLimit;
private bool pause;
private bool collision;
public void Init()
{
// Box A: Moving box
boxA = new(10, GetScreenHeight() / 2.0f - 50, 200, 100);
boxASpeedX = 4;
// Box B: Mouse moved box
boxB = new(GetScreenWidth() / 2.0f - 30, GetScreenHeight() / 2.0f - 30, 60, 60);
boxCollision = new(); // Collision rectangle
screenUpperLimit = 40; // Top menu limits
pause = false; // Movement pause
collision = false; // Collision detection
}
public void Update()
{
// Update
//-----------------------------------------------------
// Move box if not paused
if (!pause)
{
boxA.X += boxASpeedX;
}
// Bounce box on x screen limits
if (((boxA.X + boxA.Width) >= GetScreenWidth()) || (boxA.X <= 0))
{
boxASpeedX *= -1;
}
// Update player-controlled-box (box02)
boxB.X = GetMouseX() - boxB.Width / 2;
boxB.Y = GetMouseY() - boxB.Height / 2;
// Make sure Box B does not go out of move area limits
if ((boxB.X + boxB.Width) >= GetScreenWidth())
{
boxB.X = GetScreenWidth() - boxB.Width;
}
else if (boxB.X <= 0)
{
boxB.X = 0;
}
if ((boxB.Y + boxB.Height) >= GetScreenHeight())
{
boxB.Y = GetScreenHeight() - boxB.Height;
}
else if (boxB.Y <= screenUpperLimit)
{
boxB.Y = screenUpperLimit;
}
// Check boxes collision
collision = CheckCollisionRecs(boxA, boxB);
// Get collision rectangle (only on collision)
if (collision)
{
boxCollision = GetCollisionRec(boxA, boxB);
}
// Pause Box A movement
if (IsKeyPressed(KeyboardKey.Space))
{
pause = !pause;
}
//-----------------------------------------------------
// Draw
//-----------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawRectangle(0, 0, screenWidth, screenUpperLimit, collision ? Color.Red : Color.Black);
DrawRectangleRec(boxA, Color.Gold);
DrawRectangleRec(boxB, Color.Blue);
if (collision)
{
// Draw collision area
DrawRectangleRec(boxCollision, Color.Lime);
// Draw collision message
var cx = GetScreenWidth() / 2 - MeasureText("COLLISION!", 20) / 2;
var cy = screenUpperLimit / 2 - 10;
DrawText("COLLISION!", cx, cy, 20, Color.Black);
// Draw collision area
var text = $"Collision Area: {(int)boxCollision.Width * (int)boxCollision.Height}";
DrawText(text, GetScreenWidth() / 2 - 100, screenUpperLimit + 10, 20, Color.Black);
}
// Draw help instructions
DrawText("Press SPACE to PAUSE/RESUME", 20, screenHeight - 35, 20, Color.LightGray);
DrawFPS(10, 10);
EndDrawing();
//-----------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//---------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - collision area");
// Box A: Moving box
Rectangle boxA = new(10, GetScreenHeight() / 2 - 50, 200, 100);
int boxASpeedX = 4;
// Box B: Mouse moved box
Rectangle boxB = new(GetScreenWidth() / 2 - 30, GetScreenHeight() / 2 - 30, 60, 60);
Rectangle boxCollision = new();
int screenUpperLimit = 40;
// Movement pause
bool pause = false;
bool collision = false;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//----------------------------------------------------------
var game = new CollisionArea();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//-----------------------------------------------------
// Move box if not paused
if (!pause)
{
boxA.X += boxASpeedX;
}
// Bounce box on x screen limits
if (((boxA.X + boxA.Width) >= GetScreenWidth()) || (boxA.X <= 0))
{
boxASpeedX *= -1;
}
// Update player-controlled-box (box02)
boxB.X = GetMouseX() - boxB.Width / 2;
boxB.Y = GetMouseY() - boxB.Height / 2;
// Make sure Box B does not go out of move area limits
if ((boxB.X + boxB.Width) >= GetScreenWidth())
{
boxB.X = GetScreenWidth() - boxB.Width;
}
else if (boxB.X <= 0)
{
boxB.X = 0;
}
if ((boxB.Y + boxB.Height) >= GetScreenHeight())
{
boxB.Y = GetScreenHeight() - boxB.Height;
}
else if (boxB.Y <= screenUpperLimit)
{
boxB.Y = screenUpperLimit;
}
// Check boxes collision
collision = CheckCollisionRecs(boxA, boxB);
// Get collision rectangle (only on collision)
if (collision)
{
boxCollision = GetCollisionRec(boxA, boxB);
}
// Pause Box A movement
if (IsKeyPressed(KeyboardKey.Space))
{
pause = !pause;
}
//-----------------------------------------------------
// Draw
//-----------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawRectangle(0, 0, screenWidth, screenUpperLimit, collision ? Color.Red : Color.Black);
DrawRectangleRec(boxA, Color.Gold);
DrawRectangleRec(boxB, Color.Blue);
if (collision)
{
// Draw collision area
DrawRectangleRec(boxCollision, Color.Lime);
// Draw collision message
int cx = GetScreenWidth() / 2 - MeasureText("COLLISION!", 20) / 2;
int cy = screenUpperLimit / 2 - 10;
DrawText("COLLISION!", cx, cy, 20, Color.Black);
// Draw collision area
string text = $"Collision Area: {(int)boxCollision.Width * (int)boxCollision.Height}";
DrawText(text, GetScreenWidth() / 2 - 100, screenUpperLimit + 10, 20, Color.Black);
}
DrawFPS(10, 10);
EndDrawing();
//-----------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//---------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//----------------------------------------------------------
return 0;

View file

@ -1,85 +1,94 @@
/*******************************************************************************************
*
* raylib [shapes] example - Colors palette
* raylib [shapes] example - colors palette
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.0, last time updated with raylib 2.5
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class ColorsPalette
public partial class ColorsPalette : IExample
{
public static int Main()
private const int screenWidth = 800;
private const int screenHeight = 450;
public const int MaxColorsCount = 21; // Number of colors available
public string Name => "Shapes / Colors Palette";
public string Title => "raylib [shapes] example - colors palette";
private Color[] colors;
private string[] colorNames;
private Rectangle[] colorsRecs;
private int[] colorState;
private Vector2 mousePoint;
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - colors palette");
Color[] colors = new[]
colors = new[]
{
Color.DarkGray,
Color.Maroon,
Color.Orange,
Color.DarkGreen,
Color.DarkBlue,
Color.DarkPurple,
Color.DarkBrown,
Color.Gray,
Color.Red,
Color.Gold,
Color.Lime,
Color.Blue,
Color.Violet,
Color.Brown,
Color.LightGray,
Color.Pink,
Color.Yellow,
Color.Green,
Color.SkyBlue,
Color.Purple,
Color.Beige
};
Color.DarkGray,
Color.Maroon,
Color.Orange,
Color.DarkGreen,
Color.DarkBlue,
Color.DarkPurple,
Color.DarkBrown,
Color.Gray,
Color.Red,
Color.Gold,
Color.Lime,
Color.Blue,
Color.Violet,
Color.Brown,
Color.LightGray,
Color.Pink,
Color.Yellow,
Color.Green,
Color.SkyBlue,
Color.Purple,
Color.Beige
};
string[] colorNames = new[]
colorNames = new[]
{
"DARKGRAY",
"MAROON",
"ORANGE",
"DARKGREEN",
"DARKBLUE",
"DARKPURPLE",
"DARKBROWN",
"GRAY",
"RED",
"GOLD",
"LIME",
"BLUE",
"VIOLET",
"BROWN",
"LIGHTGRAY",
"PINK",
"YELLOW",
"GREEN",
"SKYBLUE",
"PURPLE",
"BEIGE"
};
"DARKGRAY",
"MAROON",
"ORANGE",
"DARKGREEN",
"DARKBLUE",
"DARKPURPLE",
"DARKBROWN",
"GRAY",
"RED",
"GOLD",
"LIME",
"BLUE",
"VIOLET",
"BROWN",
"LIGHTGRAY",
"PINK",
"YELLOW",
"GREEN",
"SKYBLUE",
"PURPLE",
"BEIGE"
};
// Rectangles array
Rectangle[] colorsRecs = new Rectangle[colors.Length];
colorsRecs = new Rectangle[colors.Length];
// Fills colorsRecs data (for every rectangle)
for (int i = 0; i < colorsRecs.Length; i++)
for (var i = 0; i < colorsRecs.Length; i++)
{
colorsRecs[i].X = 20 + 100 * (i % 7) + 10 * (i % 7);
colorsRecs[i].Y = 80 + 100 * (i / 7) + 10 * (i / 7);
@ -88,82 +97,101 @@ public class ColorsPalette
}
// Color state: 0-DEFAULT, 1-MOUSE_HOVER
int[] colorState = new int[colors.Length];
colorState = new int[colors.Length];
Vector2 mousePoint = new(0.0f, 0.0f);
mousePoint = new(0.0f, 0.0f);
}
SetTargetFPS(60);
public void Update()
{
// Update
//----------------------------------------------------------------------------------
mousePoint = GetMousePosition();
for (var i = 0; i < colors.Length; i++)
{
if (CheckCollisionPointRec(mousePoint, colorsRecs[i]))
{
colorState[i] = 1;
}
else
{
colorState[i] = 0;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("raylib colors palette", 28, 42, 20, Color.Black);
DrawText(
"press SPACE to see all colors",
GetScreenWidth() - 180,
GetScreenHeight() - 40,
10,
Color.Gray
);
for (var i = 0; i < colorsRecs.Length; i++) // Draw all rectangles
{
DrawRectangleRec(colorsRecs[i], Fade(colors[i], colorState[i] != 0 ? 0.6f : 1.0f));
if (IsKeyDown(KeyboardKey.Space) || colorState[i] != 0)
{
DrawRectangle(
(int)colorsRecs[i].X,
(int)(colorsRecs[i].Y + colorsRecs[i].Height - 26),
(int)colorsRecs[i].Width,
20,
Color.Black
);
DrawRectangleLinesEx(colorsRecs[i], 6, Fade(Color.Black, 0.3f));
DrawText(
colorNames[i],
(int)(colorsRecs[i].X + colorsRecs[i].Width - MeasureText(colorNames[i], 10) - 12),
(int)(colorsRecs[i].Y + colorsRecs[i].Height - 20),
10,
colors[i]
);
}
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - colors palette");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new ColorsPalette();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
mousePoint = GetMousePosition();
for (int i = 0; i < colors.Length; i++)
{
if (CheckCollisionPointRec(mousePoint, colorsRecs[i]))
{
colorState[i] = 1;
}
else
{
colorState[i] = 0;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("raylib colors palette", 28, 42, 20, Color.Black);
DrawText(
"press SPACE to see all colors",
GetScreenWidth() - 180,
GetScreenHeight() - 40,
10,
Color.Gray
);
// Draw all rectangles
for (int i = 0; i < colorsRecs.Length; i++)
{
DrawRectangleRec(colorsRecs[i], ColorAlpha(colors[i], colorState[i] != 0 ? 0.6f : 1.0f));
if (IsKeyDown(KeyboardKey.Space) || colorState[i] != 0)
{
DrawRectangle(
(int)colorsRecs[i].X,
(int)(colorsRecs[i].Y + colorsRecs[i].Height - 26),
(int)colorsRecs[i].Width,
20,
Color.Black
);
DrawRectangleLinesEx(colorsRecs[i], 6, ColorAlpha(Color.Black, 0.3f));
DrawText(
colorNames[i],
(int)(colorsRecs[i].X + colorsRecs[i].Width - MeasureText(colorNames[i], 10) - 12),
(int)(colorsRecs[i].Y + colorsRecs[i].Height - 20),
10,
colors[i]
);
}
}
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,144 @@
/*******************************************************************************************
*
* raylib [shapes] example - dashed line
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
* Example contributed by Luís Almeida (@luis605)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Luís Almeida (@luis605)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class DashedLine : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Dashed Line";
public string Title => "raylib [shapes] example - dashed line";
// Line Properties
private Vector2 lineStartPosition;
private Vector2 lineEndPosition;
private float dashLength;
private float blankLength;
// Color selection
private Color[] lineColors;
private int colorIndex;
public void Init()
{
// Line Properties
lineStartPosition = new Vector2(20.0f, 50.0f);
lineEndPosition = new Vector2(780.0f, 400.0f);
dashLength = 25.0f;
blankLength = 15.0f;
// Color selection
lineColors = new[] { Color.Red, Color.Orange, Color.Gold, Color.Green, Color.Blue, Color.Violet, Color.Pink, Color.Black };
colorIndex = 0;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
lineEndPosition = GetMousePosition(); // Line endpoint follows the mouse
// Change Dash Length (UP/DOWN arrows)
if (IsKeyDown(KeyboardKey.Up))
{
dashLength += 1.0f;
}
if (IsKeyDown(KeyboardKey.Down) && dashLength > 1.0f)
{
dashLength -= 1.0f;
}
// Change Space Length (LEFT/RIGHT arrows)
if (IsKeyDown(KeyboardKey.Right))
{
blankLength += 1.0f;
}
if (IsKeyDown(KeyboardKey.Left) && blankLength > 1.0f)
{
blankLength -= 1.0f;
}
// Cycle through colors ('C' key)
if (IsKeyPressed(KeyboardKey.C))
{
colorIndex = (colorIndex + 1) % lineColors.Length;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw the dashed line with the current properties
DrawLineDashed(lineStartPosition, lineEndPosition, (int)dashLength, (int)blankLength, lineColors[colorIndex]);
// Draw UI and Instructions
DrawRectangle(5, 5, 265, 95, Fade(Color.SkyBlue, 0.5f));
DrawRectangleLines(5, 5, 265, 95, Color.Blue);
DrawText("CONTROLS:", 15, 15, 10, Color.Black);
DrawText("UP/DOWN: Change Dash Length", 15, 35, 10, Color.Black);
DrawText("LEFT/RIGHT: Change Space Length", 15, 55, 10, Color.Black);
DrawText("C: Cycle Color", 15, 75, 10, Color.Black);
DrawText($"Dash: {dashLength:F0} | Space: {blankLength:F0}", 15, 115, 10, Color.DarkGray);
DrawFPS(screenWidth - 80, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - dashed line");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new DashedLine();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,353 @@
/*******************************************************************************************
*
* raylib [shapes] example - digital clock
*
* Example complexity rating: [] 4/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.6
*
* Example contributed by Hamza RAHAL (@hmz-rhl) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Hamza RAHAL (@hmz-rhl) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class DigitalClock : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int CLOCK_ANALOG = 0;
private const int CLOCK_DIGITAL = 1;
public string Name => "Shapes / Digital Clock";
public string Title => "raylib [shapes] example - digital clock";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Clock hand type
private struct ClockHand
{
public int value; // Time value
// Visual elements
public float angle; // Hand angle
public int length; // Hand length
public int thickness; // Hand thickness
public Color color; // Hand color
}
// Clock hands
private struct Clock
{
public ClockHand second; // Clock hand for seconds
public ClockHand minute; // Clock hand for minutes
public ClockHand hour; // Clock hand for hours
}
private int clockMode;
private Clock clock;
public void Init()
{
clockMode = CLOCK_DIGITAL;
// Initialize clock
// NOTE: Includes visual info for analog clock
clock = new Clock();
clock.second.angle = 45;
clock.second.length = 140;
clock.second.thickness = 3;
clock.second.color = Color.Maroon;
clock.minute.angle = 10;
clock.minute.length = 130;
clock.minute.thickness = 7;
clock.minute.color = Color.DarkGray;
clock.hour.angle = 0;
clock.hour.length = 100;
clock.hour.thickness = 7;
clock.hour.color = Color.Black;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.Space))
{
// Toggle clock mode
if (clockMode == CLOCK_DIGITAL)
{
clockMode = CLOCK_ANALOG;
}
else if (clockMode == CLOCK_ANALOG)
{
clockMode = CLOCK_DIGITAL;
}
}
UpdateClock(); // Update clock required data: value and angle
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw clock in selected mode
if (clockMode == CLOCK_ANALOG)
{
DrawClockAnalog(clock, new Vector2(400, 240));
}
else if (clockMode == CLOCK_DIGITAL)
{
DrawClockDigital(clock, new Vector2(30, 60));
// Draw clock using default raylib font
string clockTime = $"{clock.hour.value:D2}:{clock.minute.value:D2}:{clock.second.value:D2}";
DrawText(clockTime, GetScreenWidth() / 2 - MeasureText(clockTime, 150) / 2, 300, 150, Color.Black);
}
DrawText($"Press [SPACE] to switch clock mode: {((clockMode == CLOCK_DIGITAL) ? "DIGITAL CLOCK" : "ANALOGUE CLOCK")}",
10, 10, 20, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Update clock time
private void UpdateClock()
{
DateTime timeinfo = DateTime.Now;
// Updating time data
clock.second.value = timeinfo.Second;
clock.minute.value = timeinfo.Minute;
clock.hour.value = timeinfo.Hour;
clock.hour.angle = (timeinfo.Hour % 12) * 180.0f / 6.0f;
clock.hour.angle += (timeinfo.Minute % 60) * 30 / 60.0f;
clock.hour.angle -= 90;
clock.minute.angle = (timeinfo.Minute % 60) * 6.0f;
clock.minute.angle += (timeinfo.Second % 60) * 6 / 60.0f;
clock.minute.angle -= 90;
clock.second.angle = (timeinfo.Second % 60) * 6.0f;
clock.second.angle -= 90;
}
// Draw analog clock
// Parameter: position, refers to center position
private static void DrawClockAnalog(Clock clock, Vector2 position)
{
// Draw clock base
DrawCircleV(position, clock.second.length + 40.0f, Color.LightGray);
DrawCircleV(position, 12.0f, Color.Gray);
// Draw clock minutes/seconds lines
for (int i = 0; i < 60; i++)
{
DrawLineEx(new Vector2(position.X + (clock.second.length + ((i % 5) != 0 ? 10 : 6)) * MathF.Cos((6.0f * i - 90.0f) * DEG2RAD),
position.Y + (clock.second.length + ((i % 5) != 0 ? 10 : 6)) * MathF.Sin((6.0f * i - 90.0f) * DEG2RAD)),
new Vector2(position.X + (clock.second.length + 20) * MathF.Cos((6.0f * i - 90.0f) * DEG2RAD),
position.Y + (clock.second.length + 20) * MathF.Sin((6.0f * i - 90.0f) * DEG2RAD)), ((i % 5) != 0 ? 1.0f : 3.0f), Color.DarkGray);
}
// Draw hand seconds
DrawRectanglePro(new Rectangle(position.X, position.Y, (float)clock.second.length, (float)clock.second.thickness),
new Vector2(0.0f, clock.second.thickness / 2.0f), clock.second.angle, clock.second.color);
// Draw hand minutes
DrawRectanglePro(new Rectangle(position.X, position.Y, (float)clock.minute.length, (float)clock.minute.thickness),
new Vector2(0.0f, clock.minute.thickness / 2.0f), clock.minute.angle, clock.minute.color);
// Draw hand hours
DrawRectanglePro(new Rectangle(position.X, position.Y, (float)clock.hour.length, (float)clock.hour.thickness),
new Vector2(0.0f, clock.hour.thickness / 2.0f), clock.hour.angle, clock.hour.color);
}
// Draw digital clock
// PARAM: position, refers to top-left corner
private static void DrawClockDigital(Clock clock, Vector2 position)
{
// Draw clock using custom 7-segments display (made of shapes)
DrawDisplayValue(new Vector2(position.X, position.Y), clock.hour.value / 10, Color.Red, Fade(Color.LightGray, 0.3f));
DrawDisplayValue(new Vector2(position.X + 120, position.Y), clock.hour.value % 10, Color.Red, Fade(Color.LightGray, 0.3f));
DrawCircle((int)position.X + 240, (int)position.Y + 70, 12, (clock.second.value % 2) != 0 ? Color.Red : Fade(Color.LightGray, 0.3f));
DrawCircle((int)position.X + 240, (int)position.Y + 150, 12, (clock.second.value % 2) != 0 ? Color.Red : Fade(Color.LightGray, 0.3f));
DrawDisplayValue(new Vector2(position.X + 260, position.Y), clock.minute.value / 10, Color.Red, Fade(Color.LightGray, 0.3f));
DrawDisplayValue(new Vector2(position.X + 380, position.Y), clock.minute.value % 10, Color.Red, Fade(Color.LightGray, 0.3f));
DrawCircle((int)position.X + 500, (int)position.Y + 70, 12, (clock.second.value % 2) != 0 ? Color.Red : Fade(Color.LightGray, 0.3f));
DrawCircle((int)position.X + 500, (int)position.Y + 150, 12, (clock.second.value % 2) != 0 ? Color.Red : Fade(Color.LightGray, 0.3f));
DrawDisplayValue(new Vector2(position.X + 520, position.Y), clock.second.value / 10, Color.Red, Fade(Color.LightGray, 0.3f));
DrawDisplayValue(new Vector2(position.X + 640, position.Y), clock.second.value % 10, Color.Red, Fade(Color.LightGray, 0.3f));
}
// Draw 7-segment display with value
private static void DrawDisplayValue(Vector2 position, int value, Color colorOn, Color colorOff)
{
switch (value)
{
case 0:
Draw7SDisplay(position, 0b00111111, colorOn, colorOff);
break;
case 1:
Draw7SDisplay(position, 0b00000110, colorOn, colorOff);
break;
case 2:
Draw7SDisplay(position, 0b01011011, colorOn, colorOff);
break;
case 3:
Draw7SDisplay(position, 0b01001111, colorOn, colorOff);
break;
case 4:
Draw7SDisplay(position, 0b01100110, colorOn, colorOff);
break;
case 5:
Draw7SDisplay(position, 0b01101101, colorOn, colorOff);
break;
case 6:
Draw7SDisplay(position, 0b01111101, colorOn, colorOff);
break;
case 7:
Draw7SDisplay(position, 0b00000111, colorOn, colorOff);
break;
case 8:
Draw7SDisplay(position, 0b01111111, colorOn, colorOff);
break;
case 9:
Draw7SDisplay(position, 0b01101111, colorOn, colorOff);
break;
default:
break;
}
}
// Draw seven segments display
// Parameter: position, refers to top-left corner of display
// Parameter: segments, defines in binary the segments to be activated
private static void Draw7SDisplay(Vector2 position, int segments, Color colorOn, Color colorOff)
{
int segmentLen = 60;
int segmentThick = 20;
float offsetYAdjust = segmentThick * 0.3f; // HACK: Adjust gap space between segment limits
// Segment A
DrawDisplaySegment(new Vector2(position.X + segmentThick + segmentLen / 2.0f, position.Y + segmentThick),
segmentLen, segmentThick, false, (segments & 0b00000001) != 0 ? colorOn : colorOff);
// Segment B
DrawDisplaySegment(new Vector2(position.X + segmentThick + segmentLen + segmentThick / 2.0f, position.Y + 2 * segmentThick + segmentLen / 2.0f - offsetYAdjust),
segmentLen, segmentThick, true, (segments & 0b00000010) != 0 ? colorOn : colorOff);
// Segment C
DrawDisplaySegment(new Vector2(position.X + segmentThick + segmentLen + segmentThick / 2.0f, position.Y + 4 * segmentThick + segmentLen + segmentLen / 2.0f - 3 * offsetYAdjust),
segmentLen, segmentThick, true, (segments & 0b00000100) != 0 ? colorOn : colorOff);
// Segment D
DrawDisplaySegment(new Vector2(position.X + segmentThick + segmentLen / 2.0f, position.Y + 5 * segmentThick + 2 * segmentLen - 4 * offsetYAdjust),
segmentLen, segmentThick, false, (segments & 0b00001000) != 0 ? colorOn : colorOff);
// Segment E
DrawDisplaySegment(new Vector2(position.X + segmentThick / 2.0f, position.Y + 4 * segmentThick + segmentLen + segmentLen / 2.0f - 3 * offsetYAdjust),
segmentLen, segmentThick, true, (segments & 0b00010000) != 0 ? colorOn : colorOff);
// Segment F
DrawDisplaySegment(new Vector2(position.X + segmentThick / 2.0f, position.Y + 2 * segmentThick + segmentLen / 2.0f - offsetYAdjust),
segmentLen, segmentThick, true, (segments & 0b00100000) != 0 ? colorOn : colorOff);
// Segment G
DrawDisplaySegment(new Vector2(position.X + segmentThick + segmentLen / 2.0f, position.Y + 3 * segmentThick + segmentLen - 2 * offsetYAdjust),
segmentLen, segmentThick, false, (segments & 0b01000000) != 0 ? colorOn : colorOff);
}
// Draw one 7-segment display segment, horizontal or vertical
private static void DrawDisplaySegment(Vector2 center, int length, int thick, bool vertical, Color color)
{
if (!vertical)
{
// Horizontal segment points
/*
3___________________________5
/ \
/1 x 6\
\ /
\2___________________________4/
*/
Vector2[] segmentPointsH = new Vector2[6]
{
new Vector2(center.X - length / 2.0f - thick / 2.0f, center.Y), // Point 1
new Vector2(center.X - length / 2.0f, center.Y + thick / 2.0f), // Point 2
new Vector2(center.X - length / 2.0f, center.Y - thick / 2.0f), // Point 3
new Vector2(center.X + length / 2.0f, center.Y + thick / 2.0f), // Point 4
new Vector2(center.X + length / 2.0f, center.Y - thick / 2.0f), // Point 5
new Vector2(center.X + length / 2.0f + thick / 2.0f, center.Y), // Point 6
};
DrawTriangleStrip(segmentPointsH, 6, color);
}
else
{
// Vertical segment points
Vector2[] segmentPointsV = new Vector2[6]
{
new Vector2(center.X, center.Y - length / 2.0f - thick / 2.0f), // Point 1
new Vector2(center.X - thick / 2.0f, center.Y - length / 2.0f), // Point 2
new Vector2(center.X + thick / 2.0f, center.Y - length / 2.0f), // Point 3
new Vector2(center.X - thick / 2.0f, center.Y + length / 2.0f), // Point 4
new Vector2(center.X + thick / 2.0f, center.Y + length / 2.0f), // Point 5
new Vector2(center.X, center.Y + (float)length / 2 + thick / 2.0f), // Point 6
};
DrawTriangleStrip(segmentPointsV, 6, color);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - digital clock");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new DigitalClock();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,208 @@
/*******************************************************************************************
*
* raylib [shapes] example - double pendulum
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
* Example contributed by JoeCheong (@Joecheong2006) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 JoeCheong (@Joecheong2006)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class DoublePendulum : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
// Constant for Simulation
private const int SIMULATION_STEPS = 30;
private const float G = 9.81f;
public string Name => "Shapes / Double Pendulum";
public string Title => "raylib [shapes] example - double pendulum";
public ConfigFlags ConfigFlags => ConfigFlags.HighDpiWindow;
// Simulation Parameters
private float l1, m1, theta1, w1;
private float l2, m2, theta2, w2;
private float lengthScaler;
private float totalM;
private Vector2 previousPosition;
// Scale length
private float L1;
private float L2;
// Draw parameters
private float lineThick, trailThick;
private float fateAlpha;
// Create framebuffer
private RenderTexture2D target;
// Calculate pendulum end point
private static Vector2 CalculatePendulumEndPoint(float l, float theta)
{
return new(10 * l * MathF.Sin(theta), 10 * l * MathF.Cos(theta));
}
// Calculate double pendulum end point
private static Vector2 CalculateDoublePendulumEndPoint(float l1, float theta1, float l2, float theta2)
{
Vector2 endpoint1 = CalculatePendulumEndPoint(l1, theta1);
Vector2 endpoint2 = CalculatePendulumEndPoint(l2, theta2);
return new(endpoint1.X + endpoint2.X, endpoint1.Y + endpoint2.Y);
}
public void Init()
{
// Simulation Parameters
l1 = 15.0f;
m1 = 0.2f;
theta1 = DEG2RAD * 170;
w1 = 0;
l2 = 15.0f;
m2 = 0.1f;
theta2 = DEG2RAD * 0;
w2 = 0;
lengthScaler = 0.1f;
totalM = m1 + m2;
previousPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2);
previousPosition.X += ((float)screenWidth / 2);
previousPosition.Y += ((float)screenHeight / 2 - 100);
// Scale length
L1 = l1 * lengthScaler;
L2 = l2 * lengthScaler;
// Draw parameters
lineThick = 20;
trailThick = 2;
fateAlpha = 0.01f;
// Create framebuffer
target = LoadRenderTexture(screenWidth, screenHeight);
SetTextureFilter(target.Texture, TextureFilter.Bilinear);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
float dt = GetFrameTime();
float step = dt / SIMULATION_STEPS, step2 = step * step;
// Update Physics - larger steps = better approximation
for (int i = 0; i < SIMULATION_STEPS; i++)
{
float delta = theta1 - theta2;
float sinD = MathF.Sin(delta), cosD = MathF.Cos(delta), cos2D = MathF.Cos(2 * delta);
float ww1 = w1 * w1, ww2 = w2 * w2;
// Calculate a1
float a1 = (-G * (2 * m1 + m2) * MathF.Sin(theta1)
- m2 * G * MathF.Sin(theta1 - 2 * theta2)
- 2 * sinD * m2 * (ww2 * L2 + ww1 * L1 * cosD))
/ (L1 * (2 * m1 + m2 - m2 * cos2D));
// Calculate a2
float a2 = (2 * sinD * (ww1 * L1 * totalM
+ G * totalM * MathF.Cos(theta1)
+ ww2 * L2 * m2 * cosD))
/ (L2 * (2 * m1 + m2 - m2 * cos2D));
// Update thetas
theta1 += w1 * step + 0.5f * a1 * step2;
theta2 += w2 * step + 0.5f * a2 * step2;
// Update omegas
w1 += a1 * step;
w2 += a2 * step;
}
// Calculate position
Vector2 currentPosition = CalculateDoublePendulumEndPoint(l1, theta1, l2, theta2);
currentPosition.X += (float)screenWidth / 2;
currentPosition.Y += (float)screenHeight / 2 - 100;
// Draw to render texture
BeginTextureMode(target);
// Draw a transparent rectangle - smaller alpha = longer trails
DrawRectangle(0, 0, screenWidth, screenHeight, Fade(Color.Black, fateAlpha));
// Draw trail
DrawCircleV(previousPosition, trailThick, Color.Red);
DrawLineEx(previousPosition, currentPosition, trailThick * 2, Color.Red);
EndTextureMode();
// Update previous position
previousPosition = currentPosition;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.Black);
// Draw trails texture
DrawTextureRec(target.Texture, new Rectangle(0, 0, (float)target.Texture.Width, (float)-target.Texture.Height), new Vector2(0, 0), Color.White);
// Draw double pendulum
DrawRectanglePro(new Rectangle(screenWidth / 2.0f, screenHeight / 2.0f - 100, 10 * l1, lineThick),
new Vector2(0, lineThick * 0.5f), 90 - RAD2DEG * theta1, Color.RayWhite);
Vector2 endpoint1 = CalculatePendulumEndPoint(l1, theta1);
DrawRectanglePro(new Rectangle(screenWidth / 2.0f + endpoint1.X, screenHeight / 2.0f - 100 + endpoint1.Y, 10 * l2, lineThick),
new Vector2(0, lineThick * 0.5f), 90 - RAD2DEG * theta2, Color.RayWhite);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadRenderTexture(target);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.HighDpiWindow);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - double pendulum");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new DoublePendulum();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,95 +1,158 @@
/*******************************************************************************************
*
* raylib [shapes] example - draw circle sector (with gui options)
* raylib [shapes] example - circle sector drawing
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2018 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2018-2025 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class DrawCircleSector
public partial class DrawCircleSector : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Draw Circle Sector";
public string Title => "raylib [shapes] example - circle sector drawing";
private Vector2 center;
private float outerRadius;
private float startAngle;
private float endAngle;
private float segments;
private float minSegments;
public void Init()
{
center = new((GetScreenWidth() - 300) / 2.0f, GetScreenHeight() / 2.0f);
outerRadius = 180.0f;
startAngle = 0.0f;
endAngle = 180.0f;
segments = 10.0f;
minSegments = 4;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// NOTE: All variables update happens inside GUI control functions
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawLine(500, 0, 500, GetScreenHeight(), Fade(Color.LightGray, 0.6f));
DrawRectangle(500, 0, GetScreenWidth() - 500, GetScreenHeight(), Fade(Color.LightGray, 0.3f));
DrawCircleSector(center, outerRadius, startAngle, endAngle, (int)segments, Fade(Color.Maroon, 0.3f));
DrawCircleSectorLines(
center,
outerRadius,
startAngle,
endAngle,
(int)segments,
Fade(Color.Maroon, 0.6f)
);
// Draw GUI controls
//------------------------------------------------------------------------------
GuiSliderBar(new Rectangle(600, 40, 120, 20), "StartAngle", $"{startAngle:F2}", ref startAngle, 0, 720);
GuiSliderBar(new Rectangle(600, 70, 120, 20), "EndAngle", $"{endAngle:F2}", ref endAngle, 0, 720);
GuiSliderBar(new Rectangle(600, 140, 120, 20), "Radius", $"{outerRadius:F2}", ref outerRadius, 0, 200);
GuiSliderBar(new Rectangle(600, 170, 120, 20), "Segments", $"{segments:F2}", ref segments, 0, 100);
//------------------------------------------------------------------------------
minSegments = MathF.Truncate(MathF.Ceiling((endAngle - startAngle) / 90));
var color = (segments >= minSegments) ? Color.Maroon : Color.DarkGray;
DrawText($"MODE: {((segments >= minSegments) ? "MANUAL" : "AUTO")}", 600, 200, 10, color);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Minimal raygui-like widgets (plain raylib re-implementation)
//----------------------------------------------------------------------------------
private static void GuiSliderBar(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (hover && IsMouseButtonDown(MouseButton.Left))
{
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
if (value < minValue)
{
value = minValue;
}
if (value > maxValue)
{
value = maxValue;
}
}
DrawRectangleRec(bounds, Color.LightGray);
float pct = (value - minValue) / (maxValue - minValue);
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
DrawRectangleLinesEx(bounds, 1, Color.Gray);
if (!string.IsNullOrEmpty(textLeft))
{
DrawText(textLeft, (int)bounds.X - MeasureText(textLeft, 10) - 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
if (!string.IsNullOrEmpty(textRight))
{
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - circle sector drawing");
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - draw circle sector");
Vector2 center = new((GetScreenWidth() - 300) / 2, GetScreenHeight() / 2);
float outerRadius = 180.0f;
int startAngle = 0;
int endAngle = 180;
int segments = 0;
int minSegments = 4;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new DrawCircleSector();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// NOTE: All variables update happens inside GUI control functions
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawLine(500, 0, 500, GetScreenHeight(), ColorAlpha(Color.LightGray, 0.6f));
DrawRectangle(500, 0, GetScreenWidth() - 500, GetScreenHeight(), ColorAlpha(Color.LightGray, 0.3f));
DrawCircleSector(center, outerRadius, startAngle, endAngle, segments, ColorAlpha(Color.Maroon, 0.3f));
DrawCircleSectorLines(
center,
outerRadius,
startAngle,
endAngle,
segments,
ColorAlpha(Color.Maroon, 0.6f)
);
// Draw GUI controls
//------------------------------------------------------------------------------
/*startAngle = GuiSliderBar(new Rectangle( 600, 40, 120, 20), "StartAngle", startAngle, 0, 720, true );
endAngle = GuiSliderBar(new Rectangle( 600, 70, 120, 20), "EndAngle", endAngle, 0, 720, true);
outerRadius = GuiSliderBar(new Rectangle( 600, 140, 120, 20), "Radius", outerRadius, 0, 200, true);
segments = GuiSliderBar(new Rectangle( 600, 170, 120, 20), "Segments", segments, 0, 100, true);*/
//------------------------------------------------------------------------------
minSegments = (int)MathF.Ceiling((endAngle - startAngle) / 90);
Color color = (segments >= minSegments) ? Color.Maroon : Color.DarkGray;
DrawText($"MODE: {((segments >= minSegments) ? "MANUAL" : "AUTO")}", 600, 270, 10, color);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,105 +1,194 @@
/*******************************************************************************************
*
* raylib [shapes] example - draw rectangle rounded (with gui options)
* raylib [shapes] example - rounded rectangle drawing
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2018 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2018-2025 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class DrawRectangleRounded
public partial class DrawRectangleRounded : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Draw Rectangle Rounded";
public string Title => "raylib [shapes] example - rounded rectangle drawing";
private float roundness;
private float width;
private float height;
private float segments;
private float lineThick;
private bool drawRect;
private bool drawRoundedRect;
private bool drawRoundedLines;
public void Init()
{
roundness = 0.2f;
width = 200.0f;
height = 100.0f;
segments = 0.0f;
lineThick = 1.0f;
drawRect = false;
drawRoundedRect = true;
drawRoundedLines = false;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
Rectangle rec = new(
((float)GetScreenWidth() - width - 250) / 2,
(GetScreenHeight() - height) / 2.0f,
(float)width,
(float)height
);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawLine(560, 0, 560, GetScreenHeight(), Fade(Color.LightGray, 0.6f));
DrawRectangle(560, 0, GetScreenWidth() - 500, GetScreenHeight(), Fade(Color.LightGray, 0.3f));
if (drawRect)
{
DrawRectangleRec(rec, Fade(Color.Gold, 0.6f));
}
if (drawRoundedRect)
{
DrawRectangleRounded(rec, roundness, (int)segments, Fade(Color.Maroon, 0.2f));
}
if (drawRoundedLines)
{
DrawRectangleRoundedLinesEx(rec, roundness, (int)segments, lineThick, Fade(Color.Maroon, 0.4f));
}
// Draw GUI controls
//------------------------------------------------------------------------------
GuiSliderBar(new Rectangle(640, 40, 105, 20), "Width", $"{width:F2}", ref width, 0, (float)GetScreenWidth() - 300);
GuiSliderBar(new Rectangle(640, 70, 105, 20), "Height", $"{height:F2}", ref height, 0, (float)GetScreenHeight() - 50);
GuiSliderBar(new Rectangle(640, 140, 105, 20), "Roundness", $"{roundness:F2}", ref roundness, 0.0f, 1.0f);
GuiSliderBar(new Rectangle(640, 170, 105, 20), "Thickness", $"{lineThick:F2}", ref lineThick, 0, 20);
GuiSliderBar(new Rectangle(640, 240, 105, 20), "Segments", $"{segments:F2}", ref segments, 0, 60);
GuiCheckBox(new Rectangle(640, 320, 20, 20), "DrawRoundedRect", ref drawRoundedRect);
GuiCheckBox(new Rectangle(640, 350, 20, 20), "DrawRoundedLines", ref drawRoundedLines);
GuiCheckBox(new Rectangle(640, 380, 20, 20), "DrawRect", ref drawRect);
//------------------------------------------------------------------------------
var text = $"MODE: {((segments >= 4) ? "MANUAL" : "AUTO")}";
DrawText(text, 640, 280, 10, (segments >= 4) ? Color.Maroon : Color.DarkGray);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Minimal raygui-like widgets (plain raylib re-implementation)
//----------------------------------------------------------------------------------
private static void GuiSliderBar(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (hover && IsMouseButtonDown(MouseButton.Left))
{
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
if (value < minValue)
{
value = minValue;
}
if (value > maxValue)
{
value = maxValue;
}
}
DrawRectangleRec(bounds, Color.LightGray);
float pct = (value - minValue) / (maxValue - minValue);
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
DrawRectangleLinesEx(bounds, 1, Color.Gray);
if (!string.IsNullOrEmpty(textLeft))
{
DrawText(textLeft, (int)bounds.X - MeasureText(textLeft, 10) - 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
if (!string.IsNullOrEmpty(textRight))
{
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
private static void GuiCheckBox(Rectangle bounds, string text, ref bool active)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (hover && IsMouseButtonPressed(MouseButton.Left))
{
active = !active;
}
DrawRectangleLinesEx(bounds, 1, hover ? Color.DarkBlue : Color.Gray);
if (active)
{
DrawRectangle((int)bounds.X + 4, (int)bounds.Y + 4, (int)bounds.Width - 8, (int)bounds.Height - 8, Color.DarkGray);
}
if (text != null)
{
DrawText(text, (int)(bounds.X + bounds.Width + 8), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rounded rectangle drawing");
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - draw rectangle rounded");
float roundness = 0.2f;
int width = 400;
int height = 200;
int segments = 0;
int lineThick = 10;
bool drawRect = false;
bool drawRoundedRect = false;
bool drawRoundedLines = true;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new DrawRectangleRounded();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
Rectangle rec = new(
(GetScreenWidth() - width - 250) / 2.0f,
(GetScreenHeight() - height) / 2.0f,
(float)width,
(float)height
);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawLine(560, 0, 560, GetScreenHeight(), ColorAlpha(Color.LightGray, 0.6f));
DrawRectangle(560, 0, GetScreenWidth() - 500, GetScreenHeight(), ColorAlpha(Color.LightGray, 0.3f));
if (drawRect)
{
DrawRectangleRec(rec, ColorAlpha(Color.Gold, 0.6f));
}
if (drawRoundedRect)
{
DrawRectangleRounded(rec, roundness, segments, ColorAlpha(Color.Maroon, 0.2f));
}
if (drawRoundedLines)
{
DrawRectangleRoundedLinesEx(rec, roundness, segments, (float)lineThick, ColorAlpha(Color.Maroon, 0.4f));
}
// Draw GUI controls
//------------------------------------------------------------------------------
/*width = GuiSliderBar(new Rectangle( 640, 40, 105, 20 ), "Width", width, 0, GetScreenWidth() - 300, true );
height = GuiSliderBar(new Rectangle( 640, 70, 105, 20 ), "Height", height, 0, GetScreenHeight() - 50, true);
roundness = GuiSliderBar(new Rectangle( 640, 140, 105, 20 ), "Roundness", roundness, 0.0f, 1.0f, true);
lineThick = GuiSliderBar(new Rectangle( 640, 170, 105, 20 ), "Thickness", lineThick, 0, 20, true);
segments = GuiSliderBar(new Rectangle( 640, 240, 105, 20), "Segments", segments, 0, 60, true);
drawRoundedRect = GuiCheckBox(new Rectangle( 640, 320, 20, 20 ), "DrawRoundedRect", drawRoundedRect);
drawRoundedLines = GuiCheckBox(new Rectangle( 640, 350, 20, 20 ), "DrawRoundedLines", drawRoundedLines);
drawRect = GuiCheckBox(new Rectangle( 640, 380, 20, 20), "DrawRect", drawRect);*/
//------------------------------------------------------------------------------
string text = $"MODE: {((segments >= 4) ? "MANUAL" : "AUTO")}";
DrawText(text, 640, 280, 10, (segments >= 4) ? Color.Maroon : Color.DarkGray);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,130 +1,220 @@
/*******************************************************************************************
*
* raylib [shapes] example - draw ring (with gui options)
* raylib [shapes] example - ring drawing
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2018 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2018-2025 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class DrawRing
public partial class DrawRing : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Draw Ring";
public string Title => "raylib [shapes] example - ring drawing";
private Vector2 center;
private float innerRadius;
private float outerRadius;
private float startAngle;
private float endAngle;
private float segments;
private bool drawRing;
private bool drawRingLines;
private bool drawCircleLines;
public void Init()
{
center = new((GetScreenWidth() - 300) / 2.0f, GetScreenHeight() / 2.0f);
innerRadius = 80.0f;
outerRadius = 190.0f;
startAngle = 0.0f;
endAngle = 360.0f;
segments = 0.0f;
drawRing = true;
drawRingLines = false;
drawCircleLines = false;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// NOTE: All variables update happens inside GUI control functions
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawLine(500, 0, 500, GetScreenHeight(), Fade(Color.LightGray, 0.6f));
DrawRectangle(500, 0, GetScreenWidth() - 500, GetScreenHeight(), Fade(Color.LightGray, 0.3f));
if (drawRing)
{
DrawRing(
center,
innerRadius,
outerRadius,
startAngle,
endAngle,
(int)segments,
Fade(Color.Maroon, 0.3f)
);
}
if (drawRingLines)
{
DrawRingLines(
center,
innerRadius,
outerRadius,
startAngle,
endAngle,
(int)segments,
Fade(Color.Black, 0.4f)
);
}
if (drawCircleLines)
{
DrawCircleSectorLines(
center,
outerRadius,
startAngle,
endAngle,
(int)segments,
Fade(Color.Black, 0.4f)
);
}
// Draw GUI controls
//------------------------------------------------------------------------------
GuiSliderBar(new Rectangle(600, 40, 120, 20), "StartAngle", $"{startAngle:F2}", ref startAngle, -450, 450);
GuiSliderBar(new Rectangle(600, 70, 120, 20), "EndAngle", $"{endAngle:F2}", ref endAngle, -450, 450);
GuiSliderBar(new Rectangle(600, 140, 120, 20), "InnerRadius", $"{innerRadius:F2}", ref innerRadius, 0, 100);
GuiSliderBar(new Rectangle(600, 170, 120, 20), "OuterRadius", $"{outerRadius:F2}", ref outerRadius, 0, 200);
GuiSliderBar(new Rectangle(600, 240, 120, 20), "Segments", $"{segments:F2}", ref segments, 0, 100);
GuiCheckBox(new Rectangle(600, 320, 20, 20), "Draw Ring", ref drawRing);
GuiCheckBox(new Rectangle(600, 350, 20, 20), "Draw RingLines", ref drawRingLines);
GuiCheckBox(new Rectangle(600, 380, 20, 20), "Draw CircleLines", ref drawCircleLines);
//------------------------------------------------------------------------------
var minSegments = (int)MathF.Ceiling((endAngle - startAngle) / 90);
var color = (segments >= minSegments) ? Color.Maroon : Color.DarkGray;
DrawText($"MODE: {((segments >= minSegments) ? "MANUAL" : "AUTO")}", 600, 270, 10, color);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Minimal raygui-like widgets (plain raylib re-implementation)
//----------------------------------------------------------------------------------
private static void GuiSliderBar(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (hover && IsMouseButtonDown(MouseButton.Left))
{
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
if (value < minValue)
{
value = minValue;
}
if (value > maxValue)
{
value = maxValue;
}
}
DrawRectangleRec(bounds, Color.LightGray);
float pct = (value - minValue) / (maxValue - minValue);
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
DrawRectangleLinesEx(bounds, 1, Color.Gray);
if (!string.IsNullOrEmpty(textLeft))
{
DrawText(textLeft, (int)bounds.X - MeasureText(textLeft, 10) - 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
if (!string.IsNullOrEmpty(textRight))
{
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
private static void GuiCheckBox(Rectangle bounds, string text, ref bool active)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (hover && IsMouseButtonPressed(MouseButton.Left))
{
active = !active;
}
DrawRectangleLinesEx(bounds, 1, hover ? Color.DarkBlue : Color.Gray);
if (active)
{
DrawRectangle((int)bounds.X + 4, (int)bounds.Y + 4, (int)bounds.Width - 8, (int)bounds.Height - 8, Color.DarkGray);
}
if (text != null)
{
DrawText(text, (int)(bounds.X + bounds.Width + 8), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - ring drawing");
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - draw ring");
Vector2 center = new((GetScreenWidth() - 300) / 2, GetScreenHeight() / 2);
float innerRadius = 80.0f;
float outerRadius = 190.0f;
int startAngle = 0;
int endAngle = 360;
int segments = 0;
int minSegments = 4;
bool drawRing = true;
bool drawRingLines = false;
bool drawCircleLines = false;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new DrawRing();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// NOTE: All variables update happens inside GUI control functions
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawLine(500, 0, 500, GetScreenHeight(), ColorAlpha(Color.LightGray, 0.6f));
DrawRectangle(500, 0, GetScreenWidth() - 500, GetScreenHeight(), ColorAlpha(Color.LightGray, 0.3f));
if (drawRing)
{
DrawRing(
center,
innerRadius,
outerRadius,
startAngle,
endAngle,
segments,
ColorAlpha(Color.Maroon, 0.3f)
);
}
if (drawRingLines)
{
DrawRingLines(
center,
innerRadius,
outerRadius,
startAngle,
endAngle,
segments,
ColorAlpha(Color.Black, 0.4f)
);
}
if (drawCircleLines)
{
DrawCircleSectorLines(
center,
outerRadius,
startAngle,
endAngle,
segments,
ColorAlpha(Color.Black, 0.4f)
);
}
// Draw GUI controls
//------------------------------------------------------------------------------
/*startAngle = GuiSliderBar(new Rectangle( 600, 40, 120, 20 ), "StartAngle", startAngle, -450, 450, true);
endAngle = GuiSliderBar(new Rectangle( 600, 70, 120, 20 ), "EndAngle", endAngle, -450, 450, true);
innerRadius = GuiSliderBar(new Rectangle( 600, 140, 120, 20 ), "InnerRadius", innerRadius, 0, 100, true);
outerRadius = GuiSliderBar(new Rectangle( 600, 170, 120, 20 ), "OuterRadius", outerRadius, 0, 200, true);
segments = GuiSliderBar(new Rectangle( 600, 240, 120, 20 ), "Segments", segments, 0, 100, true);
drawRing = GuiCheckBox(new Rectangle( 600, 320, 20, 20 ), "Draw Ring", drawRing);
drawRingLines = GuiCheckBox(new Rectangle( 600, 350, 20, 20 ), "Draw RingLines", drawRingLines);
drawCircleLines = GuiCheckBox(new Rectangle( 600, 380, 20, 20 ), "Draw CircleLines", drawCircleLines);*/
//------------------------------------------------------------------------------
minSegments = (int)MathF.Ceiling((endAngle - startAngle) / 90);
Color color = (segments >= minSegments) ? Color.Maroon : Color.DarkGray;
DrawText($"MODE: {((segments >= minSegments) ? "MANUAL" : "AUTO")}", 600, 270, 10, color);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -1,127 +1,154 @@
/*******************************************************************************************
*
* raylib [shapes] example - easings ball anim
* raylib [shapes] example - easings ball
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
using Examples.Shared;
namespace Examples.Shapes;
public class EasingsBallAnim
public partial class EasingsBallAnim : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Easings Ball Anim";
public string Title => "raylib [shapes] example - easings ball";
// Ball variable value to be animated with easings
private int ballPositionX;
private int ballRadius;
private float ballAlpha;
private int state;
private int framesCounter;
public void Init()
{
ballPositionX = -100;
ballRadius = 20;
ballAlpha = 0.0f;
state = 0;
framesCounter = 0;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (state == 0) // Move ball position X with easing
{
framesCounter++;
ballPositionX = (int)Easings.EaseElasticOut(framesCounter, -100, screenWidth / 2.0f + 100, 120);
if (framesCounter >= 120)
{
framesCounter = 0;
state = 1;
}
}
else if (state == 1) // Increase ball radius with easing
{
framesCounter++;
ballRadius = (int)Easings.EaseElasticIn(framesCounter, 20, 500, 200);
if (framesCounter >= 200)
{
framesCounter = 0;
state = 2;
}
}
else if (state == 2) // Change ball alpha with easing (background color blending)
{
framesCounter++;
ballAlpha = Easings.EaseCubicOut(framesCounter, 0.0f, 1.0f, 200);
if (framesCounter >= 200)
{
framesCounter = 0;
state = 3;
}
}
else if (state == 3) // Reset state to play again
{
if (IsKeyPressed(KeyboardKey.Enter))
{
// Reset required variables to play again
ballPositionX = -100;
ballRadius = 20;
ballAlpha = 0.0f;
state = 0;
}
}
if (IsKeyPressed(KeyboardKey.R))
{
framesCounter = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (state >= 2)
{
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Green);
}
DrawCircle(ballPositionX, 200, ballRadius, Fade(Color.Red, 1.0f - ballAlpha));
if (state == 3)
{
DrawText("PRESS [ENTER] TO PLAY AGAIN!", 240, 200, 20, Color.Black);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings ball");
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings ball anim");
// Ball variable value to be animated with easings
int ballPositionX = -100;
int ballRadius = 20;
float ballAlpha = 0.0f;
int state = 0;
int framesCounter = 0;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new EasingsBallAnim();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (state == 0) // Move ball position X with easing
{
framesCounter += 1;
ballPositionX = (int)Easings.EaseElasticOut(framesCounter, -100, screenWidth / 2 + 100, 120);
if (framesCounter >= 120)
{
framesCounter = 0;
state = 1;
}
}
// Increase ball radius with easing
else if (state == 1)
{
framesCounter += 1;
ballRadius = (int)Easings.EaseElasticIn(framesCounter, 20, 500, 200);
if (framesCounter >= 200)
{
framesCounter = 0;
state = 2;
}
}
// Change ball alpha with easing (background color blending)
else if (state == 2)
{
framesCounter += 1;
ballAlpha = Easings.EaseCubicOut(framesCounter, 0.0f, 1.0f, 200);
if (framesCounter >= 200)
{
framesCounter = 0;
state = 3;
}
}
// Reset state to play again
else if (state == 3)
{
if (IsKeyPressed(KeyboardKey.Enter))
{
// Reset required variables to play again
ballPositionX = -100;
ballRadius = 20;
ballAlpha = 0.0f;
state = 0;
}
}
if (IsKeyPressed(KeyboardKey.R))
{
framesCounter = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (state >= 2)
{
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Green);
}
DrawCircle(ballPositionX, 200, ballRadius, ColorAlpha(Color.Red, 1.0f - ballAlpha));
if (state == 3)
{
DrawText("PRESS [ENTER] TO PLAY AGAIN!", 240, 200, 20, Color.Black);
}
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,143 +1,168 @@
/*******************************************************************************************
*
* raylib [shapes] example - easings box anim
* raylib [shapes] example - easings box
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
using Examples.Shared;
namespace Examples.Shapes;
public class EasingsBoxAnim
public partial class EasingsBoxAnim : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Easings Box Anim";
public string Title => "raylib [shapes] example - easings box";
// Box variables to be animated with easings
private Rectangle rec;
private float rotation;
private float alpha;
private int state;
private int framesCounter;
public void Init()
{
rec = new(GetScreenWidth() / 2.0f, -100, 100, 100);
rotation = 0.0f;
alpha = 1.0f;
state = 0;
framesCounter = 0;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
switch (state)
{
case 0: // Move box down to center of screen
framesCounter++;
// NOTE: Remember that 3rd parameter of easing function refers to
// desired value variation, do not confuse it with expected final value!
rec.Y = Easings.EaseElasticOut(framesCounter, -100, GetScreenHeight() / 2.0f + 100, 120);
if (framesCounter >= 120)
{
framesCounter = 0;
state = 1;
}
break;
case 1: // Scale box to an horizontal bar
framesCounter++;
rec.Height = Easings.EaseBounceOut(framesCounter, 100, -90, 120);
rec.Width = Easings.EaseBounceOut(framesCounter, 100, GetScreenWidth(), 120);
if (framesCounter >= 120)
{
framesCounter = 0;
state = 2;
}
break;
case 2: // Rotate horizontal bar rectangle
framesCounter++;
rotation = Easings.EaseQuadOut(framesCounter, 0.0f, 270.0f, 240);
if (framesCounter >= 240)
{
framesCounter = 0;
state = 3;
}
break;
case 3: // Increase bar size to fill all screen
framesCounter++;
rec.Height = Easings.EaseCircOut(framesCounter, 10, GetScreenWidth(), 120);
if (framesCounter >= 120)
{
framesCounter = 0;
state = 4;
}
break;
case 4: // Fade out animation
framesCounter++;
alpha = Easings.EaseSineOut(framesCounter, 1.0f, -1.0f, 160);
if (framesCounter >= 160)
{
framesCounter = 0;
state = 5;
}
break;
default:
break;
}
// Reset animation at any moment
if (IsKeyPressed(KeyboardKey.Space))
{
rec = new Rectangle(GetScreenWidth() / 2.0f, -100, 100, 100);
rotation = 0.0f;
alpha = 1.0f;
state = 0;
framesCounter = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawRectanglePro(
rec,
new Vector2(rec.Width / 2, rec.Height / 2),
rotation,
Fade(Color.Black, alpha)
);
DrawText("PRESS [SPACE] TO RESET BOX ANIMATION!", 10, GetScreenHeight() - 25, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings box");
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings box anim");
// Box variables to be animated with easings
Rectangle rec = new(GetScreenWidth() / 2, -100, 100, 100);
float rotation = 0.0f;
float alpha = 1.0f;
int state = 0;
int framesCounter = 0;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new EasingsBoxAnim();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
switch (state)
{
// Move box down to center of screen
case 0:
framesCounter += 1;
// NOTE: Remember that 3rd parameter of easing function refers to
// desired value variation, do not confuse it with expected final value!
rec.Y = Easings.EaseElasticOut(framesCounter, -100, GetScreenHeight() / 2 + 100, 120);
if (framesCounter >= 120)
{
framesCounter = 0;
state = 1;
}
break;
// Scale box to an horizontal bar
case 1:
framesCounter += 1;
rec.Height = Easings.EaseBounceOut(framesCounter, 100, -90, 120);
rec.Width = Easings.EaseBounceOut(framesCounter, 100, GetScreenWidth(), 120);
if (framesCounter >= 120)
{
framesCounter = 0;
state = 2;
}
break;
// Rotate horizontal bar rectangle
case 2:
framesCounter += 1;
rotation = Easings.EaseQuadOut(framesCounter, 0.0f, 270.0f, 240);
if (framesCounter >= 240)
{
framesCounter = 0;
state = 3;
}
break;
// Increase bar size to fill all screen
case 3:
framesCounter += 1;
rec.Height = Easings.EaseCircOut(framesCounter, 10, GetScreenWidth(), 120);
if (framesCounter >= 120)
{
framesCounter = 0;
state = 4;
}
break;
// Fade out animation
case 4:
framesCounter++;
alpha = Easings.EaseSineOut(framesCounter, 1.0f, -1.0f, 160);
if (framesCounter >= 160)
{
framesCounter = 0;
state = 5;
}
break;
default:
break;
}
// Reset animation at any moment
if (IsKeyPressed(KeyboardKey.Space))
{
rec = new Rectangle(GetScreenWidth() / 2, -100, 100, 100);
rotation = 0.0f;
alpha = 1.0f;
state = 0;
framesCounter = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawRectanglePro(
rec,
new Vector2(rec.Width / 2, rec.Height / 2),
rotation,
ColorAlpha(Color.Black, alpha)
);
DrawText("PRESS [SPACE] TO RESET BOX ANIMATION!", 10, GetScreenHeight() - 25, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -1,25 +1,30 @@
/*******************************************************************************************
*
* raylib [shapes] example - easings rectangle array
* raylib [shapes] example - easings rectangles
*
* Example complexity rating: [] 3/4
*
* NOTE: This example requires 'easings.h' library, provided on raylib/src. Just copy
* the library to same directory as example or make sure it's available on include path.
* the library to same directory as example or make sure it's available on include path
*
* This example has been created using raylib 2.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example originally created with raylib 2.0, last time updated with raylib 2.5
*
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
using Examples.Shared;
namespace Examples.Shapes;
public class EasingsRectangleArray
public partial class EasingsRectangleArray : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public const int RecsWidth = 50;
public const int RecsHeight = 50;
public const int MaxRecsX = 800 / RecsWidth;
@ -28,112 +33,133 @@ public class EasingsRectangleArray
// At 60 fps = 4 seconds
public const int PlayTimeInFrames = 240;
public static int Main()
public string Name => "Shapes / Easings Rectangle Array";
public string Title => "raylib [shapes] example - easings rectangles";
private Rectangle[] recs;
private float rotation;
private int framesCounter;
private int state; // Rectangles animation state: 0-Playing, 1-Finished
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
recs = new Rectangle[MaxRecsX * MaxRecsY];
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings rectangle array");
Rectangle[] recs = new Rectangle[MaxRecsX * MaxRecsY];
for (int y = 0; y < MaxRecsY; y++)
for (var y = 0; y < MaxRecsY; y++)
{
for (int x = 0; x < MaxRecsX; x++)
for (var x = 0; x < MaxRecsX; x++)
{
recs[y * MaxRecsX + x].X = RecsWidth / 2 + RecsWidth * x;
recs[y * MaxRecsX + x].Y = RecsHeight / 2 + RecsHeight * y;
recs[y * MaxRecsX + x].X = RecsWidth / 2.0f + RecsWidth * x;
recs[y * MaxRecsX + x].Y = RecsHeight / 2.0f + RecsHeight * y;
recs[y * MaxRecsX + x].Width = RecsWidth;
recs[y * MaxRecsX + x].Height = RecsHeight;
}
}
float rotation = 0.0f;
int framesCounter = 0;
rotation = 0.0f;
framesCounter = 0;
state = 0;
}
// Rectangles animation state: 0-Playing, 1-Finished
int state = 0;
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (state == 0)
{
framesCounter++;
SetTargetFPS(60);
for (var i = 0; i < MaxRecsX * MaxRecsY; i++)
{
recs[i].Height = Easings.EaseCircOut(framesCounter, RecsHeight, -RecsHeight, PlayTimeInFrames);
recs[i].Width = Easings.EaseCircOut(framesCounter, RecsWidth, -RecsWidth, PlayTimeInFrames);
if (recs[i].Height < 0)
{
recs[i].Height = 0;
}
if (recs[i].Width < 0)
{
recs[i].Width = 0;
}
// Finish playing
if ((recs[i].Height == 0) && (recs[i].Width == 0))
{
state = 1;
}
rotation = Easings.EaseLinearIn(framesCounter, 0.0f, 360.0f, PlayTimeInFrames);
}
}
else if ((state == 1) && IsKeyPressed(KeyboardKey.Space))
{
// When animation has finished, press space to restart
framesCounter = 0;
for (var i = 0; i < MaxRecsX * MaxRecsY; i++)
{
recs[i].Height = RecsHeight;
recs[i].Width = RecsWidth;
}
state = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (state == 0)
{
for (var i = 0; i < MaxRecsX * MaxRecsY; i++)
{
DrawRectanglePro(
recs[i],
new Vector2(recs[i].Width / 2, recs[i].Height / 2),
rotation,
Color.Red
);
}
}
else if (state == 1)
{
DrawText("PRESS [SPACE] TO PLAY AGAIN!", 240, 200, 20, Color.Gray);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings rectangles");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new EasingsRectangleArray();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (state == 0)
{
framesCounter++;
for (int i = 0; i < MaxRecsX * MaxRecsY; i++)
{
recs[i].Height = Easings.EaseCircOut(framesCounter, RecsHeight, -RecsHeight, PlayTimeInFrames);
recs[i].Width = Easings.EaseCircOut(framesCounter, RecsWidth, -RecsWidth, PlayTimeInFrames);
if (recs[i].Height < 0)
{
recs[i].Height = 0;
}
if (recs[i].Width < 0)
{
recs[i].Width = 0;
}
// Finish playing
if ((recs[i].Height == 0) && (recs[i].Width == 0))
{
state = 1;
}
rotation = Easings.EaseLinearIn(framesCounter, 0.0f, 360.0f, PlayTimeInFrames);
}
}
else if ((state == 1) && IsKeyPressed(KeyboardKey.Space))
{
// When animation has finished, press space to restart
framesCounter = 0;
for (int i = 0; i < MaxRecsX * MaxRecsY; i++)
{
recs[i].Height = RecsHeight;
recs[i].Width = RecsWidth;
}
state = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (state == 0)
{
for (int i = 0; i < MaxRecsX * MaxRecsY; i++)
{
DrawRectanglePro(
recs[i],
new Vector2(recs[i].Width / 2, recs[i].Height / 2),
rotation,
Color.Red
);
}
}
else if (state == 1)
{
DrawText("PRESS [SPACE] TO PLAY AGAIN!", 240, 200, 20, Color.Gray);
}
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,263 @@
/*******************************************************************************************
*
* raylib [shapes] example - easings testbed
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example contributed by Juan Miguel López (@flashback-fx) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2019-2025 Juan Miguel López (@flashback-fx) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using Examples.Shared;
namespace Examples.Shapes;
public partial class EasingsTestbed : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int FONT_SIZE = 20;
private const float D_STEP = 20.0f;
private const float D_STEP_FINE = 2.0f;
private const float D_MIN = 1.0f;
private const float D_MAX = 10000.0f;
public string Name => "Shapes / Easings Testbed";
public string Title => "raylib [shapes] example - easings testbed";
// Easing types
private const int EASE_LINEAR_NONE = 0;
private const int NUM_EASING_TYPES = 27;
private const int EASING_NONE = NUM_EASING_TYPES;
// NoEase function, used when "no easing" is selected for any axis
// It just ignores all parameters besides b
private static float NoEase(float t, float b, float c, float d)
{
// Hack to avoid compiler warning (about unused variables)
float burn = t + b + c + d;
d += burn;
return b;
}
// Easing functions reference data
private string[] easingNames;
private Func<float, float, float, float, float>[] easingFuncs;
private Vector2 ballPosition;
private float t; // Current time (in any unit measure, but same unit as duration)
private float d; // Total time it should take to complete (duration)
private bool paused;
private bool boundedT; // If true, t will stop when d >= td, otherwise t will keep adding td to its value every loop
private int easingX; // Easing selected for x axis
private int easingY; // Easing selected for y axis
public void Init()
{
easingNames = new string[]
{
"EaseLinearNone", "EaseLinearIn", "EaseLinearOut", "EaseLinearInOut",
"EaseSineIn", "EaseSineOut", "EaseSineInOut",
"EaseCircIn", "EaseCircOut", "EaseCircInOut",
"EaseCubicIn", "EaseCubicOut", "EaseCubicInOut",
"EaseQuadIn", "EaseQuadOut", "EaseQuadInOut",
"EaseExpoIn", "EaseExpoOut", "EaseExpoInOut",
"EaseBackIn", "EaseBackOut", "EaseBackInOut",
"EaseBounceOut", "EaseBounceIn", "EaseBounceInOut",
"EaseElasticIn", "EaseElasticOut", "EaseElasticInOut",
"None",
};
easingFuncs = new Func<float, float, float, float, float>[]
{
Easings.EaseLinearNone, Easings.EaseLinearIn, Easings.EaseLinearOut, Easings.EaseLinearInOut,
Easings.EaseSineIn, Easings.EaseSineOut, Easings.EaseSineInOut,
Easings.EaseCircIn, Easings.EaseCircOut, Easings.EaseCircInOut,
Easings.EaseCubicIn, Easings.EaseCubicOut, Easings.EaseCubicInOut,
Easings.EaseQuadIn, Easings.EaseQuadOut, Easings.EaseQuadInOut,
Easings.EaseExpoIn, Easings.EaseExpoOut, Easings.EaseExpoInOut,
Easings.EaseBackIn, Easings.EaseBackOut, Easings.EaseBackInOut,
Easings.EaseBounceOut, Easings.EaseBounceIn, Easings.EaseBounceInOut,
Easings.EaseElasticIn, Easings.EaseElasticOut, Easings.EaseElasticInOut,
NoEase,
};
ballPosition = new Vector2(100.0f, 100.0f);
t = 0.0f;
d = 300.0f;
paused = true;
boundedT = true;
easingX = EASING_NONE;
easingY = EASING_NONE;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.T))
{
boundedT = !boundedT;
}
// Choose easing for the X axis
if (IsKeyPressed(KeyboardKey.Right))
{
easingX++;
if (easingX > EASING_NONE)
{
easingX = 0;
}
}
else if (IsKeyPressed(KeyboardKey.Left))
{
if (easingX == 0)
{
easingX = EASING_NONE;
}
else
{
easingX--;
}
}
// Choose easing for the Y axis
if (IsKeyPressed(KeyboardKey.Down))
{
easingY++;
if (easingY > EASING_NONE)
{
easingY = 0;
}
}
else if (IsKeyPressed(KeyboardKey.Up))
{
if (easingY == 0)
{
easingY = EASING_NONE;
}
else
{
easingY--;
}
}
// Change d (duration) value
if (IsKeyPressed(KeyboardKey.W) && (d < D_MAX - D_STEP))
{
d += D_STEP;
}
else if (IsKeyPressed(KeyboardKey.Q) && (d > D_MIN + D_STEP))
{
d -= D_STEP;
}
if (IsKeyDown(KeyboardKey.S) && (d < D_MAX - D_STEP_FINE))
{
d += D_STEP_FINE;
}
else if (IsKeyDown(KeyboardKey.A) && (d > D_MIN + D_STEP_FINE))
{
d -= D_STEP_FINE;
}
// Play, pause and restart controls
if (IsKeyPressed(KeyboardKey.Space) || IsKeyPressed(KeyboardKey.T) ||
IsKeyPressed(KeyboardKey.Right) || IsKeyPressed(KeyboardKey.Left) ||
IsKeyPressed(KeyboardKey.Down) || IsKeyPressed(KeyboardKey.Up) ||
IsKeyPressed(KeyboardKey.W) || IsKeyPressed(KeyboardKey.Q) ||
IsKeyDown(KeyboardKey.S) || IsKeyDown(KeyboardKey.A) ||
(IsKeyPressed(KeyboardKey.Enter) && (boundedT == true) && (t >= d)))
{
t = 0.0f;
ballPosition.X = 100.0f;
ballPosition.Y = 100.0f;
paused = true;
}
if (IsKeyPressed(KeyboardKey.Enter))
{
paused = !paused;
}
// Movement computation
if (!paused && ((boundedT && t < d) || !boundedT))
{
ballPosition.X = easingFuncs[easingX](t, 100.0f, 700.0f - 170.0f, d);
ballPosition.Y = easingFuncs[easingY](t, 100.0f, 400.0f - 170.0f, d);
t += 1.0f;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw information text
DrawText($"Easing x: {easingNames[easingX]}", 20, FONT_SIZE, FONT_SIZE, Color.LightGray);
DrawText($"Easing y: {easingNames[easingY]}", 20, FONT_SIZE * 2, FONT_SIZE, Color.LightGray);
DrawText($"t ({(boundedT == true ? 'b' : 'u')}) = {t:F2} d = {d:F2}", 20, FONT_SIZE * 3, FONT_SIZE, Color.LightGray);
// Draw instructions text
DrawText("Use ENTER to play or pause movement, use SPACE to restart", 20, GetScreenHeight() - FONT_SIZE * 2, FONT_SIZE, Color.LightGray);
DrawText("Use Q and W or A and S keys to change duration", 20, GetScreenHeight() - FONT_SIZE * 3, FONT_SIZE, Color.LightGray);
DrawText("Use LEFT or RIGHT keys to choose easing for the x axis", 20, GetScreenHeight() - FONT_SIZE * 4, FONT_SIZE, Color.LightGray);
DrawText("Use UP or DOWN keys to choose easing for the y axis", 20, GetScreenHeight() - FONT_SIZE * 5, FONT_SIZE, Color.LightGray);
// Draw ball
DrawCircleV(ballPosition, 16.0f, Color.Maroon);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - easings testbed");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new EasingsTestbed();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,191 @@
/*******************************************************************************************
*
* raylib [shapes] example - ellipse collision
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
* Example contributed by Ziya (@Monjaris)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Ziya (@Monjaris)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class EllipseCollision : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Ellipse Collision";
public string Title => "raylib [shapes] example - collision ellipses";
private Vector2 ellipseACenter;
private float ellipseARx;
private float ellipseARy;
private Vector2 ellipseBCenter;
private float ellipseBRx;
private float ellipseBRy;
// 0 = controlling A, 1 = controlling B
private int controlled;
// Check if point is inside ellipse
private static bool CheckCollisionPointEllipse(Vector2 point, Vector2 center, float rx, float ry)
{
float dx = (point.X - center.X) / rx;
float dy = (point.Y - center.Y) / ry;
return (dx * dx + dy * dy) <= 1.0f;
}
// Check if two ellipses collide
// Uses radial boundary distance in the direction between centers — scales correctly with radii
private static bool CheckCollisionEllipses(Vector2 c1, float rx1, float ry1, Vector2 c2, float rx2, float ry2)
{
float dx = c2.X - c1.X;
float dy = c2.Y - c1.Y;
float dist = MathF.Sqrt(dx * dx + dy * dy);
// Ellipses are on top of each other
if (dist == 0.0f)
{
return true;
}
float theta = MathF.Atan2(dy, dx);
float cosT = MathF.Cos(theta);
float sinT = MathF.Sin(theta);
// Radial distance from center to ellipse boundary in direction theta
// r(theta) = (rx * ry) / sqrt((ry*cos)^2 + (rx*sin)^2)
float r1 = (rx1 * ry1) / MathF.Sqrt((ry1 * cosT) * (ry1 * cosT) + (rx1 * sinT) * (rx1 * sinT));
float r2 = (rx2 * ry2) / MathF.Sqrt((ry2 * cosT) * (ry2 * cosT) + (rx2 * sinT) * (rx2 * sinT));
return dist <= (r1 + r2);
}
public void Init()
{
ellipseACenter = new((float)screenWidth / 4, (float)screenHeight / 2);
ellipseARx = 120.0f;
ellipseARy = 70.0f;
ellipseBCenter = new((float)screenWidth * 3 / 4, (float)screenHeight / 2);
ellipseBRx = 90.0f;
ellipseBRy = 140.0f;
// 0 = controlling A, 1 = controlling B
controlled = 0;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.A))
{
controlled = 0;
}
if (IsKeyPressed(KeyboardKey.B))
{
controlled = 1;
}
if (controlled == 0)
{
ellipseACenter = GetMousePosition();
}
else
{
ellipseBCenter = GetMousePosition();
}
bool ellipsesCollide = CheckCollisionEllipses(
ellipseACenter, ellipseARx, ellipseARy,
ellipseBCenter, ellipseBRx, ellipseBRy
);
bool mouseInA = CheckCollisionPointEllipse(GetMousePosition(), ellipseACenter, ellipseARx, ellipseARy);
bool mouseInB = CheckCollisionPointEllipse(GetMousePosition(), ellipseBCenter, ellipseBRx, ellipseBRy);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawEllipse((int)ellipseACenter.X, (int)ellipseACenter.Y, ellipseARx, ellipseARy, ellipsesCollide ? Color.Red : Color.Blue);
DrawEllipse((int)ellipseBCenter.X, (int)ellipseBCenter.Y, ellipseBRx, ellipseBRy, ellipsesCollide ? Color.Red : Color.Green);
DrawEllipseLines((int)ellipseACenter.X, (int)ellipseACenter.Y, ellipseARx, ellipseARy, Color.White);
DrawEllipseLines((int)ellipseBCenter.X, (int)ellipseBCenter.Y, ellipseBRx, ellipseBRy, Color.White);
DrawCircleV(ellipseACenter, 4, Color.White);
DrawCircleV(ellipseBCenter, 4, Color.White);
if (ellipsesCollide)
{
DrawText("ELLIPSES COLLIDE", screenWidth / 2 - 120, 40, 28, Color.Red);
}
else
{
DrawText("NO COLLISION", screenWidth / 2 - 80, 40, 28, Color.DarkGray);
}
DrawText(controlled == 0 ? "Controlling: A" : "Controlling: B", 20, screenHeight - 40, 20, Color.Yellow);
if (mouseInA && controlled != 0)
{
DrawText("Mouse inside ellipse A", 20, screenHeight - 70, 20, Color.Blue);
}
if (mouseInB && controlled != 1)
{
DrawText("Mouse inside ellipse B", 20, screenHeight - 70, 20, Color.Green);
}
DrawText("Press [A] or [B] to switch control", 20, 20, 20, Color.Gray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - collision ellipses");
SetTargetFPS(60);
var game = new EllipseCollision();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -2,106 +2,140 @@
*
* raylib [shapes] example - following eyes
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Copyright (c) 2013-2019 Ramon Santamaria (@raysan5)
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System;
using System.Numerics;
using Raylib_cs;
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class FollowingEyes
public partial class FollowingEyes : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Following Eyes";
public string Title => "raylib [shapes] example - following eyes";
private Vector2 scleraLeftPosition;
private Vector2 scleraRightPosition;
private float scleraRadius;
private Vector2 irisLeftPosition;
private Vector2 irisRightPosition;
private float irisRadius;
private float angle;
private float dx, dy, dxx, dyy;
public void Init()
{
scleraLeftPosition = new(GetScreenWidth() / 2.0f - 100.0f, GetScreenHeight() / 2.0f);
scleraRightPosition = new(GetScreenWidth() / 2.0f + 100.0f, GetScreenHeight() / 2.0f);
scleraRadius = 80;
irisLeftPosition = new(GetScreenWidth() / 2.0f - 100.0f, GetScreenHeight() / 2.0f);
irisRightPosition = new(GetScreenWidth() / 2.0f + 100.0f, GetScreenHeight() / 2.0f);
irisRadius = 24;
angle = 0.0f;
dx = 0.0f;
dy = 0.0f;
dxx = 0.0f;
dyy = 0.0f;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
irisLeftPosition = GetMousePosition();
irisRightPosition = GetMousePosition();
// Check not inside the left eye sclera
if (!CheckCollisionPointCircle(irisLeftPosition, scleraLeftPosition, scleraRadius - irisRadius))
{
dx = irisLeftPosition.X - scleraLeftPosition.X;
dy = irisLeftPosition.Y - scleraLeftPosition.Y;
angle = MathF.Atan2(dy, dx);
dxx = (scleraRadius - irisRadius) * MathF.Cos(angle);
dyy = (scleraRadius - irisRadius) * MathF.Sin(angle);
irisLeftPosition.X = scleraLeftPosition.X + dxx;
irisLeftPosition.Y = scleraLeftPosition.Y + dyy;
}
// Check not inside the right eye sclera
if (!CheckCollisionPointCircle(irisRightPosition, scleraRightPosition, scleraRadius - irisRadius))
{
dx = irisRightPosition.X - scleraRightPosition.X;
dy = irisRightPosition.Y - scleraRightPosition.Y;
angle = MathF.Atan2(dy, dx);
dxx = (scleraRadius - irisRadius) * MathF.Cos(angle);
dyy = (scleraRadius - irisRadius) * MathF.Sin(angle);
irisRightPosition.X = scleraRightPosition.X + dxx;
irisRightPosition.Y = scleraRightPosition.Y + dyy;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawCircleV(scleraLeftPosition, scleraRadius, Color.LightGray);
DrawCircleV(irisLeftPosition, irisRadius, Color.Brown);
DrawCircleV(irisLeftPosition, 10, Color.Black);
DrawCircleV(scleraRightPosition, scleraRadius, Color.LightGray);
DrawCircleV(irisRightPosition, irisRadius, Color.DarkGreen);
DrawCircleV(irisRightPosition, 10, Color.Black);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - following eyes");
Vector2 scleraLeftPosition = new(GetScreenWidth() / 2 - 100, GetScreenHeight() / 2);
Vector2 scleraRightPosition = new(GetScreenWidth() / 2 + 100, GetScreenHeight() / 2);
float scleraRadius = 80;
Vector2 irisLeftPosition = new(GetScreenWidth() / 2 - 100, GetScreenHeight() / 2);
Vector2 irisRightPosition = new(GetScreenWidth() / 2 + 100, GetScreenHeight() / 2);
float irisRadius = 24;
float angle = 0.0f;
float dx = 0.0f, dy = 0.0f, dxx = 0.0f, dyy = 0.0f;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new FollowingEyes();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
irisLeftPosition = GetMousePosition();
irisRightPosition = GetMousePosition();
// Check not inside the left eye sclera
if (!CheckCollisionPointCircle(irisLeftPosition, scleraLeftPosition, scleraRadius - 20))
{
dx = irisLeftPosition.X - scleraLeftPosition.X;
dy = irisLeftPosition.Y - scleraLeftPosition.Y;
angle = MathF.Atan2(dy, dx);
dxx = (scleraRadius - irisRadius) * MathF.Cos(angle);
dyy = (scleraRadius - irisRadius) * MathF.Sin(angle);
irisLeftPosition.X = scleraLeftPosition.X + dxx;
irisLeftPosition.Y = scleraLeftPosition.Y + dyy;
}
// Check not inside the right eye sclera
if (!CheckCollisionPointCircle(irisRightPosition, scleraRightPosition, scleraRadius - 20))
{
dx = irisRightPosition.X - scleraRightPosition.X;
dy = irisRightPosition.Y - scleraRightPosition.Y;
angle = MathF.Atan2(dy, dx);
dxx = (scleraRadius - irisRadius) * MathF.Cos(angle);
dyy = (scleraRadius - irisRadius) * MathF.Sin(angle);
irisRightPosition.X = scleraRightPosition.X + dxx;
irisRightPosition.Y = scleraRightPosition.Y + dyy;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawCircleV(scleraLeftPosition, scleraRadius, Color.LightGray);
DrawCircleV(irisLeftPosition, irisRadius, Color.Brown);
DrawCircleV(irisLeftPosition, 10, Color.Black);
DrawCircleV(scleraRightPosition, scleraRadius, Color.LightGray);
DrawCircleV(irisRightPosition, irisRadius, Color.DarkGreen);
DrawCircleV(irisRightPosition, 10, Color.Black);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,313 @@
/*******************************************************************************************
*
* raylib [shapes] example - hilbert curve
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.6, last time updated with raylib 5.6
*
* Example contributed by Hamza RAHAL (@hmz-rhl) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Hamza RAHAL (@hmz-rhl)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class HilbertCurve : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Hilbert Curve";
public string Title => "raylib [shapes] example - hilbert curve";
private int order;
private float size;
private int strokeCount;
private Vector2[] hilbertPath;
private int prevOrder;
private int prevSize; // NOTE: Size from slider is float but for comparison we use int
private int counter;
private float thick;
private bool animate;
public void Init()
{
order = 2;
size = (float)GetScreenHeight();
strokeCount = 0;
hilbertPath = LoadHilbertPath(order, size, out strokeCount);
prevOrder = order;
prevSize = (int)size;
counter = 0;
thick = 2.0f;
animate = true;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Check if order or size have changed to regenerate
// NOTE: Size from slider is float but for comparison we use int
if ((prevOrder != order) || (prevSize != (int)size))
{
hilbertPath = LoadHilbertPath(order, size, out strokeCount);
if (animate)
{
counter = 0;
}
else
{
counter = strokeCount;
}
prevOrder = order;
prevSize = (int)size;
}
//----------------------------------------------------------------------------------
// Draw
//--------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (counter < strokeCount)
{
// Draw Hilbert path animation, one stroke every frame
for (int i = 1; i <= counter; i++)
{
DrawLineEx(hilbertPath[i], hilbertPath[i - 1], thick, ColorFromHSV(((float)i / strokeCount) * 360.0f, 1.0f, 1.0f));
}
counter += 1;
}
else
{
// Draw full Hilbert path
for (int i = 1; i < strokeCount; i++)
{
DrawLineEx(hilbertPath[i], hilbertPath[i - 1], thick, ColorFromHSV(((float)i / strokeCount) * 360.0f, 1.0f, 1.0f));
}
}
// Draw UI (minimal raygui-like controls, raygui is not bound in raylib-cs)
GuiCheckBox(new Rectangle(450, 50, 20, 20), "ANIMATE GENERATION ON CHANGE", ref animate);
GuiSpinner(new Rectangle(585, 100, 180, 30), "HILBERT CURVE ORDER: ", ref order, 2, 8);
GuiSlider(new Rectangle(524, 150, 240, 24), "THICKNESS: ", null, ref thick, 1.0f, 10.0f);
GuiSlider(new Rectangle(524, 190, 240, 24), "TOTAL SIZE: ", null, ref size, 10.0f, GetScreenHeight() * 1.5f);
EndDrawing();
//--------------------------------------------------------------------------
}
public void Unload()
{
}
//------------------------------------------------------------------------------------
// Module Functions Definition
//------------------------------------------------------------------------------------
// Load the whole Hilbert Path (including each U and their link)
private static Vector2[] LoadHilbertPath(int order, float size, out int strokeCount)
{
int N = 1 << order;
float len = size / N;
strokeCount = N * N;
Vector2[] hilbertPath = new Vector2[strokeCount];
for (int i = 0; i < strokeCount; i++)
{
hilbertPath[i] = ComputeHilbertStep(order, i);
hilbertPath[i].X = hilbertPath[i].X * len + len / 2.0f;
hilbertPath[i].Y = hilbertPath[i].Y * len + len / 2.0f;
}
return hilbertPath;
}
// Compute Hilbert path U positions
private static Vector2 ComputeHilbertStep(int order, int index)
{
// Hilbert points base pattern
Vector2[] hilbertPoints = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 1),
new Vector2(1, 0),
};
int hilbertIndex = index & 3;
Vector2 vect = hilbertPoints[hilbertIndex];
float temp = 0.0f;
int len = 0;
for (int j = 1; j < order; j++)
{
index = index >> 2;
hilbertIndex = index & 3;
len = 1 << j;
switch (hilbertIndex)
{
case 0:
{
temp = vect.X;
vect.X = vect.Y;
vect.Y = temp;
}
break;
case 2:
{
vect.X += len;
vect.Y += len;
}
break;
case 1:
vect.Y += len;
break;
case 3:
{
temp = len - 1 - vect.X;
vect.X = 2 * len - 1 - vect.Y;
vect.Y = temp;
}
break;
default:
break;
}
}
return vect;
}
//----------------------------------------------------------------------------------
// Minimal raygui-like widgets (plain raylib re-implementation)
//----------------------------------------------------------------------------------
private static void GuiCheckBox(Rectangle bounds, string text, ref bool active)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (hover && IsMouseButtonPressed(MouseButton.Left))
{
active = !active;
}
DrawRectangleLinesEx(bounds, 1, hover ? Color.DarkBlue : Color.Gray);
if (active)
{
DrawRectangle((int)bounds.X + 4, (int)bounds.Y + 4, (int)bounds.Width - 8, (int)bounds.Height - 8, Color.DarkGray);
}
if (text != null)
{
DrawText(text, (int)(bounds.X + bounds.Width + 8), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
private static void GuiSpinner(Rectangle bounds, string text, ref int value, int minValue, int maxValue)
{
Vector2 mouse = GetMousePosition();
Rectangle left = new Rectangle(bounds.X, bounds.Y, bounds.Height, bounds.Height);
Rectangle right = new Rectangle(bounds.X + bounds.Width - bounds.Height, bounds.Y, bounds.Height, bounds.Height);
Rectangle mid = new Rectangle(bounds.X + bounds.Height, bounds.Y, bounds.Width - 2 * bounds.Height, bounds.Height);
if (CheckCollisionPointRec(mouse, left) && IsMouseButtonPressed(MouseButton.Left) && value > minValue)
{
value--;
}
if (CheckCollisionPointRec(mouse, right) && IsMouseButtonPressed(MouseButton.Left) && value < maxValue)
{
value++;
}
DrawRectangleRec(mid, Color.RayWhite);
DrawRectangleLinesEx(mid, 1, Color.Gray);
DrawRectangleRec(left, Color.LightGray);
DrawRectangleLinesEx(left, 1, Color.Gray);
DrawRectangleRec(right, Color.LightGray);
DrawRectangleLinesEx(right, 1, Color.Gray);
DrawText("-", (int)(left.X + left.Width / 2 - 2), (int)(left.Y + left.Height / 2 - 5), 10, Color.DarkGray);
DrawText("+", (int)(right.X + right.Width / 2 - 3), (int)(right.Y + right.Height / 2 - 5), 10, Color.DarkGray);
string vs = value.ToString();
DrawText(vs, (int)(mid.X + mid.Width / 2 - MeasureText(vs, 10) / 2), (int)(mid.Y + mid.Height / 2 - 5), 10, Color.DarkGray);
if (text != null)
{
DrawText(text, (int)bounds.X - MeasureText(text, 10) - 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
private static void GuiSlider(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (hover && IsMouseButtonDown(MouseButton.Left))
{
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
if (value < minValue)
{
value = minValue;
}
if (value > maxValue)
{
value = maxValue;
}
}
DrawRectangleRec(bounds, Color.LightGray);
float pct = (value - minValue) / (maxValue - minValue);
float handleX = bounds.X + pct * bounds.Width;
DrawRectangle((int)(handleX - 5), (int)bounds.Y, 10, (int)bounds.Height, Color.DarkGray);
DrawRectangleLinesEx(bounds, 1, Color.Gray);
if (textLeft != null)
{
DrawText(textLeft, (int)bounds.X - MeasureText(textLeft, 10) - 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
if (textRight != null)
{
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - hilbert curve");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new HilbertCurve();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,221 @@
/*******************************************************************************************
*
* raylib [shapes] example - kaleidoscope
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.6
*
* Example contributed by Hugo ARNAL (@hugoarnal) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Hugo ARNAL (@hugoarnal) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raymath;
namespace Examples.Shapes;
public partial class Kaleidoscope : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int MAX_DRAW_LINES = 8192;
// Line data type
private struct Line
{
public Vector2 Start;
public Vector2 End;
}
public string Name => "Shapes / Kaleidoscope";
public string Title => "raylib [shapes] example - kaleidoscope";
public int TargetFps => 20;
// Lines array as a global static variable to be stored
// in heap and avoid potential stack overflow (on Web platform)
private Line[] lines;
// Line drawing properties
private int symmetry;
private float angle;
private float thickness;
private Rectangle resetButtonRec;
private Rectangle backButtonRec;
private Rectangle nextButtonRec;
private Vector2 mousePos;
private Vector2 prevMousePos;
private Vector2 scaleVector;
private Vector2 offset;
private Camera2D camera;
private int currentLineCounter;
private int totalLineCounter;
private bool resetButtonClicked;
private bool backButtonClicked;
private bool nextButtonClicked;
public void Init()
{
lines = new Line[MAX_DRAW_LINES];
// Line drawing properties
symmetry = 6;
angle = 360.0f / (float)symmetry;
thickness = 3.0f;
resetButtonRec = new(screenWidth - 55.0f, 5.0f, 50, 25);
backButtonRec = new(screenWidth - 55.0f, screenHeight - 30.0f, 25, 25);
nextButtonRec = new(screenWidth - 30.0f, screenHeight - 30.0f, 25, 25);
mousePos = new(0, 0);
prevMousePos = new(0, 0);
scaleVector = new(1.0f, -1.0f);
offset = new((float)screenWidth / 2.0f, (float)screenHeight / 2.0f);
camera = new();
camera.Target = new(0, 0);
camera.Offset = offset;
camera.Rotation = 0.0f;
camera.Zoom = 1.0f;
currentLineCounter = 0;
totalLineCounter = 0;
resetButtonClicked = false;
backButtonClicked = false;
nextButtonClicked = false;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
prevMousePos = mousePos;
mousePos = GetMousePosition();
Vector2 lineStart = Vector2Subtract(mousePos, offset);
Vector2 lineEnd = Vector2Subtract(prevMousePos, offset);
if (
IsMouseButtonDown(MouseButton.Left)
&& !CheckCollisionPointRec(mousePos, resetButtonRec)
&& !CheckCollisionPointRec(mousePos, backButtonRec)
&& !CheckCollisionPointRec(mousePos, nextButtonRec)
)
{
for (int s = 0; (s < symmetry) && (totalLineCounter < (MAX_DRAW_LINES - 1)); s++)
{
lineStart = Vector2Rotate(lineStart, angle * DEG2RAD);
lineEnd = Vector2Rotate(lineEnd, angle * DEG2RAD);
// Store mouse line
lines[totalLineCounter].Start = lineStart;
lines[totalLineCounter].End = lineEnd;
// Store reflective line
lines[totalLineCounter + 1].Start = Vector2Multiply(lineStart, scaleVector);
lines[totalLineCounter + 1].End = Vector2Multiply(lineEnd, scaleVector);
totalLineCounter += 2;
currentLineCounter = totalLineCounter;
}
}
if (resetButtonClicked)
{
Array.Clear(lines, 0, MAX_DRAW_LINES);
currentLineCounter = 0;
totalLineCounter = 0;
}
if (backButtonClicked && (currentLineCounter > 0))
{
currentLineCounter -= 1;
}
if (nextButtonClicked && (currentLineCounter < MAX_DRAW_LINES) && ((currentLineCounter + 1) <= totalLineCounter))
{
currentLineCounter += 1;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode2D(camera);
for (int s = 0; s < symmetry; s++)
{
for (int i = 0; i < currentLineCounter; i += 2)
{
DrawLineEx(lines[i].Start, lines[i].End, thickness, Color.Black);
DrawLineEx(lines[i + 1].Start, lines[i + 1].End, thickness, Color.Black);
}
}
EndMode2D();
// NOTE: raygui is not bound in raylib-cs, so the on-screen back/next/reset
// controls are unavailable; drawing with the mouse still works.
//------------------------------------------------------------------------------
/*
if ((currentLineCounter - 1) < 0) GuiDisable();
backButtonClicked = GuiButton(backButtonRec, "<");
GuiEnable();
if ((currentLineCounter + 1) > totalLineCounter) GuiDisable();
nextButtonClicked = GuiButton(nextButtonRec, ">");
GuiEnable();
resetButtonClicked = GuiButton(resetButtonRec, "Reset");
*/
//------------------------------------------------------------------------------
DrawText($"LINES: {currentLineCounter}/{MAX_DRAW_LINES}", 10, screenHeight - 30, 20, Color.Maroon);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - kaleidoscope");
SetTargetFPS(20);
//--------------------------------------------------------------------------------------
var game = new Kaleidoscope();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,67 +1,124 @@
/*******************************************************************************************
*
* raylib [shapes] example - Cubic-bezier lines
* raylib [shapes] example - lines bezier
*
* This example has been created using raylib 1.7 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 1/4
*
* Copyright (c) 2017 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.7, last time updated with raylib 1.7
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2017-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class LinesBezier
public partial class LinesBezier : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Lines Bezier";
public string Title => "raylib [shapes] example - lines bezier";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
private Vector2 startPoint;
private Vector2 endPoint;
private bool moveStartPoint;
private bool moveEndPoint;
public void Init()
{
startPoint = new(30, 30);
endPoint = new(screenWidth - 30, screenHeight - 30);
moveStartPoint = false;
moveEndPoint = false;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
var mouse = GetMousePosition();
if (CheckCollisionPointCircle(mouse, startPoint, 10.0f) && IsMouseButtonDown(MouseButton.Left))
{
moveStartPoint = true;
}
else if (CheckCollisionPointCircle(mouse, endPoint, 10.0f) && IsMouseButtonDown(MouseButton.Left))
{
moveEndPoint = true;
}
if (moveStartPoint)
{
startPoint = mouse;
if (IsMouseButtonReleased(MouseButton.Left))
{
moveStartPoint = false;
}
}
if (moveEndPoint)
{
endPoint = mouse;
if (IsMouseButtonReleased(MouseButton.Left))
{
moveEndPoint = false;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("MOVE START-END POINTS WITH MOUSE", 15, 20, 20, Color.Gray);
// Draw line Cubic Bezier, in-out interpolation (easing), no control points
DrawLineBezier(startPoint, endPoint, 4.0f, Color.Blue);
// Draw start-end spline circles with some details
DrawCircleV(startPoint, CheckCollisionPointCircle(mouse, startPoint, 10.0f) ? 14.0f : 8.0f, moveStartPoint ? Color.Red : Color.Blue);
DrawCircleV(endPoint, CheckCollisionPointCircle(mouse, endPoint, 10.0f) ? 14.0f : 8.0f, moveEndPoint ? Color.Red : Color.Blue);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - cubic-bezier lines");
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - lines bezier");
Vector2 start = new(0, 0);
Vector2 end = new(screenWidth, screenHeight);
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new LinesBezier();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsMouseButtonDown(MouseButton.Left))
{
start = GetMousePosition();
}
else if (IsMouseButtonDown(MouseButton.Right))
{
end = GetMousePosition();
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("USE MOUSE LEFT-RIGHT CLICK to DEFINE LINE START and END POINTS", 15, 20, 20, Color.Gray);
DrawLineBezier(start, end, 2.0f, Color.Red);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,186 @@
/*******************************************************************************************
*
* raylib [shapes] example - lines drawing
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 6.0, last time updated with raylib 5.6
*
* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Robin (@RobinsAviary)
*
********************************************************************************************/
using static Raylib_cs.Raymath;
namespace Examples.Shapes;
public partial class LinesDrawing : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Lines Drawing";
public string Title => "raylib [shapes] example - lines drawing";
// Hint text that shows before you click the screen
private bool startText;
// The mouse's position on the previous frame
private Vector2 mousePositionPrevious;
// The canvas to draw lines on
private RenderTexture2D canvas;
// The line's thickness
private float lineThickness;
// The lines hue (in HSV, from 0-360)
private float lineHue;
public void Init()
{
// Hint text that shows before you click the screen
startText = true;
// The mouse's position on the previous frame
mousePositionPrevious = GetMousePosition();
// The canvas to draw lines on
canvas = LoadRenderTexture(screenWidth, screenHeight);
// The line's thickness
lineThickness = 8.0f;
// The lines hue (in HSV, from 0-360)
lineHue = 0.0f;
// Clear the canvas to the background color
BeginTextureMode(canvas);
ClearBackground(Color.RayWhite);
EndTextureMode();
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Disable the hint text once the user clicks
if (IsMouseButtonPressed(MouseButton.Left) && startText)
{
startText = false;
}
// Clear the canvas when the user middle-clicks
if (IsMouseButtonPressed(MouseButton.Middle))
{
BeginTextureMode(canvas);
ClearBackground(Color.RayWhite);
EndTextureMode();
}
// Store whether the left and right buttons are down
bool leftButtonDown = IsMouseButtonDown(MouseButton.Left);
bool rightButtonDown = IsMouseButtonDown(MouseButton.Right);
if (leftButtonDown || rightButtonDown)
{
// The color for the line
Color drawColor = Color.White;
if (leftButtonDown)
{
// Increase the hue value by the distance our cursor has moved since the last frame (divided by 3)
lineHue += Vector2Distance(mousePositionPrevious, GetMousePosition()) / 3.0f;
// While the hue is >=360, subtract it to bring it down into the range 0-360
// This is more visually accurate than resetting to zero
while (lineHue >= 360.0f)
{
lineHue -= 360.0f;
}
// Create the final color
drawColor = ColorFromHSV(lineHue, 1.0f, 1.0f);
}
else if (rightButtonDown)
{
drawColor = Color.RayWhite; // Use the background color as an "eraser"
}
// Draw the line onto the canvas
BeginTextureMode(canvas);
// Circles act as "caps", smoothing corners
DrawCircleV(mousePositionPrevious, lineThickness / 2.0f, drawColor);
DrawCircleV(GetMousePosition(), lineThickness / 2.0f, drawColor);
DrawLineEx(mousePositionPrevious, GetMousePosition(), lineThickness, drawColor);
EndTextureMode();
}
// Update line thickness based on mousewheel
lineThickness += GetMouseWheelMove();
lineThickness = Clamp(lineThickness, 1.0f, 500.0f);
// Update mouse's previous position
mousePositionPrevious = GetMousePosition();
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
// Draw the render texture to the screen, flipped vertically to make it appear top-side up
DrawTextureRec(canvas.Texture, new Rectangle(0.0f, 0.0f, (float)canvas.Texture.Width, (float)-canvas.Texture.Height), Vector2Zero(), Color.White);
// Draw the preview circle
if (!leftButtonDown)
{
DrawCircleLinesV(GetMousePosition(), lineThickness / 2.0f, new Color(127, 127, 127, 127));
}
// Draw the hint text
if (startText)
{
DrawText("try clicking and dragging!", 275, 215, 20, Color.LightGray);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadRenderTexture(canvas); // Unload the canvas render texture
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - lines drawing");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new LinesDrawing();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,191 +1,221 @@
/*******************************************************************************************
*
* raylib [shapes] example - raylib logo animation
* raylib [shapes] example - logo raylib anim
*
* This example has been created using raylib 1.4 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Copyright (c) 2014 Ramon Santamaria (@raysan5)
* Example originally created with raylib 2.5, last time updated with raylib 4.0
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class LogoRaylibAnim
public partial class LogoRaylibAnim : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Logo Raylib Anim";
public string Title => "raylib [shapes] example - logo raylib anim";
private int logoPositionX;
private int logoPositionY;
private int framesCounter;
private int lettersCount;
private int topSideRecWidth;
private int leftSideRecHeight;
private int bottomSideRecWidth;
private int rightSideRecHeight;
private int state; // Tracking animation states (State Machine)
private float alpha; // Useful for fading
private Color outline;
public void Init()
{
logoPositionX = screenWidth / 2 - 128;
logoPositionY = screenHeight / 2 - 128;
framesCounter = 0;
lettersCount = 0;
topSideRecWidth = 16;
leftSideRecHeight = 16;
bottomSideRecWidth = 16;
rightSideRecHeight = 16;
state = 0;
alpha = 1.0f;
outline = new(139, 71, 135, 255);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (state == 0) // State 0: Small box blinking
{
framesCounter++;
if (framesCounter == 120)
{
state = 1;
framesCounter = 0; // Reset counter... will be used later...
}
}
else if (state == 1) // State 1: Top and left bars growing
{
topSideRecWidth += 4;
leftSideRecHeight += 4;
if (topSideRecWidth == 256)
{
state = 2;
}
}
else if (state == 2) // State 2: Bottom and right bars growing
{
bottomSideRecWidth += 4;
rightSideRecHeight += 4;
if (bottomSideRecWidth == 256)
{
state = 3;
}
}
else if (state == 3) // State 3: Letters appearing (one by one)
{
framesCounter++;
// Every 12 frames, one more letter!
if (framesCounter / 12 != 0)
{
lettersCount++;
framesCounter = 0;
}
// When all letters have appeared, just fade out everything
if (lettersCount >= 10)
{
alpha -= 0.02f;
if (alpha <= 0.0f)
{
alpha = 0.0f;
state = 4;
}
}
}
else if (state == 4) // State 4: Reset and Replay
{
if (IsKeyPressed(KeyboardKey.R))
{
framesCounter = 0;
lettersCount = 0;
topSideRecWidth = 16;
leftSideRecHeight = 16;
bottomSideRecWidth = 16;
rightSideRecHeight = 16;
alpha = 1.0f;
state = 0; // Return to State 0
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (state == 0)
{
if ((framesCounter / 15) % 2 != 0)
{
DrawRectangle(logoPositionX, logoPositionY, 16, 16, outline);
}
}
else if (state == 1)
{
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, outline);
DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, outline);
}
else if (state == 2)
{
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, outline);
DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, outline);
DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, outline);
DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, outline);
}
else if (state == 3)
{
var outlineFade = Fade(outline, alpha);
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, outlineFade);
DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, outlineFade);
DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, outlineFade);
DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, outlineFade);
var whiteFade = Fade(Color.RayWhite, alpha);
DrawRectangle(screenWidth / 2 - 112, screenHeight / 2 - 112, 224, 224, whiteFade);
var label = Fade(new Color(155, 79, 151, 255), alpha);
var text = "raylib".SubText(0, lettersCount);
DrawText(text, screenWidth / 2 - 44, screenHeight / 2 + 28, 50, label);
DrawText("cs".SubText(0, lettersCount), screenWidth / 2 - 44, screenHeight / 2 + 58, 50, label);
}
else if (state == 4)
{
DrawText("[R] REPLAY", 340, 200, 20, Color.Gray);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - logo raylib anim");
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - raylib logo animation");
int logoPositionX = screenWidth / 2 - 128;
int logoPositionY = screenHeight / 2 - 128;
int framesCounter = 0;
int lettersCount = 0;
int topSideRecWidth = 16;
int leftSideRecHeight = 16;
int bottomSideRecWidth = 16;
int rightSideRecHeight = 16;
// Tracking animation states (State Machine)
int state = 0;
// Useful for fading
float alpha = 1.0f;
Color outline = new(139, 71, 135, 255);
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new LogoRaylibAnim();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// State 0: Small box blinking
if (state == 0)
{
framesCounter++;
// Reset counter... will be used later...
if (framesCounter == 120)
{
state = 1;
framesCounter = 0;
}
}
// State 1: Top and left bars growing
else if (state == 1)
{
topSideRecWidth += 4;
leftSideRecHeight += 4;
if (topSideRecWidth == 256)
{
state = 2;
}
}
// State 2: Bottom and right bars growing
else if (state == 2)
{
bottomSideRecWidth += 4;
rightSideRecHeight += 4;
if (bottomSideRecWidth == 256)
{
state = 3;
}
}
// State 3: Letters appearing (one by one)
else if (state == 3)
{
framesCounter++;
// Every 12 frames, one more letter!
if (framesCounter / 12 != 0)
{
lettersCount++;
framesCounter = 0;
}
// When all letters have appeared, just fade out everything
if (lettersCount >= 10)
{
alpha -= 0.02f;
if (alpha <= 0.0f)
{
alpha = 0.0f;
state = 4;
}
}
}
// State 4: Reset and Replay
else if (state == 4)
{
if (IsKeyPressed(KeyboardKey.R))
{
framesCounter = 0;
lettersCount = 0;
topSideRecWidth = 16;
leftSideRecHeight = 16;
bottomSideRecWidth = 16;
rightSideRecHeight = 16;
// Return to State 0
alpha = 1.0f;
state = 0;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (state == 0)
{
if ((framesCounter / 15) % 2 != 0)
{
DrawRectangle(logoPositionX, logoPositionY, 16, 16, outline);
}
}
else if (state == 1)
{
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, outline);
DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, outline);
}
else if (state == 2)
{
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, outline);
DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, outline);
DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, outline);
DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, outline);
}
else if (state == 3)
{
Color outlineFade = ColorAlpha(outline, alpha);
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, outlineFade);
DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, outlineFade);
DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, outlineFade);
DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, outlineFade);
Color whiteFade = ColorAlpha(Color.RayWhite, alpha);
DrawRectangle(screenWidth / 2 - 112, screenHeight / 2 - 112, 224, 224, whiteFade);
Color label = ColorAlpha(new Color(155, 79, 151, 255), alpha);
string text = "raylib".SubText(0, lettersCount);
DrawText(text, screenWidth / 2 - 44, screenHeight / 2 + 28, 50, label);
DrawText("cs".SubText(0, lettersCount), screenWidth / 2 - 44, screenHeight / 2 + 58, 50, label);
}
else if (state == 4)
{
DrawText("[R] REPLAY", 340, 200, 20, Color.Gray);
}
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -1,59 +1,78 @@
/*******************************************************************************************
*
* raylib [shapes] example - Draw raylib logo using basic shapes
* raylib [shapes] example - logo raylib
*
* This example has been created using raylib 1.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 1/4
*
* Copyright (c) 2014 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.0, last time updated with raylib 1.0
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class LogoRaylibShape
public partial class LogoRaylibShape : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Logo Raylib Shape";
public string Title => "raylib [shapes] example - logo raylib";
public void Init()
{
}
public void Update()
{
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawRectangle(screenWidth / 2 - 128, screenHeight / 2 - 128, 256, 256, new Color(139, 71, 135, 255));
DrawRectangle(screenWidth / 2 - 112, screenHeight / 2 - 112, 224, 224, Color.RayWhite);
DrawText("raylib", screenWidth / 2 - 44, screenHeight / 2 + 28, 50, new Color(155, 79, 151, 255));
DrawText("cs", screenWidth / 2 - 44, screenHeight / 2 + 58, 50, new Color(155, 79, 151, 255));
DrawText("this is NOT a texture!", 350, 370, 10, Color.Gray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - logo raylib");
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - raylib logo using shapes");
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new LogoRaylibShape();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update your variables here
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawRectangle(screenWidth / 2 - 128, screenHeight / 2 - 128, 256, 256, new Color(139, 71, 135, 255));
DrawRectangle(screenWidth / 2 - 112, screenHeight / 2 - 112, 224, 224, Color.RayWhite);
DrawText("raylib", screenWidth / 2 - 44, screenHeight / 2 + 28, 50, new Color(155, 79, 151, 255));
DrawText("cs", screenWidth / 2 - 44, screenHeight / 2 + 58, 50, new Color(155, 79, 151, 255));
DrawText("this is NOT a texture!", 350, 370, 10, Color.Gray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,150 @@
/*******************************************************************************************
*
* raylib [shapes] example - math angle rotation
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 6.0, last time updated with raylib 5.6
*
* Example contributed by Kris (@krispy-snacc) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Kris (@krispy-snacc)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class MathAngleRotation : IExample
{
private const int screenWidth = 720;
private const int screenHeight = 400;
public string Name => "Shapes / Math Angle Rotation";
public string Title => "raylib [shapes] example - math angle rotation";
public int Width => screenWidth;
public int Height => screenHeight;
private Vector2 center;
private const float lineLength = 150.0f;
// Predefined angles for fixed lines
private int[] angles;
private int numAngles;
private float totalAngle; // Animated rotation angle
public void Init()
{
center = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
// Predefined angles for fixed lines
angles = new[] { 0, 30, 60, 90 };
numAngles = angles.Length;
totalAngle = 0.0f; // Animated rotation angle
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
totalAngle += 1.0f; // degrees per frame
if (totalAngle >= 360.0f)
{
totalAngle -= 360.0f;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.White);
DrawText("Fixed angles + rotating line", 10, 10, 20, Color.LightGray);
// Draw fixed-angle lines with colorful gradient
for (int i = 0; i < numAngles; i++)
{
float rad = angles[i] * DEG2RAD;
Vector2 end = new Vector2(center.X + MathF.Cos(rad) * lineLength,
center.Y + MathF.Sin(rad) * lineLength);
// Gradient color from green → cyan → blue → magenta
Color col;
switch (i)
{
case 0:
col = Color.Green;
break;
case 1:
col = Color.Orange;
break;
case 2:
col = Color.Blue;
break;
case 3:
col = Color.Magenta;
break;
default:
col = Color.White;
break;
}
DrawLineEx(center, end, 5.0f, col);
// Draw angle label slightly offset along the line
Vector2 textPos = new Vector2(center.X + MathF.Cos(rad) * (lineLength + 20),
center.Y + MathF.Sin(rad) * (lineLength + 20));
DrawText($"{angles[i]}°", (int)textPos.X, (int)textPos.Y, 20, col);
}
// Draw animated rotating line with changing color
float animRad = totalAngle * DEG2RAD;
Vector2 animEnd = new Vector2(center.X + MathF.Cos(animRad) * lineLength,
center.Y + MathF.Sin(animRad) * lineLength);
// Cycle through HSV colors for animated line
Color animCol = ColorFromHSV(totalAngle % 360.0f, 0.8f, 0.9f);
DrawLineEx(center, animEnd, 5.0f, animCol);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - math angle rotation");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new MathAngleRotation();
game.Init();
// Main game loop
while (!WindowShouldClose())
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,215 @@
/*******************************************************************************************
*
* raylib [shapes] example - math sine cosine
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.0
*
* Example contributed by Jopestpe (@jopestpe) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Jopestpe (@jopestpe)
*
********************************************************************************************/
using static Raylib_cs.Raymath;
namespace Examples.Shapes;
public partial class MathSineCosine : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
// Wave points for sine/cosine visualization
private const int WAVE_POINTS = 36;
public string Name => "Shapes / Math Sine Cosine";
public string Title => "raylib [shapes] example - math sine cosine";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
private Vector2[] sinePoints;
private Vector2[] cosPoints;
private Vector2 center;
private Rectangle start;
private float radius;
private float angle;
private bool pause;
public void Init()
{
sinePoints = new Vector2[WAVE_POINTS];
cosPoints = new Vector2[WAVE_POINTS];
center = new((screenWidth / 2.0f) - 30.0f, screenHeight / 2.0f);
start = new(20.0f, screenHeight - 120.0f, 200.0f, 100.0f);
radius = 130.0f;
angle = 0.0f;
pause = false;
for (int i = 0; i < WAVE_POINTS; i++)
{
float t = i / (float)(WAVE_POINTS - 1);
float currentAngle = t * 360.0f * DEG2RAD;
sinePoints[i] = new(start.X + t * start.Width, start.Y + start.Height / 2.0f - MathF.Sin(currentAngle) * (start.Height / 2.0f));
cosPoints[i] = new(start.X + t * start.Width, start.Y + start.Height / 2.0f - MathF.Cos(currentAngle) * (start.Height / 2.0f));
}
}
public unsafe void Update()
{
// Update
//----------------------------------------------------------------------------------
float angleRad = angle * DEG2RAD;
float cosRad = MathF.Cos(angleRad);
float sinRad = MathF.Sin(angleRad);
Vector2 point = new(center.X + cosRad * radius, center.Y - sinRad * radius);
Vector2 limitMin = new(center.X - radius, center.Y - radius);
Vector2 limitMax = new(center.X + radius, center.Y + radius);
float complementary = 90.0f - angle;
float supplementary = 180.0f - angle;
float explementary = 360.0f - angle;
float tangent = Clamp(MathF.Tan(angleRad), -10.0f, 10.0f);
float cotangent = (MathF.Abs(tangent) > 0.001f) ? Clamp(1.0f / tangent, -radius, radius) : 0.0f;
Vector2 tangentPoint = new(center.X + radius, center.Y - tangent * radius);
Vector2 cotangentPoint = new(center.X + cotangent * radius, center.Y - radius);
angle = Wrap(angle + (!pause ? 1.0f : 0.0f), 0.0f, 360.0f);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Cotangent (orange)
DrawLineEx(new Vector2(center.X, limitMin.Y), new Vector2(cotangentPoint.X, limitMin.Y), 2.0f, Color.Orange);
DrawLineDashed(center, cotangentPoint, 10, 4, Color.Orange);
// Side background
DrawLine(580, 0, 580, GetScreenHeight(), new Color(218, 218, 218, 255));
DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), new Color(232, 232, 232, 255));
// Base circle and axes
DrawCircleLinesV(center, radius, Color.Gray);
DrawLineEx(new Vector2(center.X, limitMin.Y), new Vector2(center.X, limitMax.Y), 1.0f, Color.Gray);
DrawLineEx(new Vector2(limitMin.X, center.Y), new Vector2(limitMax.X, center.Y), 1.0f, Color.Gray);
// Wave graph axes
DrawLineEx(new Vector2(start.X, start.Y), new Vector2(start.X, start.Y + start.Height), 2.0f, Color.Gray);
DrawLineEx(new Vector2(start.X + start.Width, start.Y), new Vector2(start.X + start.Width, start.Y + start.Height), 2.0f, Color.Gray);
DrawLineEx(new Vector2(start.X, start.Y + start.Height / 2), new Vector2(start.X + start.Width, start.Y + start.Height / 2), 2.0f, Color.Gray);
// Wave graph axis labels
DrawText("1", (int)start.X - 8, (int)start.Y, 6, Color.Gray);
DrawText("0", (int)start.X - 8, (int)start.Y + (int)start.Height / 2 - 6, 6, Color.Gray);
DrawText("-1", (int)start.X - 12, (int)start.Y + (int)start.Height - 8, 6, Color.Gray);
DrawText("0", (int)start.X - 2, (int)start.Y + (int)start.Height + 4, 6, Color.Gray);
DrawText("360", (int)start.X + (int)start.Width - 8, (int)start.Y + (int)start.Height + 4, 6, Color.Gray);
// Sine (red - vertical)
DrawLineEx(new Vector2(center.X, center.Y), new Vector2(center.X, point.Y), 2.0f, Color.Red);
DrawLineDashed(new Vector2(point.X, center.Y), new Vector2(point.X, point.Y), 10, 4, Color.Red);
DrawText($"Sine {sinRad:0.00}", 640, 190, 6, Color.Red);
DrawCircleV(new Vector2(start.X + (angle / 360.0f) * start.Width, start.Y + ((-sinRad + 1) * start.Height / 2.0f)), 4.0f, Color.Red);
fixed (Vector2* p = sinePoints)
{
DrawSplineLinear(p, WAVE_POINTS, 1.0f, Color.Red);
}
// Cosine (blue - horizontal)
DrawLineEx(new Vector2(center.X, center.Y), new Vector2(point.X, center.Y), 2.0f, Color.Blue);
DrawLineDashed(new Vector2(center.X, point.Y), new Vector2(point.X, point.Y), 10, 4, Color.Blue);
DrawText($"Cosine {cosRad:0.00}", 640, 210, 6, Color.Blue);
DrawCircleV(new Vector2(start.X + (angle / 360.0f) * start.Width, start.Y + ((-cosRad + 1) * start.Height / 2.0f)), 4.0f, Color.Blue);
fixed (Vector2* p = cosPoints)
{
DrawSplineLinear(p, WAVE_POINTS, 1.0f, Color.Blue);
}
// Tangent (purple)
DrawLineEx(new Vector2(limitMax.X, center.Y), new Vector2(limitMax.X, tangentPoint.Y), 2.0f, Color.Purple);
DrawLineDashed(center, tangentPoint, 10, 4, Color.Purple);
DrawText($"Tangent {tangent:0.00}", 640, 230, 6, Color.Purple);
// Cotangent (orange)
DrawText($"Cotangent {cotangent:0.00}", 640, 250, 6, Color.Orange);
// Complementary angle (beige)
DrawCircleSectorLines(center, radius * 0.6f, -angle, -90.0f, 36, Color.Beige);
DrawText($"Complementary {complementary:0}°", 640, 150, 6, Color.Beige);
// Supplementary angle (darkblue)
DrawCircleSectorLines(center, radius * 0.5f, -angle, -180.0f, 36, Color.DarkBlue);
DrawText($"Supplementary {supplementary:0}°", 640, 130, 6, Color.DarkBlue);
// Explementary angle (pink)
DrawCircleSectorLines(center, radius * 0.4f, -angle, -360.0f, 36, Color.Pink);
DrawText($"Explementary {explementary:0}°", 640, 170, 6, Color.Pink);
// Current angle - arc (lime), radius (black), endpoint (black)
DrawCircleSectorLines(center, radius * 0.7f, -angle, 0.0f, 36, Color.Lime);
DrawLineEx(new Vector2(center.X, center.Y), point, 2.0f, Color.Black);
DrawCircleV(point, 4.0f, Color.Black);
// Draw GUI controls
// NOTE: raygui is not bound in raylib-cs, so the Pause toggle and Angle slider
// are unavailable; the angle animates continuously.
//------------------------------------------------------------------------------
/*
GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(GRAY));
GuiToggle((Rectangle){ 640, 70, 120, 20}, TextFormat("Pause"), &pause);
GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(LIME));
GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f°", angle), &angle, 0.0f, 360.0f);
// Angle values panel
GuiGroupBox((Rectangle){ 620, 110, 140, 170}, "Angle Values");
*/
//------------------------------------------------------------------------------
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - math sine cosine");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new MathSineCosine();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,124 @@
/*******************************************************************************************
*
* raylib [shapes] example - Draw a mouse trail (position history)
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 5.6
*
* Example contributed by Balamurugan R (@Bala050814]) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Balamurugan R (@Bala050814)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class MouseTrail : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
// Define the maximum number of positions to store in the trail
private const int MAX_TRAIL_LENGTH = 30;
public string Name => "Shapes / Mouse Trail";
public string Title => "raylib [shapes] example - mouse trail";
// Array to store the history of mouse positions (our fixed-size queue)
private Vector2[] trailPositions;
public void Init()
{
// Array to store the history of mouse positions (our fixed-size queue)
trailPositions = new Vector2[MAX_TRAIL_LENGTH];
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
Vector2 mousePosition = GetMousePosition();
// Shift all existing positions backward by one slot in the array
// The last element (the oldest position) is dropped
for (int i = MAX_TRAIL_LENGTH - 1; i > 0; i--)
{
trailPositions[i] = trailPositions[i - 1];
}
// Store the new, current mouse position at the start of the array (Index 0)
trailPositions[0] = mousePosition;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.Black);
// Draw the trail by looping through the history array
for (int i = 0; i < MAX_TRAIL_LENGTH; i++)
{
// Ensure we skip drawing if the array hasn't been fully filled on startup
if ((trailPositions[i].X != 0.0f) || (trailPositions[i].Y != 0.0f))
{
// Calculate relative trail strength (ratio is near 1.0 for new, near 0.0 for old)
float ratio = (float)(MAX_TRAIL_LENGTH - i) / MAX_TRAIL_LENGTH;
// Fade effect: oldest positions are more transparent
// Fade (color, alpha) - alpha is 0.5 to 1.0 based on ratio
Color trailColor = Fade(Color.SkyBlue, ratio * 0.5f + 0.5f);
// Size effect: oldest positions are smaller
float trailRadius = 15.0f * ratio;
DrawCircleV(trailPositions[i], trailRadius, trailColor);
}
}
// Draw a distinct white circle for the current mouse position (Index 0)
DrawCircleV(mousePosition, 15.0f, Color.White);
DrawText("Move the mouse to see the trail effect!", 10, screenHeight - 30, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - mouse trail");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new MouseTrail();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,327 @@
/*******************************************************************************************
*
* raylib [shapes] example - penrose tile
*
* Example complexity rating: [] 4/4
*
* Example originally created with raylib 5.5, last time updated with raylib 6.0
* Based on: https://processing.org/examples/penrosetile.html
*
* Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 David Buzatto (@davidbuzatto)
*
********************************************************************************************/
using System.Text;
namespace Examples.Shapes;
public partial class PenroseTile : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Penrose Tile";
public string Title => "raylib [shapes] example - penrose tile";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
public int TargetFps => 120;
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
private struct TurtleState
{
public Vector2 origin;
public float angle;
}
private class PenroseLSystem
{
public int steps;
public StringBuilder production;
public string ruleW;
public string ruleX;
public string ruleY;
public string ruleZ;
public float drawLength;
public float theta;
}
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
private Stack<TurtleState> turtleStack;
private const float drawLength = 460.0f;
private int minGenerations;
private int maxGenerations;
private int generations;
private PenroseLSystem ls;
public void Init()
{
turtleStack = new Stack<TurtleState>();
minGenerations = 0;
maxGenerations = 4;
generations = 0;
// Initialize new penrose tile
ls = CreatePenroseLSystem(drawLength * (generations / (float)maxGenerations));
for (int i = 0; i < generations; i++)
{
BuildProductionStep(ls);
}
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
bool rebuild = false;
if (IsKeyPressed(KeyboardKey.Up))
{
if (generations < maxGenerations)
{
generations++;
rebuild = true;
}
}
else if (IsKeyPressed(KeyboardKey.Down))
{
if (generations > minGenerations)
{
generations--;
if (generations > 0)
{
rebuild = true;
}
}
}
if (rebuild)
{
ls = CreatePenroseLSystem(drawLength * (generations / (float)maxGenerations));
for (int i = 0; i < generations; i++)
{
BuildProductionStep(ls);
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (generations > 0)
{
DrawPenroseLSystem(ls);
}
DrawText("penrose l-system", 10, 10, 20, Color.DarkGray);
DrawText("press up or down to change generations", 10, 30, 20, Color.DarkGray);
DrawText($"generations: {generations}", 10, 50, 20, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Push turtle state for next step
private void PushTurtleState(TurtleState state)
{
turtleStack.Push(state);
}
// Pop turtle state step
private TurtleState PopTurtleState()
{
if (turtleStack.Count > 0)
{
return turtleStack.Pop();
}
else
{
TraceLog(TraceLogLevel.Warning, "TURTLE STACK UNDERFLOW!");
}
return new TurtleState();
}
// Create a new penrose tile structure
private static PenroseLSystem CreatePenroseLSystem(float drawLength)
{
PenroseLSystem ls = new PenroseLSystem
{
steps = 0,
ruleW = "YF++ZF4-XF[-YF4-WF]++",
ruleX = "+YF--ZF[3-WF--XF]+",
ruleY = "-WF++XF[+++YF++ZF]-",
ruleZ = "--YF++++WF[+ZF++++XF]--XF",
drawLength = drawLength,
theta = 36.0f // Degrees
};
ls.production = new StringBuilder("[X]++[X]++[X]++[X]++[X]");
return ls;
}
// Build next penrose step
private static void BuildProductionStep(PenroseLSystem ls)
{
StringBuilder newProduction = new StringBuilder();
string production = ls.production.ToString();
for (int i = 0; i < production.Length; i++)
{
char step = production[i];
switch (step)
{
case 'W':
newProduction.Append(ls.ruleW);
break;
case 'X':
newProduction.Append(ls.ruleX);
break;
case 'Y':
newProduction.Append(ls.ruleY);
break;
case 'Z':
newProduction.Append(ls.ruleZ);
break;
default:
{
if (step != 'F')
{
newProduction.Append(step);
}
}
break;
}
}
ls.drawLength *= 0.5f;
ls.production = newProduction;
}
// Draw penrose tile lines
private void DrawPenroseLSystem(PenroseLSystem ls)
{
Vector2 screenCenter = new Vector2(GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f);
TurtleState turtle = new TurtleState
{
origin = new Vector2(0, 0),
angle = -90.0f
};
int repeats = 1;
string production = ls.production.ToString();
int productionLength = production.Length;
ls.steps += 12;
if (ls.steps > productionLength)
{
ls.steps = productionLength;
}
for (int i = 0; i < ls.steps; i++)
{
char step = production[i];
if (step == 'F')
{
for (int j = 0; j < repeats; j++)
{
Vector2 startPosWorld = turtle.origin;
float radAngle = DEG2RAD * turtle.angle;
turtle.origin.X += ls.drawLength * MathF.Cos(radAngle);
turtle.origin.Y += ls.drawLength * MathF.Sin(radAngle);
Vector2 startPosScreen = new Vector2(startPosWorld.X + screenCenter.X, startPosWorld.Y + screenCenter.Y);
Vector2 endPosScreen = new Vector2(turtle.origin.X + screenCenter.X, turtle.origin.Y + screenCenter.Y);
DrawLineEx(startPosScreen, endPosScreen, 2, Fade(Color.Black, 0.2f));
}
repeats = 1;
}
else if (step == '+')
{
for (int j = 0; j < repeats; j++)
{
turtle.angle += ls.theta;
}
repeats = 1;
}
else if (step == '-')
{
for (int j = 0; j < repeats; j++)
{
turtle.angle += -ls.theta;
}
repeats = 1;
}
else if (step == '[')
{
PushTurtleState(turtle);
}
else if (step == ']')
{
turtle = PopTurtleState();
}
else if ((step >= 48) && (step <= 57))
{
repeats = (int)step - 48;
}
}
turtleStack.Clear();
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - penrose tile");
SetTargetFPS(120); // Set our game to run at 120 frames-per-second
//---------------------------------------------------------------------------------------
var game = new PenroseTile();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

462
Examples/Shapes/PieChart.cs Normal file
View file

@ -0,0 +1,462 @@
/*******************************************************************************************
*
* raylib [shapes] example - pie chart
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.6
*
* Example contributed by Gideon Serfontein (@GideonSerf) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Gideon Serfontein (@GideonSerf)
*
********************************************************************************************/
using System.Text;
namespace Examples.Shapes;
public partial class PieChart : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int MAX_PIE_SLICES = 10; // Max pie slices
public string Name => "Shapes / Pie Chart";
public string Title => "raylib [shapes] example - pie chart";
private int sliceCount;
private float donutInnerRadius;
private float[] values;
private StringBuilder[] labels;
private bool[] editingLabel;
private bool showValues;
private bool showPercentages;
private bool showDonut;
private int hoveredSlice;
private Vector2 scrollContentOffset;
// UI layout parameters
private const int panelWidth = 270;
private const int panelMargin = 5;
private Vector2 panelPos;
private Rectangle panelRect;
private Rectangle canvas;
private Vector2 center;
private const float radius = 205.0f;
// Total value for percentage calculations
private float totalValue;
private int framesCounter;
// Minimal raygui-like global state
private static bool guiDisabled;
public void Init()
{
sliceCount = 7;
donutInnerRadius = 25.0f;
values = new float[MAX_PIE_SLICES] { 300.0f, 100.0f, 450.0f, 350.0f, 600.0f, 380.0f, 750.0f, 0.0f, 0.0f, 0.0f };
labels = new StringBuilder[MAX_PIE_SLICES];
editingLabel = new bool[MAX_PIE_SLICES];
for (int i = 0; i < MAX_PIE_SLICES; i++)
{
labels[i] = new StringBuilder($"Slice {i + 1:D2}");
}
showValues = true;
showPercentages = false;
showDonut = false;
hoveredSlice = -1;
scrollContentOffset = new Vector2(0, 0);
// UI Panel top-left anchor
panelPos = new Vector2(
(float)screenWidth - panelMargin - panelWidth,
(float)panelMargin
);
// UI Panel rectangle
panelRect = new Rectangle(
panelPos.X, panelPos.Y,
(float)panelWidth,
(float)screenHeight - 2.0f * panelMargin
);
// Pie chart geometry
canvas = new Rectangle(0, 0, panelPos.X, (float)screenHeight);
center = new Vector2(canvas.Width / 2.0f, canvas.Height / 2.0f);
totalValue = 0.0f;
framesCounter = 0;
guiDisabled = false;
}
public void Update()
{
framesCounter++;
// Update
//----------------------------------------------------------------------------------
// Calculate total value for percentage calculations
totalValue = 0.0f;
for (int i = 0; i < sliceCount; i++)
{
totalValue += values[i];
}
// Check for mouse hover over slices
hoveredSlice = -1; // Reset hovered slice
Vector2 mousePos = GetMousePosition();
if (CheckCollisionPointRec(mousePos, canvas)) // Only check if mouse is inside the canvas
{
float dx = mousePos.X - center.X;
float dy = mousePos.Y - center.Y;
float distance = MathF.Sqrt(dx * dx + dy * dy);
if (distance <= radius) // Inside the pie radius
{
float angle = MathF.Atan2(dy, dx) * RAD2DEG;
if (angle < 0)
{
angle += 360;
}
float currentAngle = 0.0f;
for (int i = 0; i < sliceCount; i++)
{
float sweep = (totalValue > 0) ? (values[i] / totalValue) * 360.0f : 0.0f;
if ((angle >= currentAngle) && (angle < (currentAngle + sweep)))
{
hoveredSlice = i;
break;
}
currentAngle += sweep;
}
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw the pie chart on the canvas
float startAngle = 0.0f;
for (int i = 0; i < sliceCount; i++)
{
float sweepAngle = (totalValue > 0) ? (values[i] / totalValue) * 360.0f : 0.0f;
float midAngle = startAngle + sweepAngle / 2.0f; // Middle angle for label positioning
Color color = ColorFromHSV((float)i / sliceCount * 360.0f, 0.75f, 0.9f);
float currentRadius = radius;
// Make the hovered slice pop out by adding pixels to its radius
if (i == hoveredSlice)
{
currentRadius += 20.0f;
}
// Draw the pie slice using raylib's DrawCircleSector function
DrawCircleSector(center, currentRadius, startAngle, startAngle + sweepAngle, 120, color);
// Draw the label for the current slice
if (values[i] > 0)
{
string labelText;
if (showValues && showPercentages)
{
labelText = $"{values[i]:F1} ({(values[i] / totalValue) * 100.0f:F0}%)";
}
else if (showValues)
{
labelText = $"{values[i]:F1}";
}
else if (showPercentages)
{
labelText = $"{(values[i] / totalValue) * 100.0f:F0}%";
}
else
{
labelText = "";
}
Vector2 textSize = MeasureTextEx(GetFontDefault(), labelText, 20, 1);
float labelRadius = radius * 0.7f;
Vector2 labelPos = new Vector2(center.X + MathF.Cos(midAngle * DEG2RAD) * labelRadius - textSize.X / 2.0f,
center.Y + MathF.Sin(midAngle * DEG2RAD) * labelRadius - textSize.Y / 2.0f);
DrawText(labelText, (int)labelPos.X, (int)labelPos.Y, 20, Color.White);
}
// Draw inner circle to create donut effect
// TODO: This is a hacky solution, better use DrawRing()
if (showDonut)
{
DrawCircleV(center, donutInnerRadius, Color.RayWhite);
}
startAngle += sweepAngle;
}
// UI control panel (minimal raygui-like controls, raygui is not bound in raylib-cs)
DrawRectangleRec(panelRect, Fade(Color.LightGray, 0.5f));
DrawRectangleLinesEx(panelRect, 1.0f, Color.Gray);
GuiSpinner(new Rectangle(panelPos.X + 95, (float)panelPos.Y + 12, 125, 25), "Slices ", ref sliceCount, 1, MAX_PIE_SLICES);
GuiCheckBox(new Rectangle(panelPos.X + 20, (float)panelPos.Y + 12 + 40, 20, 20), "Show Values", ref showValues);
GuiCheckBox(new Rectangle(panelPos.X + 20, (float)panelPos.Y + 12 + 70, 20, 20), "Show Percentages", ref showPercentages);
GuiCheckBox(new Rectangle(panelPos.X + 20, (float)panelPos.Y + 12 + 100, 20, 20), "Make Donut", ref showDonut);
if (showDonut)
{
GuiDisable();
}
GuiSliderBar(new Rectangle(panelPos.X + 80, (float)panelPos.Y + 12 + 130, panelRect.Width - 100, 30),
"Inner Radius", null, ref donutInnerRadius, 5.0f, radius - 10.0f);
GuiEnable();
GuiLine(new Rectangle(panelPos.X + 10, (float)panelPos.Y + 12 + 170, panelRect.Width - 20, 1));
// Scrollable area for slice editors
float scrollTop = (float)panelPos.Y + 12 + 190;
Rectangle scrollPanelBounds = new Rectangle(
panelPos.X + panelMargin,
scrollTop,
panelRect.Width - panelMargin * 2,
(panelRect.Y + panelRect.Height) - scrollTop - panelMargin);
int contentHeight = sliceCount * 35;
// Simple vertical scroll via mouse wheel while hovering the panel
if (CheckCollisionPointRec(GetMousePosition(), scrollPanelBounds))
{
scrollContentOffset.Y += GetMouseWheelMove() * 20.0f;
float minOffset = MathF.Min(0.0f, scrollPanelBounds.Height - contentHeight);
if (scrollContentOffset.Y < minOffset)
{
scrollContentOffset.Y = minOffset;
}
if (scrollContentOffset.Y > 0.0f)
{
scrollContentOffset.Y = 0.0f;
}
}
Rectangle view = scrollPanelBounds;
float contentX = view.X + scrollContentOffset.X; // Left of content
float contentY = view.Y + scrollContentOffset.Y; // Top of content
BeginScissorMode((int)view.X, (int)view.Y, (int)view.Width, (int)view.Height);
for (int i = 0; i < sliceCount; i++)
{
int rowY = (int)(contentY + 5 + i * 35);
// Color indicator
Color color = ColorFromHSV((float)i / sliceCount * 360.0f, 0.75f, 0.9f);
DrawRectangle((int)(contentX + 15), rowY + 5, 20, 20, color);
// Label textbox
if (GuiTextBox(new Rectangle(contentX + 45, (float)rowY, 75, 30), labels[i], 32, editingLabel[i]))
{
editingLabel[i] = !editingLabel[i];
}
GuiSliderBar(new Rectangle(contentX + 130, (float)rowY, 110, 30), null, null, ref values[i], 0.0f, 1000.0f);
}
EndScissorMode();
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Minimal raygui-like widgets (plain raylib re-implementation)
//----------------------------------------------------------------------------------
private static void GuiDisable() => guiDisabled = true;
private static void GuiEnable() => guiDisabled = false;
private static void GuiLine(Rectangle bounds)
{
int y = (int)(bounds.Y + bounds.Height / 2);
DrawLine((int)bounds.X, y, (int)(bounds.X + bounds.Width), y, Color.Gray);
}
private static void GuiCheckBox(Rectangle bounds, string text, ref bool active)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (!guiDisabled && hover && IsMouseButtonPressed(MouseButton.Left))
{
active = !active;
}
DrawRectangleLinesEx(bounds, 1, hover ? Color.DarkBlue : Color.Gray);
if (active)
{
DrawRectangle((int)bounds.X + 4, (int)bounds.Y + 4, (int)bounds.Width - 8, (int)bounds.Height - 8, Color.DarkGray);
}
if (text != null)
{
DrawText(text, (int)(bounds.X + bounds.Width + 8), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
private static void GuiSpinner(Rectangle bounds, string text, ref int value, int minValue, int maxValue)
{
Vector2 mouse = GetMousePosition();
Rectangle left = new Rectangle(bounds.X, bounds.Y, bounds.Height, bounds.Height);
Rectangle right = new Rectangle(bounds.X + bounds.Width - bounds.Height, bounds.Y, bounds.Height, bounds.Height);
Rectangle mid = new Rectangle(bounds.X + bounds.Height, bounds.Y, bounds.Width - 2 * bounds.Height, bounds.Height);
if (!guiDisabled && CheckCollisionPointRec(mouse, left) && IsMouseButtonPressed(MouseButton.Left) && value > minValue)
{
value--;
}
if (!guiDisabled && CheckCollisionPointRec(mouse, right) && IsMouseButtonPressed(MouseButton.Left) && value < maxValue)
{
value++;
}
DrawRectangleRec(mid, Color.RayWhite);
DrawRectangleLinesEx(mid, 1, Color.Gray);
DrawRectangleRec(left, Color.LightGray);
DrawRectangleLinesEx(left, 1, Color.Gray);
DrawRectangleRec(right, Color.LightGray);
DrawRectangleLinesEx(right, 1, Color.Gray);
DrawText("-", (int)(left.X + left.Width / 2 - 2), (int)(left.Y + left.Height / 2 - 5), 10, Color.DarkGray);
DrawText("+", (int)(right.X + right.Width / 2 - 3), (int)(right.Y + right.Height / 2 - 5), 10, Color.DarkGray);
string vs = value.ToString();
DrawText(vs, (int)(mid.X + mid.Width / 2 - MeasureText(vs, 10) / 2), (int)(mid.Y + mid.Height / 2 - 5), 10, Color.DarkGray);
if (text != null)
{
DrawText(text, (int)bounds.X - MeasureText(text, 10) - 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
private static void GuiSliderBar(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (!guiDisabled && hover && IsMouseButtonDown(MouseButton.Left))
{
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
if (value < minValue)
{
value = minValue;
}
if (value > maxValue)
{
value = maxValue;
}
}
DrawRectangleRec(bounds, guiDisabled ? Color.Gray : Color.LightGray);
float pct = (value - minValue) / (maxValue - minValue);
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), guiDisabled ? Color.DarkGray : Color.SkyBlue);
DrawRectangleLinesEx(bounds, 1, Color.Gray);
if (!string.IsNullOrEmpty(textLeft))
{
DrawText(textLeft, (int)bounds.X - MeasureText(textLeft, 10) - 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
if (!string.IsNullOrEmpty(textRight))
{
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
private bool GuiTextBox(Rectangle bounds, StringBuilder text, int maxChars, bool editMode)
{
bool pressed = false;
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (editMode)
{
int key = GetCharPressed();
while (key > 0)
{
if ((key >= 32) && (key <= 125) && (text.Length < maxChars - 1))
{
text.Append((char)key);
}
key = GetCharPressed();
}
if (IsKeyPressed(KeyboardKey.Backspace) && (text.Length > 0))
{
text.Remove(text.Length - 1, 1);
}
}
DrawRectangleRec(bounds, Color.RayWhite);
DrawRectangleLinesEx(bounds, editMode ? 2 : 1, editMode ? Color.Red : (hover ? Color.Blue : Color.Gray));
string content = text.ToString();
DrawText(content, (int)bounds.X + 4, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
if (editMode && ((framesCounter / 20) % 2 == 0))
{
DrawText("_", (int)bounds.X + 4 + MeasureText(content, 10), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
if (hover && IsMouseButtonPressed(MouseButton.Left))
{
pressed = true;
}
return pressed;
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - pie chart");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new PieChart();
game.Init();
// Main game loop
while (!WindowShouldClose())
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,282 @@
/*******************************************************************************************
*
* raylib [shapes] example - rectangle advanced
*
* Example complexity rating: [] 4/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
* Example contributed by Everton Jr. (@evertonse) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2024-2025 Everton Jr. (@evertonse) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Rlgl;
namespace Examples.Shapes;
public partial class RectangleAdvanced : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Rectangle Advanced";
public string Title => "raylib [shapes] example - rectangle advanced";
public void Init()
{
}
public void Update()
{
// Update rectangle bounds
//----------------------------------------------------------------------------------
float width = GetScreenWidth() / 2.0f, height = GetScreenHeight() / 6.0f;
Rectangle rec = new Rectangle(
GetScreenWidth() / 2.0f - width / 2,
GetScreenHeight() / 2.0f - 5 * (height / 2),
width, height
);
//--------------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw All Rectangles with different roundess for each side and different gradients
DrawRectangleRoundedGradientH(rec, 0.8f, 0.8f, 36, Color.Blue, Color.Red);
rec.Y += rec.Height + 1;
DrawRectangleRoundedGradientH(rec, 0.5f, 1.0f, 36, Color.Red, Color.Pink);
rec.Y += rec.Height + 1;
DrawRectangleRoundedGradientH(rec, 1.0f, 0.5f, 36, Color.Red, Color.Blue);
rec.Y += rec.Height + 1;
DrawRectangleRoundedGradientH(rec, 0.0f, 1.0f, 36, Color.Blue, Color.Black);
rec.Y += rec.Height + 1;
DrawRectangleRoundedGradientH(rec, 1.0f, 0.0f, 36, Color.Blue, Color.Pink);
EndDrawing();
//--------------------------------------------------------------------------------------
}
public void Unload()
{
}
//--------------------------------------------------------------------------------------
// Module Functions Definition
//--------------------------------------------------------------------------------------
// Draw rectangle with rounded edges and horizontal gradient, with options to choose side of roundness
// NOTE: Adapted from both 'DrawRectangleRounded()' and 'DrawRectangleGradientH()' raylib [rshapes] implementations
private static void DrawRectangleRoundedGradientH(Rectangle rec, float roundnessLeft, float roundnessRight, int segments, Color left, Color right)
{
// Neither side is rounded
if ((roundnessLeft <= 0.0f && roundnessRight <= 0.0f) || (rec.Width < 1) || (rec.Height < 1))
{
DrawRectangleGradientEx(rec, left, left, right, right);
return;
}
if (roundnessLeft >= 1.0f)
{
roundnessLeft = 1.0f;
}
if (roundnessRight >= 1.0f)
{
roundnessRight = 1.0f;
}
// Calculate corner radius both from right and left
float recSize = rec.Width > rec.Height ? rec.Height : rec.Width;
float radiusLeft = (recSize * roundnessLeft) / 2;
float radiusRight = (recSize * roundnessRight) / 2;
if (radiusLeft <= 0.0f)
{
radiusLeft = 0.0f;
}
if (radiusRight <= 0.0f)
{
radiusRight = 0.0f;
}
if (radiusRight <= 0.0f && radiusLeft <= 0.0f)
{
return;
}
float stepLength = 90.0f / (float)segments;
/*
Diagram Copied here for reference, original at 'DrawRectangleRounded()' source code
P0____________________P1
/| |\
/1| 2 |3\
P7 /__|____________________|__\ P2
| |P8 P9| |
| 8 | 9 | 4 |
| __|____________________|__ |
P6 \ |P11 P10| / P3
\7| 6 |5/
\|____________________|/
P5 P4
*/
// Coordinates of the 12 points also adapted from `DrawRectangleRounded`
Vector2[] point = new Vector2[12]
{
// PO, P1, P2
new Vector2(rec.X + radiusLeft, rec.Y), new Vector2((rec.X + rec.Width) - radiusRight, rec.Y), new Vector2(rec.X + rec.Width, rec.Y + radiusRight),
// P3, P4
new Vector2(rec.X + rec.Width, (rec.Y + rec.Height) - radiusRight), new Vector2((rec.X + rec.Width) - radiusRight, rec.Y + rec.Height),
// P5, P6, P7
new Vector2(rec.X + radiusLeft, rec.Y + rec.Height), new Vector2(rec.X, (rec.Y + rec.Height) - radiusLeft), new Vector2(rec.X, rec.Y + radiusLeft),
// P8, P9
new Vector2(rec.X + radiusLeft, rec.Y + radiusLeft), new Vector2((rec.X + rec.Width) - radiusRight, rec.Y + radiusRight),
// P10, P11
new Vector2((rec.X + rec.Width) - radiusRight, (rec.Y + rec.Height) - radiusRight), new Vector2(rec.X + radiusLeft, (rec.Y + rec.Height) - radiusLeft)
};
Vector2[] centers = new Vector2[4] { point[8], point[9], point[10], point[11] };
float[] angles = new float[4] { 180.0f, 270.0f, 0.0f, 90.0f };
// Here we use the 'Diagram' to guide ourselves to which point receives what color
// By choosing the color correctly associated with a point the gradient effect
// will naturally come from OpenGL interpolation
// But this time instead of Quad, we think in triangles
Begin(DrawMode.Triangles);
// Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
for (int k = 0; k < 4; ++k)
{
Color color = new Color(0, 0, 0, 0);
float radius = 0.0f;
if (k == 0)
{
color = left;
radius = radiusLeft;
} // [1] Upper Left Corner
if (k == 1)
{
color = right;
radius = radiusRight;
} // [3] Upper Right Corner
if (k == 2)
{
color = right;
radius = radiusRight;
} // [5] Lower Right Corner
if (k == 3)
{
color = left;
radius = radiusLeft;
} // [7] Lower Left Corner
float angle = angles[k];
Vector2 center = centers[k];
for (int i = 0; i < segments; i++)
{
Color4ub(color.R, color.G, color.B, color.A);
Vertex2f(center.X, center.Y);
Vertex2f(center.X + MathF.Cos(DEG2RAD * (angle + stepLength)) * radius, center.Y + MathF.Sin(DEG2RAD * (angle + stepLength)) * radius);
Vertex2f(center.X + MathF.Cos(DEG2RAD * angle) * radius, center.Y + MathF.Sin(DEG2RAD * angle) * radius);
angle += stepLength;
}
}
// [2] Upper Rectangle
Color4ub(left.R, left.G, left.B, left.A);
Vertex2f(point[0].X, point[0].Y);
Vertex2f(point[8].X, point[8].Y);
Color4ub(right.R, right.G, right.B, right.A);
Vertex2f(point[9].X, point[9].Y);
Vertex2f(point[1].X, point[1].Y);
Color4ub(left.R, left.G, left.B, left.A);
Vertex2f(point[0].X, point[0].Y);
Color4ub(right.R, right.G, right.B, right.A);
Vertex2f(point[9].X, point[9].Y);
// [4] Right Rectangle
Color4ub(right.R, right.G, right.B, right.A);
Vertex2f(point[9].X, point[9].Y);
Vertex2f(point[10].X, point[10].Y);
Vertex2f(point[3].X, point[3].Y);
Vertex2f(point[2].X, point[2].Y);
Vertex2f(point[9].X, point[9].Y);
Vertex2f(point[3].X, point[3].Y);
// [6] Bottom Rectangle
Color4ub(left.R, left.G, left.B, left.A);
Vertex2f(point[11].X, point[11].Y);
Vertex2f(point[5].X, point[5].Y);
Color4ub(right.R, right.G, right.B, right.A);
Vertex2f(point[4].X, point[4].Y);
Vertex2f(point[10].X, point[10].Y);
Color4ub(left.R, left.G, left.B, left.A);
Vertex2f(point[11].X, point[11].Y);
Color4ub(right.R, right.G, right.B, right.A);
Vertex2f(point[4].X, point[4].Y);
// [8] Left Rectangle
Color4ub(left.R, left.G, left.B, left.A);
Vertex2f(point[7].X, point[7].Y);
Vertex2f(point[6].X, point[6].Y);
Vertex2f(point[11].X, point[11].Y);
Vertex2f(point[8].X, point[8].Y);
Vertex2f(point[7].X, point[7].Y);
Vertex2f(point[11].X, point[11].Y);
// [9] Middle Rectangle
Color4ub(left.R, left.G, left.B, left.A);
Vertex2f(point[8].X, point[8].Y);
Vertex2f(point[11].X, point[11].Y);
Color4ub(right.R, right.G, right.B, right.A);
Vertex2f(point[10].X, point[10].Y);
Vertex2f(point[9].X, point[9].Y);
Color4ub(left.R, left.G, left.B, left.A);
Vertex2f(point[8].X, point[8].Y);
Color4ub(right.R, right.G, right.B, right.A);
Vertex2f(point[10].X, point[10].Y);
End();
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rectangle advanced");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new RectangleAdvanced();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,120 +1,161 @@
/*******************************************************************************************
*
* raylib [shapes] example - rectangle scaling by mouse
* raylib [shapes] example - rectangle scaling
*
* This example has been created using raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2018 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2018-2025 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Shapes;
public class RectangleScaling
public partial class RectangleScaling : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public const int MOUSE_SCALE_MARK_SIZE = 12;
public string Name => "Shapes / Rectangle Scaling";
public string Title => "raylib [shapes] example - rectangle scaling";
private Rectangle rec;
private Vector2 mousePosition;
private bool mouseScaleReady;
private bool mouseScaleMode;
public void Init()
{
rec = new(100, 100, 200, 80);
mousePosition = new(0, 0);
mouseScaleReady = false;
mouseScaleMode = false;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
mousePosition = GetMousePosition();
Rectangle area = new(
rec.X + rec.Width - MOUSE_SCALE_MARK_SIZE,
rec.Y + rec.Height - MOUSE_SCALE_MARK_SIZE,
MOUSE_SCALE_MARK_SIZE,
MOUSE_SCALE_MARK_SIZE
);
if (CheckCollisionPointRec(mousePosition, area))
{
mouseScaleReady = true;
if (IsMouseButtonPressed(MouseButton.Left))
{
mouseScaleMode = true;
}
}
else
{
mouseScaleReady = false;
}
if (mouseScaleMode)
{
mouseScaleReady = true;
rec.Width = (mousePosition.X - rec.X);
rec.Height = (mousePosition.Y - rec.Y);
// Check minimum rec size
if (rec.Width < MOUSE_SCALE_MARK_SIZE)
{
rec.Width = MOUSE_SCALE_MARK_SIZE;
}
if (rec.Height < MOUSE_SCALE_MARK_SIZE)
{
rec.Height = MOUSE_SCALE_MARK_SIZE;
}
// Check maximum rec size
if (rec.Width > (GetScreenWidth() - rec.X))
{
rec.Width = GetScreenWidth() - rec.X;
}
if (rec.Height > (GetScreenHeight() - rec.Y))
{
rec.Height = GetScreenHeight() - rec.Y;
}
if (IsMouseButtonReleased(MouseButton.Left))
{
mouseScaleMode = false;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("Scale rectangle dragging from bottom-right corner!", 10, 10, 20, Color.Gray);
DrawRectangleRec(rec, Fade(Color.Green, 0.5f));
if (mouseScaleReady)
{
DrawRectangleLinesEx(rec, 1, Color.Red);
DrawTriangle(
new Vector2(rec.X + rec.Width - MOUSE_SCALE_MARK_SIZE, rec.Y + rec.Height),
new Vector2(rec.X + rec.Width, rec.Y + rec.Height),
new Vector2(rec.X + rec.Width, rec.Y + rec.Height - MOUSE_SCALE_MARK_SIZE),
Color.Red
);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rectangle scaling");
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rectangle scaling mouse");
Rectangle rec = new(100, 100, 200, 80);
Vector2 mousePosition = new(0, 0);
bool mouseScaleReady = false;
bool mouseScaleMode = false;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new RectangleScaling();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
mousePosition = GetMousePosition();
Rectangle area = new(
rec.X + rec.Width - MOUSE_SCALE_MARK_SIZE,
rec.Y + rec.Height - MOUSE_SCALE_MARK_SIZE,
MOUSE_SCALE_MARK_SIZE,
MOUSE_SCALE_MARK_SIZE
);
if (CheckCollisionPointRec(mousePosition, rec) &&
CheckCollisionPointRec(mousePosition, area))
{
mouseScaleReady = true;
if (IsMouseButtonPressed(MouseButton.Left))
{
mouseScaleMode = true;
}
}
else
{
mouseScaleReady = false;
}
if (mouseScaleMode)
{
mouseScaleReady = true;
rec.Width = (mousePosition.X - rec.X);
rec.Height = (mousePosition.Y - rec.Y);
if (rec.Width < MOUSE_SCALE_MARK_SIZE)
{
rec.Width = MOUSE_SCALE_MARK_SIZE;
}
if (rec.Height < MOUSE_SCALE_MARK_SIZE)
{
rec.Height = MOUSE_SCALE_MARK_SIZE;
}
if (IsMouseButtonReleased(MouseButton.Left))
{
mouseScaleMode = false;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("Scale rectangle dragging from bottom-right corner!", 10, 10, 20, Color.Gray);
DrawRectangleRec(rec, ColorAlpha(Color.Green, 0.5f));
if (mouseScaleReady)
{
DrawRectangleLinesEx(rec, 1, Color.Red);
DrawTriangle(
new Vector2(rec.X + rec.Width - MOUSE_SCALE_MARK_SIZE, rec.Y + rec.Height),
new Vector2(rec.X + rec.Width, rec.Y + rec.Height),
new Vector2(rec.X + rec.Width, rec.Y + rec.Height - MOUSE_SCALE_MARK_SIZE),
Color.Red
);
}
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,228 @@
/*******************************************************************************************
*
* raylib [shapes] example - recursive tree
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.0
*
* Example contributed by Jopestpe (@jopestpe)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Jopestpe (@jopestpe)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class RecursiveTree : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Recursive Tree";
public string Title => "raylib [shapes] example - recursive tree";
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
private struct Branch
{
public Vector2 start;
public Vector2 end;
public float angle;
public float length;
}
private Vector2 start;
private float angle;
private float thick;
private float treeDepth;
private float branchDecay;
private float length;
private bool bezier;
private Branch[] branches;
public void Init()
{
start = new Vector2((screenWidth / 2.0f) - 125.0f, (float)screenHeight);
angle = 40.0f;
thick = 1.0f;
treeDepth = 10.0f;
branchDecay = 0.66f;
length = 120.0f;
bezier = false;
branches = new Branch[1030];
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
float theta = angle * DEG2RAD;
int maxBranches = (int)(MathF.Pow(2, MathF.Floor(treeDepth)));
int count = 0;
Vector2 initialEnd = new Vector2(start.X + length * MathF.Sin(0.0f), start.Y - length * MathF.Cos(0.0f));
branches[count++] = new Branch { start = start, end = initialEnd, angle = 0.0f, length = length };
for (int i = 0; i < count; i++)
{
Branch branch = branches[i];
if (branch.length < 2)
{
continue;
}
float nextLength = branch.length * branchDecay;
if (count < maxBranches && nextLength >= 2)
{
Vector2 branchStart = branch.end;
float angle1 = branch.angle + theta;
Vector2 branchEnd1 = new Vector2(branchStart.X + nextLength * MathF.Sin(angle1), branchStart.Y - nextLength * MathF.Cos(angle1));
branches[count++] = new Branch { start = branchStart, end = branchEnd1, angle = angle1, length = nextLength };
float angle2 = branch.angle - theta;
Vector2 branchEnd2 = new Vector2(branchStart.X + nextLength * MathF.Sin(angle2), branchStart.Y - nextLength * MathF.Cos(angle2));
branches[count++] = new Branch { start = branchStart, end = branchEnd2, angle = angle2, length = nextLength };
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
for (int i = 0; i < count; i++)
{
Branch branch = branches[i];
if (branch.length >= 2)
{
if (bezier)
{
DrawLineBezier(branch.start, branch.end, thick, Color.Red);
}
else
{
DrawLineEx(branch.start, branch.end, thick, Color.Red);
}
}
}
DrawLine(580, 0, 580, GetScreenHeight(), new Color(218, 218, 218, 255));
DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), new Color(232, 232, 232, 255));
// Draw GUI controls (minimal raygui-like controls, raygui is not bound in raylib-cs)
//------------------------------------------------------------------------------
GuiSliderBar(new Rectangle(640, 40, 120, 20), "Angle", $"{angle:F0}", ref angle, 0, 180);
GuiSliderBar(new Rectangle(640, 70, 120, 20), "Length", $"{length:F0}", ref length, 12.0f, 240.0f);
GuiSliderBar(new Rectangle(640, 100, 120, 20), "Decay", $"{branchDecay:F2}", ref branchDecay, 0.1f, 0.78f);
GuiSliderBar(new Rectangle(640, 130, 120, 20), "Depth", $"{treeDepth:F0}", ref treeDepth, 1.0f, 10.0f);
GuiSliderBar(new Rectangle(640, 160, 120, 20), "Thick", $"{thick:F0}", ref thick, 1, 8);
GuiCheckBox(new Rectangle(640, 190, 20, 20), "Bezier", ref bezier);
//------------------------------------------------------------------------------
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Minimal raygui-like widgets (plain raylib re-implementation)
//----------------------------------------------------------------------------------
private static void GuiSliderBar(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (hover && IsMouseButtonDown(MouseButton.Left))
{
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
if (value < minValue)
{
value = minValue;
}
if (value > maxValue)
{
value = maxValue;
}
}
DrawRectangleRec(bounds, Color.LightGray);
float pct = (value - minValue) / (maxValue - minValue);
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
DrawRectangleLinesEx(bounds, 1, Color.Gray);
if (textLeft != null)
{
DrawText(textLeft, (int)bounds.X - MeasureText(textLeft, 10) - 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
if (textRight != null)
{
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
private static void GuiCheckBox(Rectangle bounds, string text, ref bool active)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (hover && IsMouseButtonPressed(MouseButton.Left))
{
active = !active;
}
DrawRectangleLinesEx(bounds, 1, hover ? Color.DarkBlue : Color.Gray);
if (active)
{
DrawRectangle((int)bounds.X + 4, (int)bounds.Y + 4, (int)bounds.Width - 8, (int)bounds.Height - 8, Color.DarkGray);
}
if (text != null)
{
DrawText(text, (int)(bounds.X + bounds.Width + 8), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - recursive tree");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new RecursiveTree();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,363 @@
/*******************************************************************************************
*
* raylib [shapes] example - rlgl color wheel
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.0
*
* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Robin (@RobinsAviary)
*
********************************************************************************************/
using static Raylib_cs.Raymath;
using static Raylib_cs.Rlgl;
namespace Examples.Shapes;
public partial class RlglColorWheel : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / RLGL Color Wheel";
public string Title => "raylib [shapes] example - rlgl color wheel";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
// The minimum/maximum points the circle can have
private const int pointsMin = 3;
private const int pointsMax = 256;
// The current number of points and the radius of the circle
private int triangleCount;
private float pointScale;
// Slider value, literally maps to value in HSV
private float value;
// The center of the screen
private Vector2 center;
// The location of the color wheel
private Vector2 circlePosition;
// The currently selected color
private Color color;
// Indicates if the slider is being clicked
private bool sliderClicked;
// Indicates if the current color going to be updated, as well as the handle position
private bool settingColor;
// How the color wheel will be rendered
private DrawMode renderType;
public void Init()
{
triangleCount = 64;
pointScale = 150.0f;
value = 1.0f;
center = new Vector2((float)screenWidth / 2.0f, (float)screenHeight / 2.0f);
circlePosition = center;
color = new Color(255, 255, 255, 255);
sliderClicked = false;
settingColor = false;
renderType = DrawMode.Triangles;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
triangleCount += (int)GetMouseWheelMove();
triangleCount = (int)Clamp((float)triangleCount, (float)pointsMin, (float)pointsMax);
Rectangle sliderRectangle = new Rectangle(42.0f, 16.0f + 64.0f + 45.0f, 64.0f, 16.0f);
Vector2 mousePosition = GetMousePosition();
// Checks if the user is hovering over the value slider
bool sliderHover = (mousePosition.X >= sliderRectangle.X && mousePosition.Y >= sliderRectangle.Y && mousePosition.X < sliderRectangle.X + sliderRectangle.Width && mousePosition.Y < sliderRectangle.Y + sliderRectangle.Height);
// Copy color as hex
if (IsKeyDown(KeyboardKey.LeftControl) && IsKeyDown(KeyboardKey.C))
{
if (IsKeyPressed(KeyboardKey.C))
{
SetClipboardText($"#{color.R:X2}{color.G:X2}{color.B:X2}");
}
}
// Scale up the color wheel, adjusting the handle visually
if (IsKeyDown(KeyboardKey.Up))
{
pointScale *= 1.025f;
if (pointScale > (float)screenHeight / 2.0f)
{
pointScale = (float)screenHeight / 2.0f;
}
else
{
circlePosition = Vector2Add(Vector2Multiply(Vector2Subtract(circlePosition, center), new Vector2(1.025f, 1.025f)), center);
}
}
// Scale down the wheel, adjusting the handle visually
if (IsKeyDown(KeyboardKey.Down))
{
pointScale *= 0.975f;
if (pointScale < 32.0f)
{
pointScale = 32.0f;
}
else
{
circlePosition = Vector2Add(Vector2Multiply(Vector2Subtract(circlePosition, center), new Vector2(0.975f, 0.975f)), center);
}
float distanceDown = Vector2Distance(center, circlePosition) / pointScale;
float angleDown = ((Vector2Angle(new Vector2(0.0f, -pointScale), Vector2Subtract(center, circlePosition)) / MathF.PI + 1.0f) / 2.0f);
if (distanceDown > 1.0f)
{
circlePosition = Vector2Add(new Vector2(MathF.Sin(angleDown * (MathF.PI * 2.0f)) * pointScale, -MathF.Cos(angleDown * (MathF.PI * 2.0f)) * pointScale), center);
}
}
// Checks if the user clicked on the color wheel
if (IsMouseButtonPressed(MouseButton.Left) && Vector2Distance(GetMousePosition(), center) <= pointScale + 10.0f)
{
settingColor = true;
}
// Update flag when mouse button is released
if (IsMouseButtonReleased(MouseButton.Left))
{
settingColor = false;
}
// Check if the user clicked/released the slider for the color's value
if (sliderHover && IsMouseButtonPressed(MouseButton.Left))
{
sliderClicked = true;
}
if (sliderClicked && IsMouseButtonReleased(MouseButton.Left))
{
sliderClicked = false;
}
// Update render mode accordingly
if (IsKeyPressed(KeyboardKey.Space))
{
renderType = DrawMode.Lines;
}
if (IsKeyReleased(KeyboardKey.Space))
{
renderType = DrawMode.Triangles;
}
// If the slider or the wheel was clicked, update the current color
if (settingColor || sliderClicked)
{
if (settingColor)
{
circlePosition = GetMousePosition();
}
float distance = Vector2Distance(center, circlePosition) / pointScale;
float angle = ((Vector2Angle(new Vector2(0.0f, -pointScale), Vector2Subtract(center, circlePosition)) / MathF.PI + 1.0f) / 2.0f);
if (settingColor && distance > 1.0f)
{
circlePosition = Vector2Add(new Vector2(MathF.Sin(angle * (MathF.PI * 2.0f)) * pointScale, -MathF.Cos(angle * (MathF.PI * 2.0f)) * pointScale), center);
}
float angle360 = angle * 360.0f;
float valueActual = Clamp(distance, 0.0f, 1.0f);
color = ColorLerp(new Color((int)(value * 255.0f), (int)(value * 255.0f), (int)(value * 255.0f), 255), ColorFromHSV(angle360, Clamp(distance, 0.0f, 1.0f), 1.0f), valueActual);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Begin rendering color wheel
Begin(renderType);
for (int i = 0; i < triangleCount; i++)
{
float angleOffset = ((MathF.PI * 2.0f) / (float)triangleCount);
float angle = angleOffset * (float)i;
float angleOffsetCalculated = ((float)i + 1) * angleOffset;
Vector2 scale = new Vector2(pointScale, pointScale);
Vector2 offset = Vector2Multiply(new Vector2(MathF.Sin(angle), -MathF.Cos(angle)), scale);
Vector2 offset2 = Vector2Multiply(new Vector2(MathF.Sin(angleOffsetCalculated), -MathF.Cos(angleOffsetCalculated)), scale);
Vector2 position = Vector2Add(center, offset);
Vector2 position2 = Vector2Add(center, offset2);
float angleNonRadian = (angle / (2.0f * MathF.PI)) * 360.0f;
float angleNonRadianOffset = (angleOffset / (2.0f * MathF.PI)) * 360.0f;
Color currentColor = ColorFromHSV(angleNonRadian, 1.0f, 1.0f);
Color offsetColor = ColorFromHSV(angleNonRadian + angleNonRadianOffset, 1.0f, 1.0f);
// Input vertices differently depending on mode
if (renderType == DrawMode.Triangles)
{
// RL_TRIANGLES expects three vertices per triangle
Color4ub(currentColor.R, currentColor.G, currentColor.B, currentColor.A);
Vertex2f(position.X, position.Y);
Color4f(value, value, value, 1.0f);
Vertex2f(center.X, center.Y);
Color4ub(offsetColor.R, offsetColor.G, offsetColor.B, offsetColor.A);
Vertex2f(position2.X, position2.Y);
}
else if (renderType == DrawMode.Lines)
{
// RL_LINES expects two vertices per line
Color4ub(currentColor.R, currentColor.G, currentColor.B, currentColor.A);
Vertex2f(position.X, position.Y);
Color4ub(Color.White.R, Color.White.G, Color.White.B, Color.White.A);
Vertex2f(center.X, center.Y);
Vertex2f(center.X, center.Y);
Color4ub(offsetColor.R, offsetColor.G, offsetColor.B, offsetColor.A);
Vertex2f(position2.X, position2.Y);
Vertex2f(position2.X, position2.Y);
Color4ub(currentColor.R, currentColor.G, currentColor.B, currentColor.A);
Vertex2f(position.X, position.Y);
}
}
End();
// Make the handle slightly more visible overtop darker colors
Color handleColor = Color.Black;
if (Vector2Distance(center, circlePosition) / pointScale <= 0.5f && value <= 0.5f)
{
handleColor = Color.DarkGray;
}
// Draw the color handle
DrawCircleLinesV(circlePosition, 4.0f, handleColor);
// Draw the color in a preview, with a darkened outline.
DrawRectangleV(new Vector2(8.0f, 8.0f), new Vector2(64.0f, 64.0f), color);
DrawRectangleLinesEx(new Rectangle(8.0f, 8.0f, 64.0f, 64.0f), 2.0f, ColorLerp(color, Color.Black, 0.5f));
// Draw current color as hex and decimal
DrawText($"#{color.R:X2}{color.G:X2}{color.B:X2}\n({color.R}, {color.G}, {color.B})", 8, 8 + 64 + 8, 20, Color.DarkGray);
// Update the visuals for the copying text
Color copyColor = Color.DarkGray;
int textOffset = 0;
if (IsKeyDown(KeyboardKey.LeftControl) && IsKeyDown(KeyboardKey.C))
{
copyColor = Color.DarkGreen;
textOffset = 4;
}
// Draw the copying text
DrawText("press ctrl+c to copy!", 8, 425 - textOffset, 20, copyColor);
// Display the number of rendered triangles
DrawText($"triangle count: {triangleCount}", 8, 395, 20, Color.DarkGray);
// Slider to change color's value (minimal raygui-like control, raygui is not bound in raylib-cs)
GuiSliderBar(sliderRectangle, "value: ", "", ref value, 0.0f, 1.0f);
// Draw FPS next to outlined color preview
DrawFPS(64 + 16, 8);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Minimal raygui-like widgets (plain raylib re-implementation)
//----------------------------------------------------------------------------------
private static void GuiSliderBar(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (hover && IsMouseButtonDown(MouseButton.Left))
{
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
if (value < minValue)
{
value = minValue;
}
if (value > maxValue)
{
value = maxValue;
}
}
DrawRectangleRec(bounds, Color.LightGray);
float pct = (value - minValue) / (maxValue - minValue);
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
DrawRectangleLinesEx(bounds, 1, Color.Gray);
if (!string.IsNullOrEmpty(textLeft))
{
DrawText(textLeft, (int)bounds.X - MeasureText(textLeft, 10) - 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
if (!string.IsNullOrEmpty(textRight))
{
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rlgl color wheel");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new RlglColorWheel();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,217 @@
/*******************************************************************************************
*
* raylib [shapes] example - rlgl triangle
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.0
*
* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Robin (@RobinsAviary)
*
********************************************************************************************/
using static Raylib_cs.Rlgl;
namespace Examples.Shapes;
public partial class RlglTriangle : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / RLGL Triangle";
public string Title => "raylib [shapes] example - rlgl triangle";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
// Starting postions and rendered triangle positions
private Vector2[] startingPositions;
private Vector2[] trianglePositions;
// Currently selected vertex, -1 means none
private int triangleIndex;
private bool linesMode;
private float handleRadius;
public void Init()
{
// Starting postions and rendered triangle positions
startingPositions = [new(400.0f, 150.0f), new(300.0f, 300.0f), new(500.0f, 300.0f)];
trianglePositions = [startingPositions[0], startingPositions[1], startingPositions[2]];
// Currently selected vertex, -1 means none
triangleIndex = -1;
linesMode = false;
handleRadius = 8.0f;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.Space))
{
linesMode = !linesMode;
}
// Check selected vertex
for (int i = 0; i < 3; i++)
{
// If the mouse is within the handle circle
if (CheckCollisionPointCircle(GetMousePosition(), trianglePositions[i], handleRadius) &&
IsMouseButtonDown(MouseButton.Left))
{
triangleIndex = i;
break;
}
}
// If the user has selected a vertex, offset it by the mouse's delta this frame
if (triangleIndex != -1)
{
Vector2 mouseDelta = GetMouseDelta();
trianglePositions[triangleIndex].X += mouseDelta.X;
trianglePositions[triangleIndex].Y += mouseDelta.Y;
}
// Reset index on release
if (IsMouseButtonReleased(MouseButton.Left))
{
triangleIndex = -1;
}
// Enable/disable backface culling (2-sided triangles, slower to render)
if (IsKeyPressed(KeyboardKey.Left))
{
EnableBackfaceCulling();
}
if (IsKeyPressed(KeyboardKey.Right))
{
DisableBackfaceCulling();
}
// Reset triangle vertices to starting positions and reset backface culling
if (IsKeyPressed(KeyboardKey.R))
{
trianglePositions[0] = startingPositions[0];
trianglePositions[1] = startingPositions[1];
trianglePositions[2] = startingPositions[2];
EnableBackfaceCulling();
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (linesMode)
{
// Draw triangle with lines
Begin(DrawMode.Lines);
// Three lines, six points
// Define color for next vertex
Color4ub(255, 0, 0, 255);
// Define vertex
Vertex2f(trianglePositions[0].X, trianglePositions[0].Y);
Color4ub(0, 255, 0, 255);
Vertex2f(trianglePositions[1].X, trianglePositions[1].Y);
Color4ub(0, 255, 0, 255);
Vertex2f(trianglePositions[1].X, trianglePositions[1].Y);
Color4ub(0, 0, 255, 255);
Vertex2f(trianglePositions[2].X, trianglePositions[2].Y);
Color4ub(0, 0, 255, 255);
Vertex2f(trianglePositions[2].X, trianglePositions[2].Y);
Color4ub(255, 0, 0, 255);
Vertex2f(trianglePositions[0].X, trianglePositions[0].Y);
End();
}
else
{
// Draw triangle as a triangle
Begin(DrawMode.Triangles);
// One triangle, three points
// Define color for next vertex
Color4ub(255, 0, 0, 255);
// Define vertex
Vertex2f(trianglePositions[0].X, trianglePositions[0].Y);
Color4ub(0, 255, 0, 255);
Vertex2f(trianglePositions[1].X, trianglePositions[1].Y);
Color4ub(0, 0, 255, 255);
Vertex2f(trianglePositions[2].X, trianglePositions[2].Y);
End();
}
// Render the vertex handles, reacting to mouse movement/input
for (int i = 0; i < 3; i++)
{
// Draw handle fill focused by mouse
if (CheckCollisionPointCircle(GetMousePosition(), trianglePositions[i], handleRadius))
{
DrawCircleV(trianglePositions[i], handleRadius, ColorAlpha(Color.DarkGray, 0.5f));
}
// Draw handle fill selected
if (i == triangleIndex)
{
DrawCircleV(trianglePositions[i], handleRadius, Color.DarkGray);
}
// Draw handle outline
DrawCircleLinesV(trianglePositions[i], handleRadius, Color.Black);
}
// Draw controls
DrawText("SPACE: Toggle lines mode", 10, 10, 20, Color.DarkGray);
DrawText("LEFT-RIGHT: Toggle backface culling", 10, 40, 20, Color.DarkGray);
DrawText("MOUSE: Click and drag vertex points", 10, 70, 20, Color.DarkGray);
DrawText("R: Reset triangle to start positions", 10, 100, 20, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rlgl triangle");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new RlglTriangle();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,347 @@
/*******************************************************************************************
*
* raylib [shapes] example - simple particles
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.6, last time updated with raylib 5.6
*
* Example contributed by Jordi Santonja (@JordSant)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Jordi Santonja (@JordSant)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class SimpleParticles : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int MAX_PARTICLES = 3000; // Max number of particles
public string Name => "Shapes / Simple Particles";
public string Title => "raylib [shapes] example - simple particles";
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
private enum ParticleType
{
Water = 0,
Smoke,
Fire
}
private static readonly string[] particleTypeNames = ["WATER", "SMOKE", "FIRE"];
private struct Particle
{
public ParticleType type; // Particle type (WATER, SMOKE, FIRE)
public Vector2 position; // Particle position on screen
public Vector2 velocity; // Particle current speed and direction
public float radius; // Particle radius
public Color color; // Particle color
public float lifeTime; // Particle life time
public bool alive; // Particle alive: inside screen and life time
}
// Circular buffer state
private int head; // Index for the next write
private int tail; // Index for the next read
private Particle[] buffer; // Particle buffer array
// Particle emitter parameters
private int emissionRate; // Negative: on average every -X frames. Positive: particles per frame
private ParticleType currentType;
private Vector2 emitterPosition;
private Random random;
public void Init()
{
// Definition of particles
buffer = new Particle[MAX_PARTICLES]; // Particle array
head = 0;
tail = 0;
// Particle emitter parameters
emissionRate = -2; // Negative: on average every -X frames. Positive: particles per frame
currentType = ParticleType.Water;
emitterPosition = new(screenWidth / 2.0f, screenHeight / 2.0f);
random = new Random();
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Emit new particles: when emissionRate is 1, emit every frame
if (emissionRate < 0)
{
if (random.Next(-emissionRate) == 0)
{
EmitParticle(emitterPosition, currentType);
}
}
else
{
for (int i = 0; i <= emissionRate; i++)
{
EmitParticle(emitterPosition, currentType);
}
}
// Update the parameters of each particle
UpdateParticles(screenWidth, screenHeight);
// Remove dead particles from the circular buffer
UpdateCircularBuffer();
// Change Particle Emission Rate (UP/DOWN arrows)
if (IsKeyPressed(KeyboardKey.Up))
{
emissionRate++;
}
if (IsKeyPressed(KeyboardKey.Down))
{
emissionRate--;
}
// Change Particle Type (LEFT/RIGHT arrows)
if (IsKeyPressed(KeyboardKey.Right))
{
currentType = (currentType == ParticleType.Fire) ? ParticleType.Water : (ParticleType)((int)currentType + 1);
}
if (IsKeyPressed(KeyboardKey.Left))
{
currentType = (currentType == ParticleType.Water) ? ParticleType.Fire : (ParticleType)((int)currentType - 1);
}
if (IsMouseButtonDown(MouseButton.Left))
{
emitterPosition = GetMousePosition();
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Call the function with a loop to draw all particles
DrawParticles();
// Draw UI and Instructions
DrawRectangle(5, 5, 315, 75, Fade(Color.SkyBlue, 0.5f));
DrawRectangleLines(5, 5, 315, 75, Color.Blue);
DrawText("CONTROLS:", 15, 15, 10, Color.Black);
DrawText("UP/DOWN: Change Particle Emission Rate", 15, 35, 10, Color.Black);
DrawText("LEFT/RIGHT: Change Particle Type (Water, Smoke, Fire)", 15, 55, 10, Color.Black);
if (emissionRate < 0)
{
DrawText($"Particles every {-emissionRate} frames | Type: {particleTypeNames[(int)currentType]}", 15, 95, 10, Color.DarkGray);
}
else
{
DrawText($"{emissionRate + 1} Particles per frame | Type: {particleTypeNames[(int)currentType]}", 15, 95, 10, Color.DarkGray);
}
DrawFPS(screenWidth - 80, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
private void EmitParticle(Vector2 emitterPosition, ParticleType type)
{
int index = AddToCircularBuffer();
// If buffer is full, index is -1
if (index != -1)
{
ref Particle newParticle = ref buffer[index];
// Fill particle properties
newParticle.position = emitterPosition;
newParticle.alive = true;
newParticle.lifeTime = 0.0f;
newParticle.type = type;
float speed = (float)(random.Next(10)) / 5.0f;
switch (type)
{
case ParticleType.Water:
{
newParticle.radius = 5.0f;
newParticle.color = Color.Blue;
}
break;
case ParticleType.Smoke:
{
newParticle.radius = 7.0f;
newParticle.color = Color.Gray;
}
break;
case ParticleType.Fire:
{
newParticle.radius = 10.0f;
newParticle.color = Color.Yellow;
speed /= 10.0f;
}
break;
default:
break;
}
float direction = (float)(random.Next(360));
newParticle.velocity = new(speed * MathF.Cos(direction * DEG2RAD), speed * MathF.Sin(direction * DEG2RAD));
}
}
private int AddToCircularBuffer()
{
int index = -1;
// Check if buffer full
if (((head + 1) % MAX_PARTICLES) != tail)
{
// Add new particle to the head position and advance head
index = head;
head = (head + 1) % MAX_PARTICLES;
}
return index;
}
private void UpdateParticles(int screenWidth, int screenHeight)
{
for (int i = tail; i != head; i = (i + 1) % MAX_PARTICLES)
{
// Update particle life and positions
buffer[i].lifeTime += 1.0f / 60.0f; // 60 FPS -> 1/60 seconds per frame
switch (buffer[i].type)
{
case ParticleType.Water:
{
buffer[i].position.X += buffer[i].velocity.X;
buffer[i].velocity.Y += 0.2f; // Gravity
buffer[i].position.Y += buffer[i].velocity.Y;
}
break;
case ParticleType.Smoke:
{
buffer[i].position.X += buffer[i].velocity.X;
buffer[i].velocity.Y -= 0.05f; // Upwards
buffer[i].position.Y += buffer[i].velocity.Y;
buffer[i].radius += 0.5f; // Increment radius: smoke expands
buffer[i].color.A -= 4; // Decrement alpha: smoke fades
// If alpha transparent, particle dies
if (buffer[i].color.A < 4)
{
buffer[i].alive = false;
}
}
break;
case ParticleType.Fire:
{
// Add a little horizontal oscillation to fire particles
buffer[i].position.X += buffer[i].velocity.X + MathF.Cos(buffer[i].lifeTime * 215.0f);
buffer[i].velocity.Y -= 0.05f; // Upwards
buffer[i].position.Y += buffer[i].velocity.Y;
buffer[i].radius -= 0.15f; // Decrement radius: fire shrinks
buffer[i].color.G -= 3; // Decrement green: fire turns reddish starting from yellow
// If radius too small, particle dies
if (buffer[i].radius <= 0.02f)
{
buffer[i].alive = false;
}
}
break;
default:
break;
}
// Disable particle when out of screen
Vector2 center = buffer[i].position;
float radius = buffer[i].radius;
if ((center.X < -radius) || (center.X > (screenWidth + radius)) ||
(center.Y < -radius) || (center.Y > (screenHeight + radius)))
{
buffer[i].alive = false;
}
}
}
private void UpdateCircularBuffer()
{
// Update circular buffer: advance tail over dead particles
while ((tail != head) && !buffer[tail].alive)
{
tail = (tail + 1) % MAX_PARTICLES;
}
}
private void DrawParticles()
{
for (int i = tail; i != head; i = (i + 1) % MAX_PARTICLES)
{
if (buffer[i].alive)
{
DrawCircleV(buffer[i].position,
buffer[i].radius,
buffer[i].color);
}
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - simple particles");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new SimpleParticles();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,461 @@
/*******************************************************************************************
*
* raylib [shapes] example - splines drawing
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.0, last time updated with raylib 5.0
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2023-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class SplinesDrawing : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int MAX_SPLINE_POINTS = 32;
public string Name => "Shapes / Splines Drawing";
public string Title => "raylib [shapes] example - splines drawing";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Cubic Bezier spline control points
// NOTE: Every segment has two control points
private struct ControlPoint
{
public Vector2 start;
public Vector2 end;
}
// Spline types
private const int SPLINE_LINEAR = 0; // Linear
private const int SPLINE_BASIS = 1; // B-Spline
private const int SPLINE_CATMULLROM = 2; // Catmull-Rom
private const int SPLINE_BEZIER = 3; // Cubic Bezier
private Vector2[] points;
private Vector2[] pointsInterleaved;
private int pointCount;
private int selectedPoint;
private int focusedPoint;
private int selectedControlIndex; // -1 when none
private bool selectedControlStart;
private int focusedControlIndex; // -1 when none
private bool focusedControlStart;
private ControlPoint[] control;
// Spline config variables
private float splineThickness;
private int splineTypeActive; // 0-Linear, 1-BSpline, 2-CatmullRom, 3-Bezier
private bool splineTypeEditMode;
private bool splineHelpersActive;
// Minimal raygui-like global lock
private static bool guiLocked;
public void Init()
{
points = new Vector2[MAX_SPLINE_POINTS];
points[0] = new Vector2(50.0f, 400.0f);
points[1] = new Vector2(160.0f, 220.0f);
points[2] = new Vector2(340.0f, 380.0f);
points[3] = new Vector2(520.0f, 60.0f);
points[4] = new Vector2(710.0f, 260.0f);
// Array required for spline bezier-cubic,
// including control points interleaved with start-end segment points
pointsInterleaved = new Vector2[3 * (MAX_SPLINE_POINTS - 1) + 1];
pointCount = 5;
selectedPoint = -1;
focusedPoint = -1;
selectedControlIndex = -1;
focusedControlIndex = -1;
// Cubic Bezier control points initialization
control = new ControlPoint[MAX_SPLINE_POINTS - 1];
for (int i = 0; i < pointCount - 1; i++)
{
control[i].start = new Vector2(points[i].X + 50, points[i].Y);
control[i].end = new Vector2(points[i + 1].X - 50, points[i + 1].Y);
}
splineThickness = 8.0f;
splineTypeActive = SPLINE_LINEAR;
splineTypeEditMode = false;
splineHelpersActive = true;
guiLocked = false;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Spline points creation logic (at the end of spline)
if (IsMouseButtonPressed(MouseButton.Right) && (pointCount < MAX_SPLINE_POINTS))
{
points[pointCount] = GetMousePosition();
int i = pointCount - 1;
control[i].start = new Vector2(points[i].X + 50, points[i].Y);
control[i].end = new Vector2(points[i + 1].X - 50, points[i + 1].Y);
pointCount++;
}
// Spline point focus and selection logic
if ((selectedPoint == -1) && ((splineTypeActive != SPLINE_BEZIER) || (selectedControlIndex == -1)))
{
focusedPoint = -1;
for (int i = 0; i < pointCount; i++)
{
if (CheckCollisionPointCircle(GetMousePosition(), points[i], 8.0f))
{
focusedPoint = i;
break;
}
}
if (IsMouseButtonPressed(MouseButton.Left))
{
selectedPoint = focusedPoint;
}
}
// Spline point movement logic
if (selectedPoint >= 0)
{
points[selectedPoint] = GetMousePosition();
if (IsMouseButtonReleased(MouseButton.Left))
{
selectedPoint = -1;
}
}
// Cubic Bezier spline control points logic
if ((splineTypeActive == SPLINE_BEZIER) && (focusedPoint == -1))
{
// Spline control point focus and selection logic
if (selectedControlIndex == -1)
{
focusedControlIndex = -1;
for (int i = 0; i < pointCount - 1; i++)
{
if (CheckCollisionPointCircle(GetMousePosition(), control[i].start, 6.0f))
{
focusedControlIndex = i;
focusedControlStart = true;
break;
}
else if (CheckCollisionPointCircle(GetMousePosition(), control[i].end, 6.0f))
{
focusedControlIndex = i;
focusedControlStart = false;
break;
}
}
if (IsMouseButtonPressed(MouseButton.Left))
{
selectedControlIndex = focusedControlIndex;
selectedControlStart = focusedControlStart;
}
}
// Spline control point movement logic
if (selectedControlIndex != -1)
{
if (selectedControlStart)
{
control[selectedControlIndex].start = GetMousePosition();
}
else
{
control[selectedControlIndex].end = GetMousePosition();
}
if (IsMouseButtonReleased(MouseButton.Left))
{
selectedControlIndex = -1;
}
}
}
// Spline selection logic
if (IsKeyPressed(KeyboardKey.One))
{
splineTypeActive = 0;
}
else if (IsKeyPressed(KeyboardKey.Two))
{
splineTypeActive = 1;
}
else if (IsKeyPressed(KeyboardKey.Three))
{
splineTypeActive = 2;
}
else if (IsKeyPressed(KeyboardKey.Four))
{
splineTypeActive = 3;
}
// Clear selection when changing to a spline without control points
if (IsKeyPressed(KeyboardKey.One) || IsKeyPressed(KeyboardKey.Two) || IsKeyPressed(KeyboardKey.Three))
{
selectedControlIndex = -1;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (splineTypeActive == SPLINE_LINEAR)
{
// Draw spline: linear
DrawSplineLinear(points, pointCount, splineThickness, Color.Red);
}
else if (splineTypeActive == SPLINE_BASIS)
{
// Draw spline: basis
DrawSplineBasis(points, pointCount, splineThickness, Color.Red); // Provide connected points array
}
else if (splineTypeActive == SPLINE_CATMULLROM)
{
// Draw spline: catmull-rom
DrawSplineCatmullRom(points, pointCount, splineThickness, Color.Red); // Provide connected points array
}
else if (splineTypeActive == SPLINE_BEZIER)
{
// NOTE: Cubic-bezier spline requires the 2 control points of each segment to be
// provided interleaved with the start and end point of every segment
for (int i = 0; i < (pointCount - 1); i++)
{
pointsInterleaved[3 * i] = points[i];
pointsInterleaved[3 * i + 1] = control[i].start;
pointsInterleaved[3 * i + 2] = control[i].end;
}
pointsInterleaved[3 * (pointCount - 1)] = points[pointCount - 1];
// Draw spline: cubic-bezier (with control points)
DrawSplineBezierCubic(pointsInterleaved, 3 * (pointCount - 1) + 1, splineThickness, Color.Red);
// Draw spline control points
for (int i = 0; i < pointCount - 1; i++)
{
// Every cubic bezier point have two control points
DrawCircleV(control[i].start, 6, Color.Gold);
DrawCircleV(control[i].end, 6, Color.Gold);
if (focusedControlIndex == i && focusedControlStart)
{
DrawCircleV(control[i].start, 8, Color.Green);
}
else if (focusedControlIndex == i && !focusedControlStart)
{
DrawCircleV(control[i].end, 8, Color.Green);
}
DrawLineEx(points[i], control[i].start, 1.0f, Color.LightGray);
DrawLineEx(points[i + 1], control[i].end, 1.0f, Color.LightGray);
// Draw spline control lines
DrawLineV(points[i], control[i].start, Color.Gray);
DrawLineV(control[i].end, points[i + 1], Color.Gray);
}
}
if (splineHelpersActive)
{
// Draw spline point helpers
for (int i = 0; i < pointCount; i++)
{
DrawCircleLinesV(points[i], (focusedPoint == i) ? 12.0f : 8.0f, (focusedPoint == i) ? Color.Blue : Color.DarkBlue);
if ((splineTypeActive != SPLINE_LINEAR) &&
(splineTypeActive != SPLINE_BEZIER) &&
(i < pointCount - 1))
{
DrawLineV(points[i], points[i + 1], Color.Gray);
}
DrawText($"[{points[i].X:F0}, {points[i].Y:F0}]", (int)points[i].X, (int)points[i].Y + 10, 10, Color.Black);
}
}
// Check all possible UI states that require controls lock
if (splineTypeEditMode || (selectedPoint != -1) || (selectedControlIndex != -1))
{
GuiLock();
}
// Draw spline config
GuiLabel(new Rectangle(12, 62, 140, 24), $"Spline thickness: {(int)splineThickness}");
GuiSliderBar(new Rectangle(12, 60 + 24, 140, 16), null, null, ref splineThickness, 1.0f, 40.0f);
GuiCheckBox(new Rectangle(12, 110, 20, 20), "Show point helpers", ref splineHelpersActive);
if (splineTypeEditMode)
{
GuiUnlock();
}
GuiLabel(new Rectangle(12, 10, 140, 24), "Spline type:");
if (GuiDropdownBox(new Rectangle(12, 8 + 24, 140, 28), "LINEAR;BSPLINE;CATMULLROM;BEZIER", ref splineTypeActive, splineTypeEditMode))
{
splineTypeEditMode = !splineTypeEditMode;
}
GuiUnlock();
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Minimal raygui-like widgets (plain raylib re-implementation)
//----------------------------------------------------------------------------------
private static void GuiLock() => guiLocked = true;
private static void GuiUnlock() => guiLocked = false;
private static void GuiLabel(Rectangle bounds, string text)
{
DrawText(text, (int)bounds.X, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
private static void GuiSliderBar(Rectangle bounds, string textLeft, string textRight, ref float value, float minValue, float maxValue)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (!guiLocked && hover && IsMouseButtonDown(MouseButton.Left))
{
value = minValue + ((mouse.X - bounds.X) / bounds.Width) * (maxValue - minValue);
if (value < minValue)
{
value = minValue;
}
if (value > maxValue)
{
value = maxValue;
}
}
DrawRectangleRec(bounds, Color.LightGray);
float pct = (value - minValue) / (maxValue - minValue);
DrawRectangleRec(new Rectangle(bounds.X, bounds.Y, bounds.Width * pct, bounds.Height), Color.SkyBlue);
DrawRectangleLinesEx(bounds, 1, Color.Gray);
if (!string.IsNullOrEmpty(textLeft))
{
DrawText(textLeft, (int)bounds.X - MeasureText(textLeft, 10) - 5, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
if (!string.IsNullOrEmpty(textRight))
{
DrawText(textRight, (int)(bounds.X + bounds.Width + 5), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
private static void GuiCheckBox(Rectangle bounds, string text, ref bool active)
{
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (!guiLocked && hover && IsMouseButtonPressed(MouseButton.Left))
{
active = !active;
}
DrawRectangleLinesEx(bounds, 1, hover ? Color.DarkBlue : Color.Gray);
if (active)
{
DrawRectangle((int)bounds.X + 4, (int)bounds.Y + 4, (int)bounds.Width - 8, (int)bounds.Height - 8, Color.DarkGray);
}
if (text != null)
{
DrawText(text, (int)(bounds.X + bounds.Width + 8), (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
}
}
private static bool GuiDropdownBox(Rectangle bounds, string text, ref int active, bool editMode)
{
string[] items = text.Split(';');
bool pressed = false;
Vector2 mouse = GetMousePosition();
bool clickable = !guiLocked;
bool hoverMain = CheckCollisionPointRec(mouse, bounds);
DrawRectangleRec(bounds, editMode ? Color.SkyBlue : (hoverMain ? Color.LightGray : Color.RayWhite));
DrawRectangleLinesEx(bounds, 1, editMode ? Color.Blue : Color.Gray);
DrawText(items[active], (int)bounds.X + 6, (int)(bounds.Y + bounds.Height / 2 - 5), 10, Color.DarkGray);
if (editMode)
{
for (int i = 0; i < items.Length; i++)
{
Rectangle itemRec = new Rectangle(bounds.X, bounds.Y + bounds.Height * (i + 1), bounds.Width, bounds.Height);
bool hoverItem = CheckCollisionPointRec(mouse, itemRec);
DrawRectangleRec(itemRec, hoverItem ? Color.SkyBlue : Color.RayWhite);
DrawRectangleLinesEx(itemRec, 1, Color.Gray);
DrawText(items[i], (int)itemRec.X + 6, (int)(itemRec.Y + itemRec.Height / 2 - 5), 10, Color.DarkGray);
if (clickable && hoverItem && IsMouseButtonPressed(MouseButton.Left))
{
active = i;
pressed = true;
}
}
}
if (clickable && hoverMain && IsMouseButtonPressed(MouseButton.Left))
{
pressed = true;
}
return pressed;
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - splines drawing");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new SplinesDrawing();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,191 @@
/*******************************************************************************************
*
* raylib [shapes] example - starfield effect
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.5, last time updated with raylib 6.0
*
* Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 JP Mortiboys (@themushroompirates)
*
********************************************************************************************/
using static Raylib_cs.Raymath; // Required for: Lerp()
namespace Examples.Shapes;
public partial class StarfieldEffect : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int STAR_COUNT = 420;
public string Name => "Shapes / Starfield Effect";
public string Title => "raylib [shapes] example - starfield effect";
private Color bgColor;
// Speed at which we fly forward
private float speed;
// We're either drawing lines or circles
private bool drawLines;
private Vector3[] stars;
private Vector2[] starsScreenPos;
public void Init()
{
bgColor = ColorLerp(Color.DarkBlue, Color.Black, 0.69f);
// Speed at which we fly forward
speed = 10.0f / 9.0f;
// We're either drawing lines or circles
drawLines = true;
stars = new Vector3[STAR_COUNT];
starsScreenPos = new Vector2[STAR_COUNT];
// Setup the stars with a random position
for (int i = 0; i < STAR_COUNT; i++)
{
stars[i].X = (float)GetRandomValue(-screenWidth / 2, (int)screenWidth / 2);
stars[i].Y = (float)GetRandomValue(-screenHeight / 2, (int)screenHeight / 2);
stars[i].Z = 1.0f;
}
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Change speed based on mouse
float mouseMove = GetMouseWheelMove();
if ((int)mouseMove != 0)
{
speed += 2.0f * mouseMove / 9.0f;
}
if (speed < 0.0f)
{
speed = 0.1f;
}
else if (speed > 2.0f)
{
speed = 2.0f;
}
// Toggle lines / points with space bar
if (IsKeyPressed(KeyboardKey.Space))
{
drawLines = !drawLines;
}
float dt = GetFrameTime();
for (int i = 0; i < STAR_COUNT; i++)
{
// Update star's timer
stars[i].Z -= dt * speed;
// Calculate the screen position
starsScreenPos[i] = new Vector2(
screenWidth * 0.5f + stars[i].X / stars[i].Z,
screenHeight * 0.5f + stars[i].Y / stars[i].Z
);
// If the star is too old, or offscreen, it dies and we make a new random one
if ((stars[i].Z < 0.0f) || (starsScreenPos[i].X < 0) || (starsScreenPos[i].Y < 0.0f) ||
(starsScreenPos[i].X > screenWidth) || (starsScreenPos[i].Y > screenHeight))
{
stars[i].X = (float)GetRandomValue(-screenWidth / 2, screenWidth / 2);
stars[i].Y = (float)GetRandomValue(-screenHeight / 2, screenHeight / 2);
stars[i].Z = 1.0f;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(bgColor);
for (int i = 0; i < STAR_COUNT; i++)
{
if (drawLines)
{
// Get the time a little while ago for this star, but clamp it
float t = Clamp(stars[i].Z + 1.0f / 32.0f, 0.0f, 1.0f);
// If it's different enough from the current time, we proceed
if ((t - stars[i].Z) > 1e-3)
{
// Calculate the screen position of the old point
Vector2 startPos = new Vector2(
screenWidth * 0.5f + stars[i].X / t,
screenHeight * 0.5f + stars[i].Y / t
);
// Draw a line connecting the old point to the current point
DrawLineV(startPos, starsScreenPos[i], Color.RayWhite);
}
}
else
{
// Make the radius grow as the star ages
float radius = Lerp(stars[i].Z, 1.0f, 5.0f);
// Draw the circle
DrawCircleV(starsScreenPos[i], radius, Color.RayWhite);
}
}
DrawText($"[MOUSE WHEEL] Current Speed: {9.0f * speed / 2.0f:F0}", 10, 40, 20, Color.RayWhite);
DrawText($"[SPACE] Current draw mode: {(drawLines ? "Lines" : "Circles")}", 10, 70, 20, Color.RayWhite);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - starfield effect");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new StarfieldEffect();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,458 @@
/*******************************************************************************************
*
* raylib [shapes] example - top down lights
*
* Example complexity rating: [] 4/4
*
* Example originally created with raylib 4.2, last time updated with raylib 4.2
*
* Example contributed by Jeffery Myers (@JeffM2501) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2022-2025 Jeffery Myers (@JeffM2501)
*
********************************************************************************************/
using static Raylib_cs.Raymath;
using static Raylib_cs.Rlgl;
namespace Examples.Shapes;
public partial class TopDownLights : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
// Custom Blend Modes
private const int RLGL_SRC_ALPHA = 0x0302;
private const int RLGL_MIN = 0x8007;
private const int RLGL_MAX = 0x8008;
private const int MAX_BOXES = 20;
private const int MAX_SHADOWS = MAX_BOXES * 3; // MAX_BOXES*3 - Each box can cast up to two shadow volumes for the edges it is away from, and one for the box itself
private const int MAX_LIGHTS = 16;
public string Name => "Shapes / Top Down Lights";
public string Title => "raylib [shapes] example - top down lights";
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Shadow geometry type
private class ShadowGeometry
{
public Vector2[] vertices = new Vector2[4];
}
// Light info type
private class LightInfo
{
public bool active; // Is this light slot active?
public bool dirty; // Does this light need to be updated?
public bool valid; // Is this light in a valid position?
public Vector2 position; // Light position
public RenderTexture2D mask; // Alpha mask for the light
public float outerRadius; // The distance the light touches
public Rectangle bounds; // A cached rectangle of the light bounds to help with culling
public ShadowGeometry[] shadows = new ShadowGeometry[MAX_SHADOWS];
public int shadowCount;
public LightInfo()
{
for (int i = 0; i < MAX_SHADOWS; i++)
{
shadows[i] = new ShadowGeometry();
}
}
}
//------------------------------------------------------------------------------------
// Global Variables Definition
//------------------------------------------------------------------------------------
private LightInfo[] lights;
private int boxCount;
private Rectangle[] boxes;
private Texture2D backgroundTexture;
private RenderTexture2D lightMask;
private int nextLight;
private bool showLines;
public void Init()
{
lights = new LightInfo[MAX_LIGHTS];
for (int i = 0; i < MAX_LIGHTS; i++)
{
lights[i] = new LightInfo();
}
// Initialize our 'world' of boxes
boxCount = 0;
boxes = new Rectangle[MAX_BOXES];
SetupBoxes();
// Create a checkerboard ground texture
Image img = GenImageChecked(64, 64, 32, 32, Color.DarkBrown, Color.DarkGray);
backgroundTexture = LoadTextureFromImage(img);
UnloadImage(img);
// Create a global light mask to hold all the blended lights
lightMask = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
// Setup initial light
SetupLight(0, 600, 400, 300);
nextLight = 1;
showLines = false;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Drag light 0
if (IsMouseButtonDown(MouseButton.Left))
{
MoveLight(0, GetMousePosition().X, GetMousePosition().Y);
}
// Make a new light
if (IsMouseButtonPressed(MouseButton.Right) && (nextLight < MAX_LIGHTS))
{
SetupLight(nextLight, GetMousePosition().X, GetMousePosition().Y, 200);
nextLight++;
}
// Toggle debug info
if (IsKeyPressed(KeyboardKey.F1))
{
showLines = !showLines;
}
// Update the lights and keep track if any were dirty so we know if we need to update the master light mask
bool dirtyLights = false;
for (int i = 0; i < MAX_LIGHTS; i++)
{
if (UpdateLight(i, boxes, boxCount))
{
dirtyLights = true;
}
}
// Update the light mask
if (dirtyLights)
{
// Build up the light mask
BeginTextureMode(lightMask);
ClearBackground(Color.Black);
// Force the blend mode to only set the alpha of the destination
SetBlendFactors(RLGL_SRC_ALPHA, RLGL_SRC_ALPHA, RLGL_MIN);
SetBlendMode(BlendMode.Custom);
// Merge in all the light masks
for (int i = 0; i < MAX_LIGHTS; i++)
{
if (lights[i].active)
{
DrawTextureRec(lights[i].mask.Texture, new Rectangle(0, 0, (float)GetScreenWidth(), -(float)GetScreenHeight()), Vector2Zero(), Color.White);
}
}
DrawRenderBatchActive();
// Go back to normal blend
SetBlendMode(BlendMode.Alpha);
EndTextureMode();
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.Black);
// Draw the tile background
DrawTextureRec(backgroundTexture, new Rectangle(0, 0, (float)GetScreenWidth(), (float)GetScreenHeight()), Vector2Zero(), Color.White);
// Overlay the shadows from all the lights
DrawTextureRec(lightMask.Texture, new Rectangle(0, 0, (float)GetScreenWidth(), -(float)GetScreenHeight()), Vector2Zero(), ColorAlpha(Color.White, showLines ? 0.75f : 1.0f));
// Draw the lights
for (int i = 0; i < MAX_LIGHTS; i++)
{
if (lights[i].active)
{
DrawCircle((int)lights[i].position.X, (int)lights[i].position.Y, 10, (i == 0) ? Color.Yellow : Color.White);
}
}
if (showLines)
{
for (int s = 0; s < lights[0].shadowCount; s++)
{
DrawTriangleFan(lights[0].shadows[s].vertices, 4, Color.DarkPurple);
}
for (int b = 0; b < boxCount; b++)
{
if (CheckCollisionRecs(boxes[b], lights[0].bounds))
{
DrawRectangleRec(boxes[b], Color.Purple);
}
DrawRectangleLines((int)boxes[b].X, (int)boxes[b].Y, (int)boxes[b].Width, (int)boxes[b].Height, Color.DarkBlue);
}
DrawText("(F1) Hide Shadow Volumes", 10, 50, 10, Color.Green);
}
else
{
DrawText("(F1) Show Shadow Volumes", 10, 50, 10, Color.Green);
}
DrawFPS(screenWidth - 80, 10);
DrawText("Drag to move light #1", 10, 10, 10, Color.DarkGreen);
DrawText("Right click to add new light", 10, 30, 10, Color.DarkGreen);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadTexture(backgroundTexture);
UnloadRenderTexture(lightMask);
for (int i = 0; i < MAX_LIGHTS; i++)
{
if (lights[i].active)
{
UnloadRenderTexture(lights[i].mask);
}
}
}
//------------------------------------------------------------------------------------
// Module Functions Definition
//------------------------------------------------------------------------------------
// Move a light and mark it as dirty so that we update it's mask next frame
private void MoveLight(int slot, float x, float y)
{
lights[slot].dirty = true;
lights[slot].position.X = x;
lights[slot].position.Y = y;
// update the cached bounds
lights[slot].bounds.X = x - lights[slot].outerRadius;
lights[slot].bounds.Y = y - lights[slot].outerRadius;
}
// Compute a shadow volume for the edge
// It takes the edge and projects it back by the light radius and turns it into a quad
private void ComputeShadowVolumeForEdge(int slot, Vector2 sp, Vector2 ep)
{
if (lights[slot].shadowCount >= MAX_SHADOWS)
{
return;
}
float extension = lights[slot].outerRadius * 2;
Vector2 spVector = Vector2Normalize(Vector2Subtract(sp, lights[slot].position));
Vector2 spProjection = Vector2Add(sp, Vector2Scale(spVector, extension));
Vector2 epVector = Vector2Normalize(Vector2Subtract(ep, lights[slot].position));
Vector2 epProjection = Vector2Add(ep, Vector2Scale(epVector, extension));
lights[slot].shadows[lights[slot].shadowCount].vertices[0] = sp;
lights[slot].shadows[lights[slot].shadowCount].vertices[1] = ep;
lights[slot].shadows[lights[slot].shadowCount].vertices[2] = epProjection;
lights[slot].shadows[lights[slot].shadowCount].vertices[3] = spProjection;
lights[slot].shadowCount++;
}
// Setup a light
private void SetupLight(int slot, float x, float y, float radius)
{
lights[slot].active = true;
lights[slot].valid = false; // The light must prove it is valid
lights[slot].mask = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
lights[slot].outerRadius = radius;
lights[slot].bounds.Width = radius * 2;
lights[slot].bounds.Height = radius * 2;
MoveLight(slot, x, y);
// Force the render texture to have something in it
DrawLightMask(slot);
}
// See if a light needs to update it's mask
private bool UpdateLight(int slot, Rectangle[] boxes, int count)
{
if (!lights[slot].active || !lights[slot].dirty)
{
return false;
}
lights[slot].dirty = false;
lights[slot].shadowCount = 0;
lights[slot].valid = false;
for (int i = 0; i < count; i++)
{
// Are we in a box? if so we are not valid
if (CheckCollisionPointRec(lights[slot].position, boxes[i]))
{
return false;
}
// If this box is outside our bounds, we can skip it
if (!CheckCollisionRecs(lights[slot].bounds, boxes[i]))
{
continue;
}
// Check the edges that are on the same side we are, and cast shadow volumes out from them
// Top
Vector2 sp = new Vector2(boxes[i].X, boxes[i].Y);
Vector2 ep = new Vector2(boxes[i].X + boxes[i].Width, boxes[i].Y);
if (lights[slot].position.Y > ep.Y)
{
ComputeShadowVolumeForEdge(slot, sp, ep);
}
// Right
sp = ep;
ep.Y += boxes[i].Height;
if (lights[slot].position.X < ep.X)
{
ComputeShadowVolumeForEdge(slot, sp, ep);
}
// Bottom
sp = ep;
ep.X -= boxes[i].Width;
if (lights[slot].position.Y < ep.Y)
{
ComputeShadowVolumeForEdge(slot, sp, ep);
}
// Left
sp = ep;
ep.Y -= boxes[i].Height;
if (lights[slot].position.X > ep.X)
{
ComputeShadowVolumeForEdge(slot, sp, ep);
}
// The box itself
lights[slot].shadows[lights[slot].shadowCount].vertices[0] = new Vector2(boxes[i].X, boxes[i].Y);
lights[slot].shadows[lights[slot].shadowCount].vertices[1] = new Vector2(boxes[i].X, boxes[i].Y + boxes[i].Height);
lights[slot].shadows[lights[slot].shadowCount].vertices[2] = new Vector2(boxes[i].X + boxes[i].Width, boxes[i].Y + boxes[i].Height);
lights[slot].shadows[lights[slot].shadowCount].vertices[3] = new Vector2(boxes[i].X + boxes[i].Width, boxes[i].Y);
lights[slot].shadowCount++;
}
lights[slot].valid = true;
DrawLightMask(slot);
return true;
}
// Draw the light and shadows to the mask for a light
private void DrawLightMask(int slot)
{
// Use the light mask
BeginTextureMode(lights[slot].mask);
ClearBackground(Color.White);
// Force the blend mode to only set the alpha of the destination
SetBlendFactors(RLGL_SRC_ALPHA, RLGL_SRC_ALPHA, RLGL_MIN);
SetBlendMode(BlendMode.Custom);
// If we are valid, then draw the light radius to the alpha mask
if (lights[slot].valid)
{
DrawCircleGradient(lights[slot].position, lights[slot].outerRadius, ColorAlpha(Color.White, 0), Color.White);
}
DrawRenderBatchActive();
// Cut out the shadows from the light radius by forcing the alpha to maximum
SetBlendMode(BlendMode.Alpha);
SetBlendFactors(RLGL_SRC_ALPHA, RLGL_SRC_ALPHA, RLGL_MAX);
SetBlendMode(BlendMode.Custom);
// Draw the shadows to the alpha mask
for (int i = 0; i < lights[slot].shadowCount; i++)
{
DrawTriangleFan(lights[slot].shadows[i].vertices, 4, Color.White);
}
DrawRenderBatchActive();
// Go back to normal blend mode
SetBlendMode(BlendMode.Alpha);
EndTextureMode();
}
// Set up some boxes
private void SetupBoxes()
{
boxes[0] = new Rectangle(150, 80, 40, 40);
boxes[1] = new Rectangle(1200, 700, 40, 40);
boxes[2] = new Rectangle(200, 600, 40, 40);
boxes[3] = new Rectangle(1000, 50, 40, 40);
boxes[4] = new Rectangle(500, 350, 40, 40);
for (int i = 5; i < MAX_BOXES; i++)
{
boxes[i] = new Rectangle((float)GetRandomValue(0, GetScreenWidth()), (float)GetRandomValue(0, GetScreenHeight()), (float)GetRandomValue(10, 100), (float)GetRandomValue(10, 100));
}
boxCount = MAX_BOXES;
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - top down lights");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new TopDownLights();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,137 @@
/*******************************************************************************************
*
* raylib [shapes] example - triangle strip
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.0
*
* Example contributed by Jopestpe (@jopestpe)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Jopestpe (@jopestpe)
*
********************************************************************************************/
namespace Examples.Shapes;
public partial class TriangleStrip : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Triangle Strip";
public string Title => "raylib [shapes] example - triangle strip";
private Vector2[] points;
private Vector2 center;
private float segments;
private float insideRadius;
private float outsideRadius;
private bool outline;
public void Init()
{
points = new Vector2[122];
center = new((screenWidth / 2.0f) - 125.0f, screenHeight / 2.0f);
segments = 6.0f;
insideRadius = 100.0f;
outsideRadius = 150.0f;
outline = true;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
int pointCount = (int)(segments);
float angleStep = (360.0f / pointCount) * DEG2RAD;
for (int i = 0, i2 = 0; i < pointCount; i++, i2 += 2)
{
float angle1 = i * angleStep;
points[i2] = new Vector2(center.X + MathF.Cos(angle1) * insideRadius, center.Y + MathF.Sin(angle1) * insideRadius);
float angle2 = angle1 + angleStep / 2.0f;
points[i2 + 1] = new Vector2(center.X + MathF.Cos(angle2) * outsideRadius, center.Y + MathF.Sin(angle2) * outsideRadius);
}
points[pointCount * 2] = points[0];
points[pointCount * 2 + 1] = points[1];
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
for (int i = 0; i < pointCount; i++)
{
Vector2 a = points[i * 2];
Vector2 b = points[i * 2 + 1];
Vector2 c = points[i * 2 + 2];
Vector2 d = points[i * 2 + 3];
float angle1 = i * angleStep;
DrawTriangle(c, b, a, ColorFromHSV(angle1 * RAD2DEG, 1.0f, 1.0f));
DrawTriangle(d, b, c, ColorFromHSV((angle1 + angleStep / 2) * RAD2DEG, 1.0f, 1.0f));
if (outline)
{
DrawTriangleLines(a, b, c, Color.Black);
DrawTriangleLines(c, b, d, Color.Black);
}
}
DrawLine(580, 0, 580, GetScreenHeight(), new Color(218, 218, 218, 255));
DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), new Color(232, 232, 232, 255));
// Draw GUI controls
//------------------------------------------------------------------------------
// NOTE: raygui is not bound in raylib-cs, so the interactive controls are omitted
// and 'segments'/'outline' keep their initial values.
//GuiSliderBar(new Rectangle(640, 40, 120, 20), "Segments", TextFormat("%.0f", segments), ref segments, 6.0f, 60.0f);
//GuiCheckBox(new Rectangle(640, 70, 20, 20), "Outline", ref outline);
//------------------------------------------------------------------------------
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - triangle strip");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new TriangleStrip();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,175 @@
/*******************************************************************************************
*
* raylib [shapes] example - vector angle
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 1.0, last time updated with raylib 5.0
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2023-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raymath; // Required for: Vector2LineAngle()
namespace Examples.Shapes;
public partial class VectorAngle : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Shapes / Vector Angle";
public string Title => "raylib [shapes] example - vector angle";
private Vector2 v0;
private Vector2 v1;
private Vector2 v2; // Updated with mouse position
private float angle; // Angle in degrees
private int angleMode; // 0-Vector2Angle(), 1-Vector2LineAngle()
public void Init()
{
v0 = new(screenWidth / 2.0f, screenHeight / 2.0f);
v1 = Vector2Add(v0, new Vector2(100.0f, 80.0f));
v2 = new(0, 0); // Updated with mouse position
angle = 0.0f; // Angle in degrees
angleMode = 0; // 0-Vector2Angle(), 1-Vector2LineAngle()
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
float startangle = 0.0f;
if (angleMode == 0)
{
startangle = -Vector2LineAngle(v0, v1) * RAD2DEG;
}
if (angleMode == 1)
{
startangle = 0.0f;
}
v2 = GetMousePosition();
if (IsKeyPressed(KeyboardKey.Space))
{
angleMode = (angleMode == 0) ? 1 : 0;
}
if ((angleMode == 0) && IsMouseButtonDown(MouseButton.Right))
{
v1 = GetMousePosition();
}
if (angleMode == 0)
{
// Calculate angle between two vectors, considering a common origin (v0)
Vector2 v1Normal = Vector2Normalize(Vector2Subtract(v1, v0));
Vector2 v2Normal = Vector2Normalize(Vector2Subtract(v2, v0));
angle = Vector2Angle(v1Normal, v2Normal) * RAD2DEG;
}
else if (angleMode == 1)
{
// Calculate angle defined by a two vectors line, in reference to horizontal line
angle = Vector2LineAngle(v0, v2) * RAD2DEG;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (angleMode == 0)
{
DrawText("MODE 0: Angle between V1 and V2", 10, 10, 20, Color.Black);
DrawText("Right Click to Move V2", 10, 30, 20, Color.DarkGray);
DrawLineEx(v0, v1, 2.0f, Color.Black);
DrawLineEx(v0, v2, 2.0f, Color.Red);
DrawCircleSector(v0, 40.0f, startangle, startangle + angle, 32, Fade(Color.Green, 0.6f));
}
else if (angleMode == 1)
{
DrawText("MODE 1: Angle formed by line V1 to V2", 10, 10, 20, Color.Black);
DrawLine(0, screenHeight / 2, screenWidth, screenHeight / 2, Color.LightGray);
DrawLineEx(v0, v2, 2.0f, Color.Red);
DrawCircleSector(v0, 40.0f, startangle, startangle - angle, 32, Fade(Color.Green, 0.6f));
}
DrawText("v0", (int)v0.X, (int)v0.Y, 10, Color.DarkGray);
// If the line from v0 to v1 would overlap the text, move it's position up 10
if (angleMode == 0 && Vector2Subtract(v0, v1).Y > 0.0f)
{
DrawText("v1", (int)v1.X, (int)v1.Y - 10, 10, Color.DarkGray);
}
if (angleMode == 0 && Vector2Subtract(v0, v1).Y < 0.0f)
{
DrawText("v1", (int)v1.X, (int)v1.Y, 10, Color.DarkGray);
}
// If angle mode 1, use v1 to emphasize the horizontal line
if (angleMode == 1)
{
DrawText("v1", (int)v0.X + 40, (int)v0.Y, 10, Color.DarkGray);
}
// position adjusted by -10 so it isn't hidden by cursor
DrawText("v2", (int)v2.X - 10, (int)v2.Y - 10, 10, Color.DarkGray);
DrawText("Press SPACE to change MODE", 460, 10, 20, Color.DarkGray);
DrawText($"ANGLE: {angle:F2}", 10, 70, 20, Color.Lime);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - vector angle");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new VectorAngle();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}