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:
parent
b207e633ae
commit
8c22e68c2a
236 changed files with 40405 additions and 10896 deletions
278
Examples/Shapes/BallPhysics.cs
Normal file
278
Examples/Shapes/BallPhysics.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
319
Examples/Shapes/BulletHell.cs
Normal file
319
Examples/Shapes/BulletHell.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
251
Examples/Shapes/ClockOfClocks.cs
Normal file
251
Examples/Shapes/ClockOfClocks.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
144
Examples/Shapes/DashedLine.cs
Normal file
144
Examples/Shapes/DashedLine.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
353
Examples/Shapes/DigitalClock.cs
Normal file
353
Examples/Shapes/DigitalClock.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
208
Examples/Shapes/DoublePendulum.cs
Normal file
208
Examples/Shapes/DoublePendulum.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
263
Examples/Shapes/EasingsTestbed.cs
Normal file
263
Examples/Shapes/EasingsTestbed.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
191
Examples/Shapes/EllipseCollision.cs
Normal file
191
Examples/Shapes/EllipseCollision.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
313
Examples/Shapes/HilbertCurve.cs
Normal file
313
Examples/Shapes/HilbertCurve.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
221
Examples/Shapes/Kaleidoscope.cs
Normal file
221
Examples/Shapes/Kaleidoscope.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
186
Examples/Shapes/LinesDrawing.cs
Normal file
186
Examples/Shapes/LinesDrawing.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
150
Examples/Shapes/MathAngleRotation.cs
Normal file
150
Examples/Shapes/MathAngleRotation.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
215
Examples/Shapes/MathSineCosine.cs
Normal file
215
Examples/Shapes/MathSineCosine.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
124
Examples/Shapes/MouseTrail.cs
Normal file
124
Examples/Shapes/MouseTrail.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
327
Examples/Shapes/PenroseTile.cs
Normal file
327
Examples/Shapes/PenroseTile.cs
Normal 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
462
Examples/Shapes/PieChart.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
282
Examples/Shapes/RectangleAdvanced.cs
Normal file
282
Examples/Shapes/RectangleAdvanced.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
228
Examples/Shapes/RecursiveTree.cs
Normal file
228
Examples/Shapes/RecursiveTree.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
363
Examples/Shapes/RlglColorWheel.cs
Normal file
363
Examples/Shapes/RlglColorWheel.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
217
Examples/Shapes/RlglTriangle.cs
Normal file
217
Examples/Shapes/RlglTriangle.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
347
Examples/Shapes/SimpleParticles.cs
Normal file
347
Examples/Shapes/SimpleParticles.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
461
Examples/Shapes/SplinesDrawing.cs
Normal file
461
Examples/Shapes/SplinesDrawing.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
191
Examples/Shapes/StarfieldEffect.cs
Normal file
191
Examples/Shapes/StarfieldEffect.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
458
Examples/Shapes/TopDownLights.cs
Normal file
458
Examples/Shapes/TopDownLights.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
137
Examples/Shapes/TriangleStrip.cs
Normal file
137
Examples/Shapes/TriangleStrip.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
175
Examples/Shapes/VectorAngle.cs
Normal file
175
Examples/Shapes/VectorAngle.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue