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

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

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

* chg: Modernize CI workflow, enable SourceLink

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

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

* chore: updated readme

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

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

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

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

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

* chore: readme updated

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

* fix: Wrong signature of FrameBufferComplete

* chore: readme update

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

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

* chore: readme, gitignore, and targets backport.

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

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

* chore: readme, gitignore, and targets backport.

* chore: clean up linter warnings

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

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

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

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

View file

@ -0,0 +1,419 @@
/*******************************************************************************************
*
* raylib [core] example - automation events
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.0, last time updated with raylib 5.0
*
* Example based on 2d_camera_platformer example by arvyy (@arvyy)
*
* 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.Core;
public partial class AutomationEvents : IExample
{
private const int GRAVITY = 400;
private const float PLAYER_JUMP_SPD = 350.0f;
private const float PLAYER_HOR_SPD = 200.0f;
private const int MAX_ENVIRONMENT_ELEMENTS = 5;
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Automation Events";
public string Title => "raylib [core] example - automation events";
private struct Player
{
public Vector2 Position;
public float Speed;
public bool CanJump;
}
private struct EnvElement
{
public Rectangle Rect;
public int Blocking;
public Color Color;
}
private Player player;
private EnvElement[] envElements;
private Camera2D camera;
private AutomationEventList aelist;
private bool eventRecording;
private bool eventPlaying;
private uint frameCounter;
private uint playFrameCounter;
private uint currentPlayFrame;
public unsafe void Init()
{
// Define player
player = new Player();
player.Position = new Vector2(400, 280);
player.Speed = 0;
player.CanJump = false;
// Define environment elements (platforms)
envElements = new EnvElement[MAX_ENVIRONMENT_ELEMENTS]
{
new EnvElement { Rect = new Rectangle(0, 0, 1000, 400), Blocking = 0, Color = Color.LightGray },
new EnvElement { Rect = new Rectangle(0, 400, 1000, 200), Blocking = 1, Color = Color.Gray },
new EnvElement { Rect = new Rectangle(300, 200, 400, 10), Blocking = 1, Color = Color.Gray },
new EnvElement { Rect = new Rectangle(250, 300, 100, 10), Blocking = 1, Color = Color.Gray },
new EnvElement { Rect = new Rectangle(650, 300, 100, 10), Blocking = 1, Color = Color.Gray }
};
// Define camera
camera = new Camera2D();
camera.Target = player.Position;
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
camera.Rotation = 0.0f;
camera.Zoom = 1.0f;
// Automation events
aelist = LoadAutomationEventList((sbyte*)null); // Initialize list of automation events to record new events
SetAutomationEventList(ref aelist);
eventRecording = false;
eventPlaying = false;
frameCounter = 0;
playFrameCounter = 0;
currentPlayFrame = 0;
}
public unsafe void Update()
{
// Update
//----------------------------------------------------------------------------------
float deltaTime = 0.015f;//GetFrameTime();
// Dropped files logic
//----------------------------------------------------------------------------------
#if BROWSER
// NOTE: drag-and-drop event-list loading (.txt/.rae) is not supported in the browser host.
#else
if (IsFileDropped())
{
FilePathList droppedFiles = LoadDroppedFiles();
// Supports loading .rgs style files (text or binary) and .png style palette images
if (IsFileExtension(droppedFiles[0], ".txt;.rae"))
{
UnloadAutomationEventList(aelist);
aelist = LoadAutomationEventList(droppedFiles[0]);
eventRecording = false;
// Reset scene state to play
eventPlaying = true;
playFrameCounter = 0;
currentPlayFrame = 0;
player.Position = new Vector2(400, 280);
player.Speed = 0;
player.CanJump = false;
camera.Target = player.Position;
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
camera.Rotation = 0.0f;
camera.Zoom = 1.0f;
}
UnloadDroppedFiles(droppedFiles); // Unload filepaths from memory
}
#endif
//----------------------------------------------------------------------------------
// Update player
//----------------------------------------------------------------------------------
if (IsKeyDown(KeyboardKey.Left))
{
player.Position.X -= PLAYER_HOR_SPD * deltaTime;
}
if (IsKeyDown(KeyboardKey.Right))
{
player.Position.X += PLAYER_HOR_SPD * deltaTime;
}
if (IsKeyDown(KeyboardKey.Space) && player.CanJump)
{
player.Speed = -PLAYER_JUMP_SPD;
player.CanJump = false;
}
int hitObstacle = 0;
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
{
EnvElement element = envElements[i];
if (element.Blocking != 0 &&
element.Rect.X <= player.Position.X &&
element.Rect.X + element.Rect.Width >= player.Position.X &&
element.Rect.Y >= player.Position.Y &&
element.Rect.Y <= player.Position.Y + player.Speed * deltaTime)
{
hitObstacle = 1;
player.Speed = 0.0f;
player.Position.Y = element.Rect.Y;
}
}
if (hitObstacle == 0)
{
player.Position.Y += player.Speed * deltaTime;
player.Speed += GRAVITY * deltaTime;
player.CanJump = false;
}
else
{
player.CanJump = true;
}
if (IsKeyPressed(KeyboardKey.R))
{
// Reset game state
player.Position = new Vector2(400, 280);
player.Speed = 0;
player.CanJump = false;
camera.Target = player.Position;
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
camera.Rotation = 0.0f;
camera.Zoom = 1.0f;
}
//----------------------------------------------------------------------------------
// Events playing
// NOTE: Logic must be before Camera update because it depends on mouse-wheel value,
// that can be set by the played event... but some other inputs could be affected
//----------------------------------------------------------------------------------
if (eventPlaying)
{
// NOTE: Multiple events could be executed in a single frame
while (playFrameCounter == aelist.Events[currentPlayFrame].Frame)
{
PlayAutomationEvent(aelist.Events[currentPlayFrame]);
currentPlayFrame++;
if (currentPlayFrame == aelist.Count)
{
eventPlaying = false;
currentPlayFrame = 0;
playFrameCounter = 0;
TraceLog(TraceLogLevel.Info, "FINISH PLAYING!");
break;
}
}
playFrameCounter++;
}
//----------------------------------------------------------------------------------
// Update camera
//----------------------------------------------------------------------------------
camera.Target = player.Position;
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000;
// WARNING: On event replay, mouse-wheel internal value is set
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
if (camera.Zoom > 3.0f)
{
camera.Zoom = 3.0f;
}
else if (camera.Zoom < 0.25f)
{
camera.Zoom = 0.25f;
}
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
{
EnvElement element = envElements[i];
minX = MathF.Min(element.Rect.X, minX);
maxX = MathF.Max(element.Rect.X + element.Rect.Width, maxX);
minY = MathF.Min(element.Rect.Y, minY);
maxY = MathF.Max(element.Rect.Y + element.Rect.Height, maxY);
}
Vector2 max = GetWorldToScreen2D(new Vector2(maxX, maxY), camera);
Vector2 min = GetWorldToScreen2D(new Vector2(minX, minY), camera);
if (max.X < screenWidth)
{
camera.Offset.X = screenWidth - (max.X - (float)screenWidth / 2);
}
if (max.Y < screenHeight)
{
camera.Offset.Y = screenHeight - (max.Y - (float)screenHeight / 2);
}
if (min.X > 0)
{
camera.Offset.X = (float)screenWidth / 2 - min.X;
}
if (min.Y > 0)
{
camera.Offset.Y = (float)screenHeight / 2 - min.Y;
}
//----------------------------------------------------------------------------------
// Events management
if (IsKeyPressed(KeyboardKey.S)) // Toggle events recording
{
if (!eventPlaying)
{
if (eventRecording)
{
StopAutomationEventRecording();
eventRecording = false;
ExportAutomationEventList(aelist, "automation.rae");
TraceLog(TraceLogLevel.Info, $"RECORDED FRAMES: {aelist.Count}");
}
else
{
SetAutomationEventBaseFrame(180);
StartAutomationEventRecording();
eventRecording = true;
}
}
}
else if (IsKeyPressed(KeyboardKey.A)) // Toggle events playing (WARNING: Starts next frame)
{
if (!eventRecording && (aelist.Count > 0))
{
// Reset scene state to play
eventPlaying = true;
playFrameCounter = 0;
currentPlayFrame = 0;
player.Position = new Vector2(400, 280);
player.Speed = 0;
player.CanJump = false;
camera.Target = player.Position;
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
camera.Rotation = 0.0f;
camera.Zoom = 1.0f;
}
}
if (eventRecording || eventPlaying)
{
frameCounter++;
}
else
{
frameCounter = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.LightGray);
BeginMode2D(camera);
// Draw environment elements
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
{
DrawRectangleRec(envElements[i].Rect, envElements[i].Color);
}
// Draw player rectangle
DrawRectangleRec(new Rectangle(player.Position.X - 20, player.Position.Y - 40, 40, 40), Color.Red);
EndMode2D();
// Draw game controls
DrawRectangle(10, 10, 290, 145, Fade(Color.SkyBlue, 0.5f));
DrawRectangleLines(10, 10, 290, 145, Fade(Color.Blue, 0.8f));
DrawText("Controls:", 20, 20, 10, Color.Black);
DrawText("- RIGHT | LEFT: Player movement", 30, 40, 10, Color.DarkGray);
DrawText("- SPACE: Player jump", 30, 60, 10, Color.DarkGray);
DrawText("- R: Reset game state", 30, 80, 10, Color.DarkGray);
DrawText("- S: START/STOP RECORDING INPUT EVENTS", 30, 110, 10, Color.Black);
DrawText("- A: REPLAY LAST RECORDED INPUT EVENTS", 30, 130, 10, Color.Black);
// Draw automation events recording indicator
if (eventRecording)
{
DrawRectangle(10, 160, 290, 30, Fade(Color.Red, 0.3f));
DrawRectangleLines(10, 160, 290, 30, Fade(Color.Maroon, 0.8f));
DrawCircle(30, 175, 10, Color.Maroon);
if (((frameCounter / 15) % 2) == 1)
{
DrawText($"RECORDING EVENTS... [{aelist.Count}]", 50, 170, 10, Color.Maroon);
}
}
else if (eventPlaying)
{
DrawRectangle(10, 160, 290, 30, Fade(Color.Lime, 0.3f));
DrawRectangleLines(10, 160, 290, 30, Fade(Color.DarkGreen, 0.8f));
DrawTriangle(new Vector2(20, 155 + 10), new Vector2(20, 155 + 30), new Vector2(40, 155 + 20), Color.DarkGreen);
if (((frameCounter / 15) % 2) == 1)
{
DrawText($"PLAYING RECORDED EVENTS... [{currentPlayFrame}]", 50, 170, 10, Color.DarkGreen);
}
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadAutomationEventList(aelist);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - automation events");
var game = new AutomationEvents();
game.Init();
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose())
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,29 +1,23 @@
/*******************************************************************************************
*
* raylib [core] example - Basic window
* raylib [core] example - basic screen manager
*
* Welcome to raylib!
* Example complexity rating: [] 1/4
*
* To test examples, just press F6 and execute raylib_compile_execute script
* Note that compiled executable is placed in the same folder as .c file
* NOTE: This example illustrates a very simple screen manager based on a states machines
*
* You can find all basic examples on C:\raylib\raylib\examples folder or
* raylib official webpage: www.raylib.com
* Example originally created with raylib 4.0, last time updated with raylib 4.0
*
* Enjoy using raylib. :)
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* 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)
*
* Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
* Copyright (c) 2021-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Core;
enum GameScreen
internal enum GameScreen
{
Logo = 0,
Title,
@ -31,143 +25,160 @@ enum GameScreen
Ending
}
public class BasicScreenManager
public partial class BasicScreenManager : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Basic Screen Manager";
public string Title => "raylib [core] example - basic screen manager";
private GameScreen currentScreen;
private int framesCounter;
public void Init()
{
currentScreen = GameScreen.Logo;
// TODO: Initialize all required variables and load all required data here!
framesCounter = 0; // Useful to count frames
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
switch (currentScreen)
{
case GameScreen.Logo:
{
// TODO: Update LOGO screen variables here!
framesCounter++; // Count frames
// Wait for 2 seconds (120 frames) before jumping to TITLE screen
if (framesCounter > 120)
{
currentScreen = GameScreen.Title;
}
}
break;
case GameScreen.Title:
{
// TODO: Update TITLE screen variables here!
// Press enter to change to GAMEPLAY screen
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
{
currentScreen = GameScreen.Gameplay;
}
}
break;
case GameScreen.Gameplay:
{
// TODO: Update GAMEPLAY screen variables here!
// Press enter to change to ENDING screen
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
{
currentScreen = GameScreen.Ending;
}
}
break;
case GameScreen.Ending:
{
// TODO: Update ENDING screen variables here!
// Press enter to return to TITLE screen
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
{
currentScreen = GameScreen.Title;
}
}
break;
default:
break;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
switch (currentScreen)
{
case GameScreen.Logo:
{
// TODO: Draw LOGO screen here!
DrawText("LOGO SCREEN", 20, 20, 40, Color.LightGray);
DrawText("WAIT for 2 SECONDS...", 290, 220, 20, Color.Gray);
}
break;
case GameScreen.Title:
{
// TODO: Draw TITLE screen here!
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Green);
DrawText("TITLE SCREEN", 20, 20, 40, Color.DarkGreen);
DrawText("PRESS ENTER or TAP to JUMP to GAMEPLAY SCREEN", 120, 220, 20, Color.DarkGreen);
}
break;
case GameScreen.Gameplay:
{
// TODO: Draw GAMEPLAY screen here!
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Purple);
DrawText("GAMEPLAY SCREEN", 20, 20, 40, Color.Maroon);
DrawText("PRESS ENTER or TAP to JUMP to ENDING SCREEN", 130, 220, 20, Color.Maroon);
}
break;
case GameScreen.Ending:
{
// TODO: Draw ENDING screen here!
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Blue);
DrawText("ENDING SCREEN", 20, 20, 40, Color.DarkBlue);
DrawText("PRESS ENTER or TAP to RETURN to TITLE SCREEN", 120, 220, 20, Color.DarkBlue);
}
break;
default:
break;
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
// TODO: Unload all loaded data (textures, fonts, audio) here!
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic screen manager");
GameScreen currentScreen = GameScreen.Logo;
// TODO: Initialize all required variables and load all required data here!
// Useful to count frames
int framesCounter = 0;
SetTargetFPS(60); // Set desired framerate (frames-per-second)
//--------------------------------------------------------------------------------------
var game = new BasicScreenManager();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
switch (currentScreen)
{
case GameScreen.Logo:
{
// TODO: Update LOGO screen variables here!
// Count frames
framesCounter++;
// Wait for 2 seconds (120 frames) before jumping to TITLE screen
if (framesCounter > 120)
{
currentScreen = GameScreen.Title;
}
}
break;
case GameScreen.Title:
{
// TODO: Update TITLE screen variables here!
// Press enter to change to GAMEPLAY screen
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
{
currentScreen = GameScreen.Gameplay;
}
}
break;
case GameScreen.Gameplay:
{
// TODO: Update GAMEPLAY screen variables here!
// Press enter to change to ENDING screen
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
{
currentScreen = GameScreen.Ending;
}
}
break;
case GameScreen.Ending:
{
// TODO: Update ENDING screen variables here!
// Press enter to return to TITLE screen
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
{
currentScreen = GameScreen.Title;
}
}
break;
default:
break;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
switch (currentScreen)
{
case GameScreen.Logo:
{
// TODO: Draw LOGO screen here!
DrawText("LOGO SCREEN", 20, 20, 40, Color.LightGray);
DrawText("WAIT for 2 SECONDS...", 290, 220, 20, Color.Gray);
}
break;
case GameScreen.Title:
{
// TODO: Draw TITLE screen here!
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Green);
DrawText("TITLE SCREEN", 20, 20, 40, Color.DarkGreen);
DrawText("PRESS ENTER or TAP to JUMP to GAMEPLAY SCREEN", 120, 220, 20, Color.DarkGreen);
}
break;
case GameScreen.Gameplay:
{
// TODO: Draw GAMEPLAY screen here!
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Purple);
DrawText("GAMEPLAY SCREEN", 20, 20, 40, Color.Maroon);
DrawText("PRESS ENTER or TAP to JUMP to ENDING SCREEN", 130, 220, 20, Color.Maroon);
}
break;
case GameScreen.Ending:
{
// TODO: Draw ENDING screen here!
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Blue);
DrawText("ENDING SCREEN", 20, 20, 40, Color.DarkBlue);
DrawText("PRESS ENTER or TAP to RETURN to TITLE SCREEN", 120, 220, 20, Color.DarkBlue);
}
break;
default:
break;
}
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
// TODO: Unload all loaded data (textures, fonts, audio) here!
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -26,50 +26,58 @@
*
********************************************************************************************/
using System.Numerics;
using System;
using System.Text;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class BasicWindow
public partial class BasicWindow : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Basic Window";
public string Title => "raylib [core] example - basic window";
public void Init()
{
}
public void Update()
{
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("Congrats! You created your first window!", 190, 200, 20, Color.LightGray);
EndDrawing();
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
var game = new BasicWindow();
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("Congrats! You created your first window!", 190, 200, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
return 0;
}

View file

@ -13,31 +13,33 @@
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class Camera2dDemo
public partial class Camera2dDemo : IExample
{
public const int MaxBuildings = 100;
public static int Main()
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Camera 2D Demo";
public string Title => "raylib [core] example - 2d camera";
private Rectangle player;
private Rectangle[] buildings;
private Color[] buildColors;
private Camera2D camera;
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
player = new(400, 280, 40, 40);
buildings = new Rectangle[MaxBuildings];
buildColors = new Color[MaxBuildings];
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
var spacing = 0;
Rectangle player = new(400, 280, 40, 40);
Rectangle[] buildings = new Rectangle[MaxBuildings];
Color[] buildColors = new Color[MaxBuildings];
int spacing = 0;
for (int i = 0; i < MaxBuildings; i++)
for (var i = 0; i < MaxBuildings; i++)
{
buildings[i].Width = GetRandomValue(50, 200);
buildings[i].Height = GetRandomValue(100, 800);
@ -54,124 +56,139 @@ public class Camera2dDemo
);
}
Camera2D camera = new();
camera = new();
camera.Target = new Vector2(player.X + 20, player.Y + 20);
camera.Offset = new Vector2(screenWidth / 2, screenHeight / 2);
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
camera.Rotation = 0.0f;
camera.Zoom = 1.0f;
}
SetTargetFPS(60);
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Player movement
if (IsKeyDown(KeyboardKey.Right))
{
player.X += 2;
}
else if (IsKeyDown(KeyboardKey.Left))
{
player.X -= 2;
}
// Camera target follows player
camera.Target = new Vector2(player.X + 20, player.Y + 20);
// Camera rotation controls
if (IsKeyDown(KeyboardKey.A))
{
camera.Rotation--;
}
else if (IsKeyDown(KeyboardKey.S))
{
camera.Rotation++;
}
// Limit camera rotation to 80 degrees (-40 to 40)
if (camera.Rotation > 40)
{
camera.Rotation = 40;
}
else if (camera.Rotation < -40)
{
camera.Rotation = -40;
}
// Camera zoom controls
// Uses log scaling to provide consistent zoom speed
camera.Zoom = MathF.Exp(MathF.Log(camera.Zoom) + ((float)GetMouseWheelMove() * 0.1f));
if (camera.Zoom > 3.0f)
{
camera.Zoom = 3.0f;
}
else if (camera.Zoom < 0.1f)
{
camera.Zoom = 0.1f;
}
// Camera reset (zoom and rotation)
if (IsKeyPressed(KeyboardKey.R))
{
camera.Zoom = 1.0f;
camera.Rotation = 0.0f;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode2D(camera);
DrawRectangle(-6000, 320, 13000, 8000, Color.DarkGray);
for (var i = 0; i < MaxBuildings; i++)
{
DrawRectangleRec(buildings[i], buildColors[i]);
}
DrawRectangleRec(player, Color.Red);
DrawLine((int)camera.Target.X, -screenHeight * 10, (int)camera.Target.X, screenHeight * 10, Color.Green);
DrawLine(-screenWidth * 10, (int)camera.Target.Y, screenWidth * 10, (int)camera.Target.Y, Color.Green);
EndMode2D();
DrawText("SCREEN AREA", 640, 10, 20, Color.Red);
DrawRectangle(0, 0, screenWidth, 5, Color.Red);
DrawRectangle(0, 5, 5, screenHeight - 10, Color.Red);
DrawRectangle(screenWidth - 5, 5, 5, screenHeight - 10, Color.Red);
DrawRectangle(0, screenHeight - 5, screenWidth, 5, Color.Red);
DrawRectangle(10, 10, 250, 113, Fade(Color.SkyBlue, 0.5f));
DrawRectangleLines(10, 10, 250, 113, Color.Blue);
DrawText("Free 2D camera controls:", 20, 20, 10, Color.Black);
DrawText("- Right/Left to move player", 40, 40, 10, Color.DarkGray);
DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, Color.DarkGray);
DrawText("- A / S to Rotate", 40, 80, 10, Color.DarkGray);
DrawText("- R to reset Zoom and Rotation", 40, 100, 10, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new Camera2dDemo();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// Player movement
if (IsKeyDown(KeyboardKey.Right))
{
player.X += 2;
}
else if (IsKeyDown(KeyboardKey.Left))
{
player.X -= 2;
}
// Camera3D target follows player
camera.Target = new Vector2(player.X + 20, player.Y + 20);
// Camera3D rotation controls
if (IsKeyDown(KeyboardKey.A))
{
camera.Rotation--;
}
else if (IsKeyDown(KeyboardKey.S))
{
camera.Rotation++;
}
// Limit camera rotation to 80 degrees (-40 to 40)
if (camera.Rotation > 40)
{
camera.Rotation = 40;
}
else if (camera.Rotation < -40)
{
camera.Rotation = -40;
}
// Camera3D zoom controls
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
if (camera.Zoom > 3.0f)
{
camera.Zoom = 3.0f;
}
else if (camera.Zoom < 0.1f)
{
camera.Zoom = 0.1f;
}
// Camera3D reset (zoom and rotation)
if (IsKeyPressed(KeyboardKey.R))
{
camera.Zoom = 1.0f;
camera.Rotation = 0.0f;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode2D(camera);
DrawRectangle(-6000, 320, 13000, 8000, Color.DarkGray);
for (int i = 0; i < MaxBuildings; i++)
{
DrawRectangleRec(buildings[i], buildColors[i]);
}
DrawRectangleRec(player, Color.Red);
DrawRectangle((int)camera.Target.X, -500, 1, (int)(screenHeight * 4), Color.Green);
DrawLine(
(int)(-screenWidth * 10),
(int)camera.Target.Y,
(int)(screenWidth * 10),
(int)camera.Target.Y,
Color.Green
);
EndMode2D();
DrawText("SCREEN AREA", 640, 10, 20, Color.Red);
DrawRectangle(0, 0, (int)screenWidth, 5, Color.Red);
DrawRectangle(0, 5, 5, (int)screenHeight - 10, Color.Red);
DrawRectangle((int)screenWidth - 5, 5, 5, (int)screenHeight - 10, Color.Red);
DrawRectangle(0, (int)screenHeight - 5, (int)screenWidth, 5, Color.Red);
DrawRectangle(10, 10, 250, 113, ColorAlpha(Color.SkyBlue, 0.5f));
DrawRectangleLines(10, 10, 250, 113, Color.Blue);
DrawText("Free 2d camera controls:", 20, 20, 10, Color.Black);
DrawText("- Right/Left to move Offset", 40, 40, 10, Color.DarkGray);
DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, Color.DarkGray);
DrawText("- A / S to Rotate", 40, 80, 10, Color.DarkGray);
DrawText("- R to reset Zoom and Rotation", 40, 100, 10, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,181 @@
/*******************************************************************************************
*
* raylib [core] example - 2d camera mouse zoom
*
* Example complexity rating: [] 2/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;
namespace Examples.Core;
public partial class Camera2dMouseZoom : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Camera 2D Mouse Zoom";
public string Title => "raylib [core] example - 2d camera mouse zoom";
private Camera2D camera;
private int zoomMode; // 0-Mouse Wheel, 1-Mouse Move
public void Init()
{
camera = new Camera2D();
camera.Zoom = 1.0f;
zoomMode = 0;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.One))
{
zoomMode = 0;
}
else if (IsKeyPressed(KeyboardKey.Two))
{
zoomMode = 1;
}
// Translate based on mouse right click
if (IsMouseButtonDown(MouseButton.Left))
{
Vector2 delta = GetMouseDelta();
delta = Vector2Scale(delta, -1.0f / camera.Zoom);
camera.Target = Vector2Add(camera.Target, delta);
}
if (zoomMode == 0)
{
// Zoom based on mouse wheel
float wheel = GetMouseWheelMove();
if (wheel != 0)
{
// Get the world point that is under the mouse
Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera);
// Set the offset to where the mouse is
camera.Offset = GetMousePosition();
// Set the target to match, so that the camera maps the world space point
// under the cursor to the screen space point under the cursor at any zoom
camera.Target = mouseWorldPos;
// Zoom increment
// Uses log scaling to provide consistent zoom speed
float scale = 0.2f * wheel;
camera.Zoom = Clamp(MathF.Exp(MathF.Log(camera.Zoom) + scale), 0.125f, 64.0f);
}
}
else
{
// Zoom based on mouse right click
if (IsMouseButtonPressed(MouseButton.Right))
{
// Get the world point that is under the mouse
Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera);
// Set the offset to where the mouse is
camera.Offset = GetMousePosition();
// Set the target to match, so that the camera maps the world space point
// under the cursor to the screen space point under the cursor at any zoom
camera.Target = mouseWorldPos;
}
if (IsMouseButtonDown(MouseButton.Right))
{
// Zoom increment
// Uses log scaling to provide consistent zoom speed
float deltaX = GetMouseDelta().X;
float scale = 0.005f * deltaX;
camera.Zoom = Clamp(MathF.Exp(MathF.Log(camera.Zoom) + scale), 0.125f, 64.0f);
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode2D(camera);
// Draw the 3d grid, rotated 90 degrees and centered around 0,0
// just so we have something in the XY plane
Rlgl.PushMatrix();
Rlgl.Translatef(0, 25 * 50, 0);
Rlgl.Rotatef(90, 1, 0, 0);
DrawGrid(100, 50);
Rlgl.PopMatrix();
// Draw a reference circle
DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, 50, Color.Maroon);
EndMode2D();
// Draw mouse reference
//Vector2 mousePos = GetWorldToScreen2D(GetMousePosition(), camera)
DrawCircleV(GetMousePosition(), 4, Color.DarkGray);
DrawTextEx(GetFontDefault(), $"[{GetMouseX()}, {GetMouseY()}]",
Vector2Add(GetMousePosition(), new Vector2(-44, -24)), 20, 2, Color.Black);
DrawText("[1][2] Select mouse zoom mode (Wheel or Move)", 20, 20, 20, Color.DarkGray);
if (zoomMode == 0)
{
DrawText("Mouse left button drag to move, mouse wheel to zoom", 20, 50, 20, Color.DarkGray);
}
else
{
DrawText("Mouse left button drag to move, mouse press and move to zoom", 20, 50, 20, Color.DarkGray);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera mouse zoom");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new Camera2dMouseZoom();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -2,36 +2,44 @@
*
* raylib [core] example - 2d camera platformer
*
* 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 3.0
*
* Example contributed by arvyy (@arvyy) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2019 arvyy (@arvyy)
* 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 arvyy (@arvyy)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
using static Raylib_cs.Raymath;
namespace Examples.Core;
public class Camera2dPlatformer
public partial class Camera2dPlatformer : IExample
{
const int G = 400;
const float PlayerJumpSpeed = 350.0f;
const float PlayerHorSpeed = 200.0f;
private const int screenWidth = 800;
private const int screenHeight = 450;
struct Player
private const int G = 400;
private const float PlayerJumpSpeed = 350.0f;
private const float PlayerHorSpeed = 200.0f;
public string Name => "Core / 2D Camera Platformer";
public string Title => "raylib [core] example - 2d camera platformer";
private struct Player
{
public Vector2 Position;
public float Speed;
public bool CanJump;
}
struct EnvItem
private struct EnvItem
{
public Rectangle Rect;
public int Blocking;
@ -45,7 +53,7 @@ public class Camera2dPlatformer
}
}
delegate void CameraUpdaterCallback(
private delegate void CameraUpdaterCallback(
ref Camera2D camera,
ref Player player,
EnvItem[] envItems,
@ -54,21 +62,22 @@ public class Camera2dPlatformer
int height
);
public static int Main()
private Player player;
private EnvItem[] envItems;
private Camera2D camera;
private CameraUpdaterCallback[] cameraUpdaters;
private int cameraOption;
private int cameraUpdatersLength;
private string[] cameraDescriptions;
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
Player player = new();
player = new();
player.Position = new Vector2(400, 280);
player.Speed = 0;
player.CanJump = false;
EnvItem[] envItems = new EnvItem[]
envItems = new EnvItem[]
{
new EnvItem(new Rectangle(0, 0, 1000, 400), 0, Color.LightGray),
new EnvItem(new Rectangle(0, 400, 1000, 200), 1, Color.Gray),
@ -77,14 +86,14 @@ public class Camera2dPlatformer
new EnvItem(new Rectangle(650, 300, 100, 10), 1, Color.Gray)
};
Camera2D camera = new();
camera = new();
camera.Target = player.Position;
camera.Offset = new Vector2(screenWidth / 2, screenHeight / 2);
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
camera.Rotation = 0.0f;
camera.Zoom = 1.0f;
// Store callbacks to the multiple update camera functions
CameraUpdaterCallback[] cameraUpdaters = new CameraUpdaterCallback[]
// Store pointers to the multiple update camera functions
cameraUpdaters = new CameraUpdaterCallback[]
{
UpdateCameraCenter,
UpdateCameraCenterInsideMap,
@ -93,93 +102,89 @@ public class Camera2dPlatformer
UpdateCameraPlayerBoundsPush
};
int cameraOption = 0;
int cameraUpdatersLength = cameraUpdaters.Length;
cameraOption = 0;
cameraUpdatersLength = cameraUpdaters.Length;
string[] cameraDescriptions = new string[]{
cameraDescriptions = new string[]{
"Follow player center",
"Follow player center, but clamp to map edges",
"Follow player center; smoothed",
"Follow player center horizontally; update player center vertically after landing",
"Player push camera on getting too close to screen edge"
};
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose())
{
// Update
//----------------------------------------------------------------------------------
float deltaTime = GetFrameTime();
UpdatePlayer(ref player, envItems, deltaTime);
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
if (camera.Zoom > 3.0f)
{
camera.Zoom = 3.0f;
}
else if (camera.Zoom < 0.25f)
{
camera.Zoom = 0.25f;
}
if (IsKeyPressed(KeyboardKey.R))
{
camera.Zoom = 1.0f;
player.Position = new Vector2(400, 280);
}
if (IsKeyPressed(KeyboardKey.C))
{
cameraOption = (cameraOption + 1) % cameraUpdatersLength;
}
// Call update camera function by its pointer
cameraUpdaters[cameraOption](ref camera, ref player, envItems, deltaTime, screenWidth, screenHeight);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.LightGray);
BeginMode2D(camera);
for (int i = 0; i < envItems.Length; i++)
{
DrawRectangleRec(envItems[i].Rect, envItems[i].Color);
}
Rectangle playerRect = new(player.Position.X - 20, player.Position.Y - 40, 40, 40);
DrawRectangleRec(playerRect, Color.Red);
EndMode2D();
DrawText("Controls:", 20, 20, 10, Color.Black);
DrawText("- Right/Left to move", 40, 40, 10, Color.DarkGray);
DrawText("- Space to jump", 40, 60, 10, Color.DarkGray);
DrawText("- Mouse Wheel to Zoom in-out, R to reset zoom", 40, 80, 10, Color.DarkGray);
DrawText("- C to change camera mode", 40, 100, 10, Color.DarkGray);
DrawText("Current camera mode:", 20, 120, 10, Color.Black);
DrawText(cameraDescriptions[cameraOption], 40, 140, 10, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
//--------------------------------------------------------------------------------------
return 0;
}
static void UpdatePlayer(ref Player player, EnvItem[] envItems, float delta)
public void Update()
{
// Update
//----------------------------------------------------------------------------------
var deltaTime = GetFrameTime();
UpdatePlayer(ref player, envItems, deltaTime);
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
if (camera.Zoom > 3.0f)
{
camera.Zoom = 3.0f;
}
else if (camera.Zoom < 0.25f)
{
camera.Zoom = 0.25f;
}
if (IsKeyPressed(KeyboardKey.R))
{
camera.Zoom = 1.0f;
player.Position = new Vector2(400, 280);
}
if (IsKeyPressed(KeyboardKey.C))
{
cameraOption = (cameraOption + 1) % cameraUpdatersLength;
}
// Call update camera function by its pointer
cameraUpdaters[cameraOption](ref camera, ref player, envItems, deltaTime, screenWidth, screenHeight);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.LightGray);
BeginMode2D(camera);
for (var i = 0; i < envItems.Length; i++)
{
DrawRectangleRec(envItems[i].Rect, envItems[i].Color);
}
Rectangle playerRect = new(player.Position.X - 20, player.Position.Y - 40, 40.0f, 40.0f);
DrawRectangleRec(playerRect, Color.Red);
DrawCircleV(player.Position, 5.0f, Color.Gold);
EndMode2D();
DrawText("Controls:", 20, 20, 10, Color.Black);
DrawText("- Right/Left to move", 40, 40, 10, Color.DarkGray);
DrawText("- Space to jump", 40, 60, 10, Color.DarkGray);
DrawText("- Mouse Wheel to Zoom in-out", 40, 80, 10, Color.DarkGray);
DrawText("- R to reset position + zoom", 40, 100, 10, Color.DarkGray);
DrawText("- C to change camera mode", 40, 120, 10, Color.DarkGray);
DrawText("Current camera mode:", 20, 140, 10, Color.Black);
DrawText(cameraDescriptions[cameraOption], 40, 160, 10, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
private static void UpdatePlayer(ref Player player, EnvItem[] envItems, float delta)
{
if (IsKeyDown(KeyboardKey.Left))
{
@ -197,11 +202,11 @@ public class Camera2dPlatformer
player.CanJump = false;
}
int hitObstacle = 0;
for (int i = 0; i < envItems.Length; i++)
var hitObstacle = 0;
for (var i = 0; i < envItems.Length; i++)
{
EnvItem ei = envItems[i];
Vector2 p = player.Position;
var ei = envItems[i];
var p = player.Position;
if (ei.Blocking != 0 &&
ei.Rect.X <= p.X &&
ei.Rect.X + ei.Rect.Width >= p.X &&
@ -211,6 +216,7 @@ public class Camera2dPlatformer
hitObstacle = 1;
player.Speed = 0.0f;
player.Position.Y = ei.Rect.Y;
break;
}
}
@ -226,7 +232,7 @@ public class Camera2dPlatformer
}
}
static void UpdateCameraCenter(
private static void UpdateCameraCenter(
ref Camera2D camera,
ref Player player,
EnvItem[] envItems,
@ -235,11 +241,11 @@ public class Camera2dPlatformer
int height
)
{
camera.Offset = new Vector2(width / 2, height / 2);
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
camera.Target = player.Position;
}
static void UpdateCameraCenterInsideMap(
private static void UpdateCameraCenterInsideMap(
ref Camera2D camera,
ref Player player,
EnvItem[] envItems,
@ -248,43 +254,43 @@ public class Camera2dPlatformer
int height)
{
camera.Target = player.Position;
camera.Offset = new Vector2(width / 2, height / 2);
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000;
for (int i = 0; i < envItems.Length; i++)
for (var i = 0; i < envItems.Length; i++)
{
EnvItem ei = envItems[i];
var ei = envItems[i];
minX = Math.Min(ei.Rect.X, minX);
maxX = Math.Max(ei.Rect.X + ei.Rect.Width, maxX);
minY = Math.Min(ei.Rect.Y, minY);
maxY = Math.Max(ei.Rect.Y + ei.Rect.Height, maxY);
}
Vector2 max = GetWorldToScreen2D(new Vector2(maxX, maxY), camera);
Vector2 min = GetWorldToScreen2D(new Vector2(minX, minY), camera);
var max = GetWorldToScreen2D(new Vector2(maxX, maxY), camera);
var min = GetWorldToScreen2D(new Vector2(minX, minY), camera);
if (max.X < width)
{
camera.Offset.X = width - (max.X - width / 2);
camera.Offset.X = width - (max.X - width / 2.0f);
}
if (max.Y < height)
{
camera.Offset.Y = height - (max.Y - height / 2);
camera.Offset.Y = height - (max.Y - height / 2.0f);
}
if (min.X > 0)
{
camera.Offset.X = width / 2 - min.X;
camera.Offset.X = width / 2.0f - min.X;
}
if (min.Y > 0)
{
camera.Offset.Y = height / 2 - min.Y;
camera.Offset.Y = height / 2.0f - min.Y;
}
}
static void UpdateCameraCenterSmoothFollow(
private static void UpdateCameraCenterSmoothFollow(
ref Camera2D camera,
ref Player player,
EnvItem[] envItems,
@ -297,18 +303,18 @@ public class Camera2dPlatformer
const float minEffectLength = 10;
const float fractionSpeed = 0.8f;
camera.Offset = new Vector2(width / 2, height / 2);
Vector2 diff = Vector2Subtract(player.Position, camera.Target);
float length = Vector2Length(diff);
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
var diff = Vector2Subtract(player.Position, camera.Target);
var length = Vector2Length(diff);
if (length > minEffectLength)
{
float speed = Math.Max(fractionSpeed * length, minSpeed);
var speed = Math.Max(fractionSpeed * length, minSpeed);
camera.Target = Vector2Add(camera.Target, Vector2Scale(diff, speed * delta / length));
}
}
static void UpdateCameraEvenOutOnLanding(
private static void UpdateCameraEvenOutOnLanding(
ref Camera2D camera,
ref Player player,
EnvItem[] envItems,
@ -318,10 +324,10 @@ public class Camera2dPlatformer
)
{
float evenOutSpeed = 700;
int eveningOut = 0;
float evenOutTarget = 0.0f;
var eveningOut = 0;
var evenOutTarget = 0.0f;
camera.Offset = new Vector2(width / 2, height / 2);
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
camera.Target.X = player.Position.X;
if (eveningOut != 0)
@ -357,7 +363,7 @@ public class Camera2dPlatformer
}
}
static void UpdateCameraPlayerBoundsPush(
private static void UpdateCameraPlayerBoundsPush(
ref Camera2D camera,
ref Player player,
EnvItem[] envItems,
@ -368,11 +374,11 @@ public class Camera2dPlatformer
{
Vector2 bbox = new(0.2f, 0.2f);
Vector2 bboxWorldMin = GetScreenToWorld2D(
var bboxWorldMin = GetScreenToWorld2D(
new Vector2((1 - bbox.X) * 0.5f * width, (1 - bbox.Y) * 0.5f * height),
camera
);
Vector2 bboxWorldMax = GetScreenToWorld2D(
var bboxWorldMax = GetScreenToWorld2D(
new Vector2((1 + bbox.X) * 0.5f * width,
(1 + bbox.Y) * 0.5f * height),
camera
@ -399,4 +405,32 @@ public class Camera2dPlatformer
camera.Target.Y = bboxWorldMin.Y + (player.Position.Y - bboxWorldMax.Y);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera platformer");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new Camera2dPlatformer();
game.Init();
// Main game loop
while (!WindowShouldClose())
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -2,183 +2,215 @@
*
* raylib [core] example - 3d camera first person
*
* This example has been created using raylib 1.3 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.3, last time updated with raylib 1.3
*
* 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) 2015-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class Camera3dFirstPerson
public partial class Camera3dFirstPerson : IExample
{
public const int MaxColumns = 20;
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Camera 3D First Person";
public string Title => "raylib [core] example - 3d camera first person";
public bool CursorDisabled => true;
private Camera3D camera;
private CameraMode cameraMode;
private float[] heights;
private Vector3[] positions;
private Color[] colors;
public void Init()
{
// Define the camera to look into our 3d world (position, target, up vector)
camera = new();
camera.Position = new Vector3(0.0f, 2.0f, 4.0f); // Camera position
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
camera.FovY = 60.0f; // Camera field-of-view Y
camera.Projection = CameraProjection.Perspective; // Camera projection type
cameraMode = CameraMode.FirstPerson;
// Generates some random columns
heights = new float[MaxColumns];
positions = new Vector3[MaxColumns];
colors = new Color[MaxColumns];
for (var i = 0; i < MaxColumns; i++)
{
heights[i] = (float)GetRandomValue(1, 12);
positions[i] = new Vector3(GetRandomValue(-15, 15), heights[i] / 2.0f, GetRandomValue(-15, 15));
colors[i] = new Color(GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255);
}
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Switch camera mode
if (IsKeyPressed(KeyboardKey.One))
{
cameraMode = CameraMode.Free;
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
}
if (IsKeyPressed(KeyboardKey.Two))
{
cameraMode = CameraMode.FirstPerson;
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
}
if (IsKeyPressed(KeyboardKey.Three))
{
cameraMode = CameraMode.ThirdPerson;
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
}
if (IsKeyPressed(KeyboardKey.Four))
{
cameraMode = CameraMode.Orbital;
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
}
// Switch camera projection
if (IsKeyPressed(KeyboardKey.P))
{
if (camera.Projection == CameraProjection.Perspective)
{
// Create isometric view
cameraMode = CameraMode.ThirdPerson;
// Note: The target distance is related to the render distance in the orthographic projection
camera.Position = new Vector3(0.0f, 2.0f, -100.0f);
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.Projection = CameraProjection.Orthographic;
camera.FovY = 20.0f; // near plane width in CAMERA_ORTHOGRAPHIC
// CameraYaw(&camera, -135 * DEG2RAD, true);
// CameraPitch(&camera, -45 * DEG2RAD, true, true, false);
}
else if (camera.Projection == CameraProjection.Orthographic)
{
// Reset to default view
cameraMode = CameraMode.ThirdPerson;
camera.Position = new Vector3(0.0f, 2.0f, 10.0f);
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.Projection = CameraProjection.Perspective;
camera.FovY = 60.0f;
}
}
// Update camera computes movement internally depending on the camera mode
// Some default standard keyboard/mouse inputs are hardcoded to simplify use
// For advanced camera controls, it's recommended to compute camera movement manually
UpdateCamera(ref camera, cameraMode); // Update camera
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
// Draw ground
DrawPlane(new Vector3(0.0f, 0.0f, 0.0f), new Vector2(32.0f, 32.0f), Color.LightGray);
// Draw a blue wall
DrawCube(new Vector3(-16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Blue);
// Draw a green wall
DrawCube(new Vector3(16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Lime);
// Draw a yellow wall
DrawCube(new Vector3(0.0f, 2.5f, 16.0f), 32.0f, 5.0f, 1.0f, Color.Gold);
// Draw some cubes around
for (var i = 0; i < MaxColumns; i++)
{
DrawCube(positions[i], 2.0f, heights[i], 2.0f, colors[i]);
DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, Color.Maroon);
}
// Draw player cube
if (cameraMode == CameraMode.ThirdPerson)
{
DrawCube(camera.Target, 0.5f, 0.5f, 0.5f, Color.Purple);
DrawCubeWires(camera.Target, 0.5f, 0.5f, 0.5f, Color.DarkPurple);
}
EndMode3D();
// Draw info boxes
DrawRectangle(5, 5, 330, 100, Fade(Color.SkyBlue, 0.5f));
DrawRectangleLines(5, 5, 330, 100, Color.Blue);
DrawText("Camera controls:", 15, 15, 10, Color.Black);
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, Color.Black);
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, Color.Black);
DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, Color.Black);
DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, Color.Black);
DrawText("- Camera projection key: P", 15, 90, 10, Color.Black);
DrawRectangle(600, 5, 195, 100, Fade(Color.SkyBlue, 0.5f));
DrawRectangleLines(600, 5, 195, 100, Color.Blue);
DrawText("Camera status:", 610, 15, 10, Color.Black);
DrawText($"- Mode: {cameraMode}", 610, 30, 10, Color.Black);
DrawText($"- Projection: {camera.Projection}", 610, 45, 10, Color.Black);
DrawText($"- Position: {camera.Position}", 610, 60, 10, Color.Black);
DrawText($"- Target: {camera.Target}", 610, 75, 10, Color.Black);
DrawText($"- Up: {camera.Up}", 610, 90, 10, Color.Black);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person");
// Define the camera to look into our 3d world (position, target, up vector)
Camera3D camera = new();
camera.Position = new Vector3(4.0f, 2.0f, 4.0f);
camera.Target = new Vector3(0.0f, 1.8f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.FovY = 60.0f;
camera.Projection = CameraProjection.Perspective;
DisableCursor(); // Limit cursor to relative movement inside the window
// Generates some random columns
float[] heights = new float[MaxColumns];
Vector3[] positions = new Vector3[MaxColumns];
Color[] colors = new Color[MaxColumns];
for (int i = 0; i < MaxColumns; i++)
{
heights[i] = (float)GetRandomValue(1, 12);
positions[i] = new Vector3(GetRandomValue(-15, 15), heights[i] / 2, GetRandomValue(-15, 15));
colors[i] = new Color(GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255);
}
CameraMode cameraMode = CameraMode.FirstPerson;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new Camera3dFirstPerson();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// Switch camera mode
if (IsKeyPressed(KeyboardKey.One))
{
cameraMode = CameraMode.Free;
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
}
if (IsKeyPressed(KeyboardKey.Two))
{
cameraMode = CameraMode.FirstPerson;
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
}
if (IsKeyPressed(KeyboardKey.Three))
{
cameraMode = CameraMode.ThirdPerson;
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
}
if (IsKeyPressed(KeyboardKey.Four))
{
cameraMode = CameraMode.Orbital;
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
}
// Switch camera projection
if (IsKeyPressed(KeyboardKey.P))
{
if (camera.Projection == CameraProjection.Perspective)
{
// Create isometric view
cameraMode = CameraMode.ThirdPerson;
// Note: The target distance is related to the render distance in the orthographic projection
camera.Position = new Vector3(0.0f, 2.0f, -100.0f);
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.Projection = CameraProjection.Orthographic;
camera.FovY = 20.0f; // near plane width in CAMERA_ORTHOGRAPHIC
// CameraYaw(&camera, -135 * DEG2RAD, true);
// CameraPitch(&camera, -45 * DEG2RAD, true, true, false);
}
else if (camera.Projection == CameraProjection.Orthographic)
{
// Reset to default view
cameraMode = CameraMode.ThirdPerson;
camera.Position = new Vector3(0.0f, 2.0f, 10.0f);
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.Projection = CameraProjection.Perspective;
camera.FovY = 60.0f;
}
}
// Update camera computes movement internally depending on the camera mode
// Some default standard keyboard/mouse inputs are hardcoded to simplify use
// For advance camera controls, it's reecommended to compute camera movement manually
UpdateCamera(ref camera, cameraMode);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
// Draw ground
DrawPlane(new Vector3(0.0f, 0.0f, 0.0f), new Vector2(32.0f, 32.0f), Color.LightGray);
// Draw a blue wall
DrawCube(new Vector3(-16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Blue);
// Draw a green wall
DrawCube(new Vector3(16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Lime);
// Draw a yellow wall
DrawCube(new Vector3(0.0f, 2.5f, 16.0f), 32.0f, 5.0f, 1.0f, Color.Gold);
// Draw some cubes around
for (int i = 0; i < MaxColumns; i++)
{
DrawCube(positions[i], 2.0f, heights[i], 2.0f, colors[i]);
DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, Color.Maroon);
}
// Draw player cube
if (cameraMode == CameraMode.ThirdPerson)
{
DrawCube(camera.Target, 0.5f, 0.5f, 0.5f, Color.Purple);
DrawCubeWires(camera.Target, 0.5f, 0.5f, 0.5f, Color.DarkPurple);
}
EndMode3D();
// Draw info boxes
DrawRectangle(5, 5, 330, 100, ColorAlpha(Color.SkyBlue, 0.5f));
DrawRectangleLines(10, 10, 330, 100, Color.Blue);
DrawText("Camera controls:", 15, 15, 10, Color.Black);
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, Color.Black);
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, Color.Black);
DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, Color.Black);
DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, Color.Black);
DrawText("- Camera projection key: P", 15, 90, 10, Color.Black);
DrawRectangle(600, 5, 195, 100, Fade(Color.SkyBlue, 0.5f));
DrawRectangleLines(600, 5, 195, 100, Color.Blue);
DrawText("Camera status:", 610, 15, 10, Color.Black);
DrawText($"- Mode: {cameraMode}", 610, 30, 10, Color.Black);
DrawText($"- Projection: {camera.Projection}", 610, 45, 10, Color.Black);
DrawText($"- Position: {camera.Position}", 610, 60, 10, Color.Black);
DrawText($"- Target: {camera.Target}", 610, 75, 10, Color.Black);
DrawText($"- Up: {camera.Up}", 610, 90, 10, Color.Black);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,360 @@
/*******************************************************************************************
*
* raylib [core] example - 3d camera fps
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
* Example contributed by Agnis Aldiņš (@nezvers) 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 Agnis Aldiņš (@nezvers)
*
********************************************************************************************/
using static Raylib_cs.Raymath;
namespace Examples.Core;
public partial class Camera3dFps : IExample
{
// Movement constants
private const float GRAVITY = 32.0f;
private const float MAX_SPEED = 20.0f;
private const float CROUCH_SPEED = 5.0f;
private const float JUMP_FORCE = 12.0f;
private const float MAX_ACCEL = 150.0f;
// Grounded drag
private const float FRICTION = 0.86f;
// Increasing air drag, increases strafing speed
private const float AIR_DRAG = 0.98f;
// Responsiveness for turning movement direction to looked direction
private const float CONTROL = 15.0f;
private const float CROUCH_HEIGHT = 0.0f;
private const float STAND_HEIGHT = 1.0f;
private const float BOTTOM_HEIGHT = 0.5f;
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / 3D Camera FPS";
public string Title => "raylib [core] example - 3d camera fps";
public bool CursorDisabled => true;
// Body structure
private struct Body
{
public Vector3 Position;
public Vector3 Velocity;
public Vector3 Dir;
public bool IsGrounded;
}
// State that was global in the C example
private readonly Vector2 sensitivity = new Vector2(0.001f, 0.001f);
private Body player;
private Vector2 lookRotation;
private float headTimer;
private float walkLerp;
private float headLerp;
private Vector2 lean;
private Camera3D camera;
public void Init()
{
player = new Body();
lookRotation = new Vector2(0, 0);
headTimer = 0.0f;
walkLerp = 0.0f;
headLerp = STAND_HEIGHT;
lean = new Vector2(0, 0);
// Initialize camera variables
// NOTE: UpdateCameraFPS() takes care of the rest
camera = new Camera3D();
camera.FovY = 60.0f;
camera.Projection = CameraProjection.Perspective;
camera.Position = new Vector3(
player.Position.X,
player.Position.Y + (BOTTOM_HEIGHT + headLerp),
player.Position.Z);
UpdateCameraFPS(ref camera); // Update camera parameters
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
Vector2 mouseDelta = GetMouseDelta();
lookRotation.X -= mouseDelta.X * sensitivity.X;
lookRotation.Y += mouseDelta.Y * sensitivity.Y;
int sideway = (IsKeyDown(KeyboardKey.D) ? 1 : 0) - (IsKeyDown(KeyboardKey.A) ? 1 : 0);
int forward = (IsKeyDown(KeyboardKey.W) ? 1 : 0) - (IsKeyDown(KeyboardKey.S) ? 1 : 0);
bool crouching = IsKeyDown(KeyboardKey.LeftControl);
UpdateBody(ref player, lookRotation.X, sideway, forward, IsKeyPressed(KeyboardKey.Space), crouching);
float delta = GetFrameTime();
headLerp = Lerp(headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0f * delta);
camera.Position = new Vector3(
player.Position.X,
player.Position.Y + (BOTTOM_HEIGHT + headLerp),
player.Position.Z);
if (player.IsGrounded && ((forward != 0) || (sideway != 0)))
{
headTimer += delta * 3.0f;
walkLerp = Lerp(walkLerp, 1.0f, 10.0f * delta);
camera.FovY = Lerp(camera.FovY, 55.0f, 5.0f * delta);
}
else
{
walkLerp = Lerp(walkLerp, 0.0f, 10.0f * delta);
camera.FovY = Lerp(camera.FovY, 60.0f, 5.0f * delta);
}
lean.X = Lerp(lean.X, sideway * 0.02f, 10.0f * delta);
lean.Y = Lerp(lean.Y, forward * 0.015f, 10.0f * delta);
UpdateCameraFPS(ref camera);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
DrawLevel();
EndMode3D();
// Draw info box
DrawRectangle(5, 5, 330, 75, Fade(Color.SkyBlue, 0.5f));
DrawRectangleLines(5, 5, 330, 75, Color.Blue);
DrawText("Camera controls:", 15, 15, 10, Color.Black);
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, Color.Black);
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, Color.Black);
float velLen = Vector2Length(new Vector2(player.Velocity.X, player.Velocity.Z));
DrawText($"- Velocity Len: ({velLen:00.000})", 15, 60, 10, Color.Black);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
// Update body considering current world state
private void UpdateBody(ref Body body, float rot, int side, int forward, bool jumpPressed, bool crouchHold)
{
Vector2 input = new Vector2((float)side, (float)-forward);
// Upstream guards this with `#if defined(NORMALIZE_INPUT)`, which is always true given the
// `#define NORMALIZE_INPUT 0` above it (defined() tests definedness, not the value), so the
// diagonal-movement normalization is active.
// Slow down diagonal movement
if ((side != 0) && (forward != 0))
{
input = Vector2Normalize(input);
}
float delta = GetFrameTime();
if (!body.IsGrounded)
{
body.Velocity.Y -= GRAVITY * delta;
}
if (body.IsGrounded && jumpPressed)
{
body.Velocity.Y = JUMP_FORCE;
body.IsGrounded = false;
// Sound can be played at this moment
//SetSoundPitch(fxJump, 1.0f + (GetRandomValue(-100, 100)*0.001));
//PlaySound(fxJump);
}
Vector3 front = new Vector3(MathF.Sin(rot), 0.0f, MathF.Cos(rot));
Vector3 right = new Vector3(MathF.Cos(-rot), 0.0f, MathF.Sin(-rot));
Vector3 desiredDir = new Vector3(
input.X * right.X + input.Y * front.X,
0.0f,
input.X * right.Z + input.Y * front.Z);
body.Dir = Vector3Lerp(body.Dir, desiredDir, CONTROL * delta);
float decel = (body.IsGrounded ? FRICTION : AIR_DRAG);
Vector3 hvel = new Vector3(body.Velocity.X * decel, 0.0f, body.Velocity.Z * decel);
float hvelLength = Vector3Length(hvel); // Magnitude
if (hvelLength < (MAX_SPEED * 0.01f))
{
hvel = new Vector3(0, 0, 0);
}
// This is what creates strafing
float speed = Vector3DotProduct(hvel, body.Dir);
// Whenever the amount of acceleration to add is clamped by the maximum acceleration constant,
// a Player can make the speed faster by bringing the direction closer to horizontal velocity angle
// More info here: https://youtu.be/v3zT3Z5apaM?t=165
float maxSpeed = (crouchHold ? CROUCH_SPEED : MAX_SPEED);
float accel = Clamp(maxSpeed - speed, 0.0f, MAX_ACCEL * delta);
hvel.X += body.Dir.X * accel;
hvel.Z += body.Dir.Z * accel;
body.Velocity.X = hvel.X;
body.Velocity.Z = hvel.Z;
body.Position.X += body.Velocity.X * delta;
body.Position.Y += body.Velocity.Y * delta;
body.Position.Z += body.Velocity.Z * delta;
// Fancy collision system against the floor
if (body.Position.Y <= 0.0f)
{
body.Position.Y = 0.0f;
body.Velocity.Y = 0.0f;
body.IsGrounded = true; // Enable jumping
}
}
// Update camera for FPS behaviour
private void UpdateCameraFPS(ref Camera3D camera)
{
Vector3 up = new Vector3(0.0f, 1.0f, 0.0f);
Vector3 targetOffset = new Vector3(0.0f, 0.0f, -1.0f);
// Left and right
Vector3 yaw = Vector3RotateByAxisAngle(targetOffset, up, lookRotation.X);
// Clamp view up
float maxAngleUp = Vector3Angle(up, yaw);
maxAngleUp -= 0.001f; // Avoid numerical errors
if (-(lookRotation.Y) > maxAngleUp)
{
lookRotation.Y = -maxAngleUp;
}
// Clamp view down
float maxAngleDown = Vector3Angle(Vector3Negate(up), yaw);
maxAngleDown *= -1.0f; // Downwards angle is negative
maxAngleDown += 0.001f; // Avoid numerical errors
if (-(lookRotation.Y) < maxAngleDown)
{
lookRotation.Y = -maxAngleDown;
}
// Up and down
Vector3 right = Vector3Normalize(Vector3CrossProduct(yaw, up));
// Rotate view vector around right axis
float pitchAngle = -lookRotation.Y - lean.Y;
pitchAngle = Clamp(pitchAngle, -MathF.PI / 2 + 0.0001f, MathF.PI / 2 - 0.0001f); // Clamp angle so it doesn't go past straight up or straight down
Vector3 pitch = Vector3RotateByAxisAngle(yaw, right, pitchAngle);
// Head animation
// Rotate up direction around forward axis
float headSin = MathF.Sin(headTimer * MathF.PI);
float headCos = MathF.Cos(headTimer * MathF.PI);
const float stepRotation = 0.01f;
camera.Up = Vector3RotateByAxisAngle(up, pitch, headSin * stepRotation + lean.X);
// Camera BOB
const float bobSide = 0.1f;
const float bobUp = 0.15f;
Vector3 bobbing = Vector3Scale(right, headSin * bobSide);
bobbing.Y = MathF.Abs(headCos * bobUp);
camera.Position = Vector3Add(camera.Position, Vector3Scale(bobbing, walkLerp));
camera.Target = Vector3Add(camera.Position, pitch);
}
// Draw game level
private void DrawLevel()
{
const int floorExtent = 25;
const float tileSize = 5.0f;
Color tileColor1 = new Color(150, 200, 200, 255);
// Floor tiles
for (int y = -floorExtent; y < floorExtent; y++)
{
for (int x = -floorExtent; x < floorExtent; x++)
{
if ((y & 1) != 0 && (x & 1) != 0)
{
DrawPlane(new Vector3(x * tileSize, 0.0f, y * tileSize), new Vector2(tileSize, tileSize), tileColor1);
}
else if ((y & 1) == 0 && (x & 1) == 0)
{
DrawPlane(new Vector3(x * tileSize, 0.0f, y * tileSize), new Vector2(tileSize, tileSize), Color.LightGray);
}
}
}
Vector3 towerSize = new Vector3(16.0f, 32.0f, 16.0f);
Color towerColor = new Color(150, 200, 200, 255);
Vector3 towerPos = new Vector3(16.0f, 16.0f, 16.0f);
DrawCubeV(towerPos, towerSize, towerColor);
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
towerPos.X *= -1;
DrawCubeV(towerPos, towerSize, towerColor);
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
towerPos.Z *= -1;
DrawCubeV(towerPos, towerSize, towerColor);
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
towerPos.X *= -1;
DrawCubeV(towerPos, towerSize, towerColor);
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
// Red sun
DrawSphere(new Vector3(300.0f, 300.0f, 0.0f), 100.0f, new Color(255, 0, 0, 255));
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera fps");
DisableCursor(); // Limit cursor to relative movement inside the window
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new Camera3dFps();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,87 +1,114 @@
/*******************************************************************************************
*
* raylib [core] example - Initialize 3d camera free
* raylib [core] example - 3d camera free
*
* This example has been created using raylib 1.3 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 1/4
*
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.3, last time updated with raylib 1.3
*
* 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) 2015-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class Camera3dFree
public partial class Camera3dFree : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Camera 3D Free";
public string Title => "raylib [core] example - 3d camera free";
public bool CursorDisabled => true;
private Camera3D camera;
private Vector3 cubePosition;
public void Init()
{
// Define the camera to look into our 3d world
camera = new();
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
camera.FovY = 45.0f; // Camera field-of-view Y
camera.Projection = CameraProjection.Perspective; // Camera projection type
cubePosition = new(0.0f, 0.0f, 0.0f);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.Free);
if (IsKeyPressed(KeyboardKey.Z))
{
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
DrawGrid(10, 1.0f);
EndMode3D();
DrawRectangle(10, 10, 320, 93, Fade(Color.SkyBlue, 0.5f));
DrawRectangleLines(10, 10, 320, 93, Color.Blue);
DrawText("Free camera default controls:", 20, 20, 10, Color.Black);
DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, Color.DarkGray);
DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, Color.DarkGray);
DrawText("- Z to zoom to (0, 0, 0)", 40, 80, 10, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free");
// Define the camera to look into our 3d world
Camera3D camera;
camera.Position = new Vector3(10.0f, 10.0f, 10.0f);
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.FovY = 45.0f;
camera.Projection = CameraProjection.Perspective;
DisableCursor(); // Limit cursor to relative movement inside the window
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new Camera3dFree();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.Free);
if (IsKeyDown(KeyboardKey.Z))
{
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
DrawGrid(10, 1.0f);
EndMode3D();
DrawRectangle(10, 10, 320, 133, ColorAlpha(Color.SkyBlue, 0.5f));
DrawRectangleLines(10, 10, 320, 133, Color.Blue);
DrawText("Free camera default controls:", 20, 20, 10, Color.Black);
DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, Color.DarkGray);
DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, Color.DarkGray);
DrawText("- Alt + Mouse Wheel Pressed to Rotate", 40, 80, 10, Color.DarkGray);
DrawText("- Alt + Ctrl + Mouse Wheel Pressed for Smooth Zoom", 40, 100, 10, Color.DarkGray);
DrawText("- Z to zoom to (0, 0, 0)", 40, 120, 10, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -1,76 +1,96 @@
/*******************************************************************************************
*
* raylib [core] example - Initialize 3d camera mode
* raylib [core] example - 3d camera mode
*
* 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 System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class Camera3dMode
public partial class Camera3dMode : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private Camera3D camera;
private Vector3 cubePosition;
public string Name => "Core / Camera 3D Mode";
public string Title => "raylib [core] example - 3d camera mode";
public void Init()
{
// Define the camera to look into our 3d world
camera = new();
camera.Position = new Vector3(0.0f, 10.0f, 10.0f); // Camera position
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
camera.FovY = 45.0f; // Camera field-of-view Y
camera.Projection = CameraProjection.Perspective; // Camera mode type
cubePosition = new(0.0f, 0.0f, 0.0f);
}
public void Update()
{
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
DrawGrid(10, 1.0f);
EndMode3D();
DrawText("Welcome to the third dimension!", 10, 40, 20, Color.DarkGray);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera mode");
// Define the camera to look into our 3d world
Camera3D camera = new();
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.FovY = 45.0f;
camera.Projection = CameraProjection.Perspective;
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new Camera3dMode();
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);
BeginMode3D(camera);
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
DrawGrid(10, 1.0f);
EndMode3D();
DrawText("Welcome to the third dimension!", 10, 40, 20, Color.DarkGray);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,311 @@
/*******************************************************************************************
*
* raylib [core] example - clipboard text
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.0
*
* Example contributed by Ananth S (@Ananth1839) 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 Ananth S (@Ananth1839)
*
********************************************************************************************/
// NOTE: The upstream C example uses raygui (GuiTextBox/GuiButton/GuiLabel) for its UI.
// raygui is not bound in raylib-cs, so the widgets below are minimal re-implementations
// using plain raylib drawing/input. Clipboard behaviour (cut/copy/paste and CTRL+X/C/V
// shortcuts) matches the original.
using System.Text;
namespace Examples.Core;
public partial class ClipboardText : IExample
{
private const int MaxTextSamples = 5;
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Clipboard Text";
public string Title => "raylib [core] example - clipboard text";
private string[] sampleTexts;
private string clipboardText;
private StringBuilder inputBuffer;
// UI required variables
private bool textBoxEditMode;
private bool btnCutPressed;
private bool btnCopyPressed;
private bool btnPastePressed;
private bool btnClearPressed;
private bool btnRandomPressed;
private int framesCounter;
public void Init()
{
// Define some sample texts
sampleTexts = new string[]
{
"Hello from raylib!",
"The quick brown fox jumps over the lazy dog",
"Clipboard operations are useful!",
"raylib is a simple and easy-to-use library",
"Copy and paste me!"
};
clipboardText = null;
inputBuffer = new StringBuilder("Hello from raylib!"); // Random initial string
// UI required variables
textBoxEditMode = false;
btnCutPressed = false;
btnCopyPressed = false;
btnPastePressed = false;
btnClearPressed = false;
btnRandomPressed = false;
framesCounter = 0;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
framesCounter++;
// Handle button interactions
if (btnCutPressed)
{
SetClipboardText(inputBuffer.ToString());
clipboardText = GetClipboardText_();
inputBuffer.Clear(); // Quick solution to clear text
}
if (btnCopyPressed)
{
SetClipboardText(inputBuffer.ToString()); // Copy text to clipboard
clipboardText = GetClipboardText_(); // Get text from clipboard
}
if (btnPastePressed)
{
// Paste text from clipboard
clipboardText = GetClipboardText_();
if (clipboardText != null)
{
SetInputBuffer(clipboardText);
}
}
if (btnClearPressed)
{
inputBuffer.Clear(); // Quick solution to clear text
}
if (btnRandomPressed)
{
// Get random text from sample list
SetInputBuffer(sampleTexts[GetRandomValue(0, MaxTextSamples - 1)]);
}
// Quick cut/copy/paste with keyboard shortcuts
if (IsKeyDown(KeyboardKey.LeftControl) || IsKeyDown(KeyboardKey.RightControl))
{
if (IsKeyPressed(KeyboardKey.X))
{
SetClipboardText(inputBuffer.ToString());
inputBuffer.Clear(); // Quick solution to clear text
}
if (IsKeyPressed(KeyboardKey.C))
{
SetClipboardText(inputBuffer.ToString());
}
if (IsKeyPressed(KeyboardKey.V))
{
clipboardText = GetClipboardText_();
if (clipboardText != null)
{
SetInputBuffer(clipboardText);
}
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw instructions
GuiLabel(new Rectangle(50, 20, 700, 36), "Use the BUTTONS or KEY SHORTCUTS:");
DrawText("[CTRL+X] - CUT | [CTRL+C] COPY | [CTRL+V] | PASTE", 50, 60, 20, Color.Maroon);
// Draw text box
if (GuiTextBox(new Rectangle(50, 120, 652, 40), inputBuffer, 256, textBoxEditMode))
{
textBoxEditMode = !textBoxEditMode;
}
// Random text button
btnRandomPressed = GuiButton(new Rectangle(50 + 652 + 8, 120, 40, 40), "RND");
// Draw buttons
btnCutPressed = GuiButton(new Rectangle(50, 180, 158, 40), "CUT");
btnCopyPressed = GuiButton(new Rectangle(50 + 165, 180, 158, 40), "COPY");
btnPastePressed = GuiButton(new Rectangle(50 + 165 * 2, 180, 158, 40), "PASTE");
btnClearPressed = GuiButton(new Rectangle(50 + 165 * 3, 180, 158, 40), "CLEAR");
// Draw clipboard status
GuiLabel(new Rectangle(50, 260, 700, 40), "Clipboard current text data:");
GuiTextBoxReadOnly(new Rectangle(50, 300, 700, 40), clipboardText);
GuiLabel(new Rectangle(50, 360, 700, 40), "Try copying text from other applications and pasting here!");
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
// Replace input buffer contents (equivalent to raylib TextCopy into a fixed buffer)
private void SetInputBuffer(string text)
{
inputBuffer.Clear();
if (text != null)
{
if (text.Length > 255)
{
text = text.Substring(0, 255);
}
inputBuffer.Append(text);
}
}
//----------------------------------------------------------------------------------
// Minimal raygui-like widgets (plain raylib re-implementation)
//----------------------------------------------------------------------------------
private static void GuiLabel(Rectangle bounds, string text)
{
DrawText(text, (int)bounds.X, (int)(bounds.Y + (bounds.Height - 20) / 2), 20, Color.DarkGray);
}
private static bool GuiButton(Rectangle bounds, string text)
{
bool pressed = false;
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
Color fill = hover ? (IsMouseButtonDown(MouseButton.Left) ? Color.SkyBlue : Color.LightGray) : Color.RayWhite;
DrawRectangleRec(bounds, fill);
DrawRectangleLinesEx(bounds, 1, hover ? Color.Blue : Color.Gray);
int textWidth = MeasureText(text, 20);
DrawText(text, (int)(bounds.X + (bounds.Width - textWidth) / 2), (int)(bounds.Y + (bounds.Height - 20) / 2), 20, Color.DarkGray);
if (hover && IsMouseButtonReleased(MouseButton.Left))
{
pressed = true;
}
return pressed;
}
private bool GuiTextBox(Rectangle bounds, StringBuilder text, int maxChars, bool editMode)
{
bool pressed = false;
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
if (editMode)
{
// Get char pressed (unicode character) on the queue
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 - 20) / 2), 20, Color.DarkGray);
// Draw blinking cursor while editing
if (editMode && ((framesCounter / 20) % 2 == 0))
{
DrawText("_", (int)bounds.X + 4 + MeasureText(content, 20), (int)(bounds.Y + (bounds.Height - 20) / 2), 20, Color.DarkGray);
}
if (hover && IsMouseButtonPressed(MouseButton.Left))
{
pressed = true;
}
return pressed;
}
private static void GuiTextBoxReadOnly(Rectangle bounds, string text)
{
DrawRectangleRec(bounds, Color.LightGray);
DrawRectangleLinesEx(bounds, 1, Color.Gray);
if (text != null)
{
DrawText(text, (int)bounds.X + 4, (int)(bounds.Y + (bounds.Height - 20) / 2), 20, Color.Gray);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - clipboard text");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new ClipboardText();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,276 @@
/*******************************************************************************************
*
* raylib [core] example - compute hash
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.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) 2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
// NOTE: The upstream C example uses raygui (GuiTextBox/GuiButton/GuiLabel) for its UI.
// raygui is not bound in raylib-cs, so the widgets below are minimal re-implementations
// using plain raylib drawing/input. The hashing/Base64 logic is a faithful port.
using System.Text;
namespace Examples.Core;
public unsafe partial class ComputeHash : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Compute Hash";
public string Title => "raylib [core] example - compute hash";
// UI controls variables
private StringBuilder textInput;
private bool textBoxEditMode;
private bool btnComputeHashes;
// Data hash values
private uint hashCRC32;
private uint[] hashMD5;
private uint[] hashSHA1;
private uint[] hashSHA256;
// Base64 encoded data
private string base64Text;
private int framesCounter;
public void Init()
{
textInput = new StringBuilder("The quick brown fox jumps over the lazy dog.");
textBoxEditMode = false;
btnComputeHashes = false;
hashCRC32 = 0;
hashMD5 = null;
hashSHA1 = null;
hashSHA256 = null;
base64Text = null;
framesCounter = 0;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
framesCounter++;
if (btnComputeHashes)
{
byte[] bytes = Encoding.UTF8.GetBytes(textInput.ToString());
int textInputLen = bytes.Length;
fixed (byte* textInputPtr = bytes)
{
int base64TextSize;
// Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
sbyte* base64 = EncodeDataBase64(textInputPtr, textInputLen, &base64TextSize);
base64Text = (base64 != null) ? new string(base64) : null;
MemFree(base64); // Free Base64 text data (kept managed above)
hashCRC32 = ComputeCRC32(textInputPtr, textInputLen); // Compute CRC32 hash code (4 bytes)
hashMD5 = CopyHash(ComputeMD5(textInputPtr, textInputLen), 4); // Compute MD5 hash code, returns static int[4] (16 bytes)
hashSHA1 = CopyHash(ComputeSHA1(textInputPtr, textInputLen), 5); // Compute SHA1 hash code, returns static int[5] (20 bytes)
hashSHA256 = CopyHash(ComputeSHA256(textInputPtr, textInputLen), 8); // Compute SHA256 hash code, returns static int[8] (32 bytes)
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
GuiLabel(new Rectangle(40, 26, 720, 32), "INPUT DATA (TEXT):", 20);
if (GuiTextBox(new Rectangle(40, 64, 720, 32), textInput, 95, textBoxEditMode, 10))
{
textBoxEditMode = !textBoxEditMode;
}
btnComputeHashes = GuiButton(new Rectangle(40, 64 + 40, 720, 32), "COMPUTE INPUT DATA HASHES", 10);
GuiLabel(new Rectangle(40, 160, 720, 32), "INPUT DATA HASH VALUES:", 20);
GuiLabel(new Rectangle(40, 200, 120, 32), "CRC32 [32 bit]:", 10);
GuiTextBoxReadOnly(new Rectangle(40 + 120, 200, 720 - 120, 32), GetDataAsHexText(new uint[] { hashCRC32 }, 1), 10);
GuiLabel(new Rectangle(40, 200 + 36, 120, 32), "MD5 [128 bit]:", 10);
GuiTextBoxReadOnly(new Rectangle(40 + 120, 200 + 36, 720 - 120, 32), GetDataAsHexText(hashMD5, 4), 10);
GuiLabel(new Rectangle(40, 200 + 36 * 2, 120, 32), "SHA1 [160 bit]:", 10);
GuiTextBoxReadOnly(new Rectangle(40 + 120, 200 + 36 * 2, 720 - 120, 32), GetDataAsHexText(hashSHA1, 5), 10);
GuiLabel(new Rectangle(40, 200 + 36 * 3, 120, 32), "SHA256 [256 bit]:", 10);
GuiTextBoxReadOnly(new Rectangle(40 + 120, 200 + 36 * 3, 720 - 120, 32), GetDataAsHexText(hashSHA256, 8), 10);
GuiLabel(new Rectangle(40, 200 + 36 * 5 - 30, 320, 32), "BONUS - BAS64 ENCODED STRING:", 10);
GuiLabel(new Rectangle(40, 200 + 36 * 5, 120, 32), "BASE64 ENCODING:", 10);
GuiTextBoxReadOnly(new Rectangle(40 + 120, 200 + 36 * 5, 720 - 120, 32), base64Text, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
private static uint[] CopyHash(uint* data, int count)
{
if (data == null)
{
return null;
}
uint[] result = new uint[count];
for (int i = 0; i < count; i++)
{
result[i] = data[i];
}
return result;
}
private static string GetDataAsHexText(uint[] data, int dataSize)
{
if ((data != null) && (dataSize > 0) && (dataSize < ((128 / 8) - 1)))
{
StringBuilder text = new StringBuilder();
for (int i = 0; i < dataSize; i++)
{
text.Append(data[i].ToString("X8"));
}
return text.ToString();
}
return "00000000";
}
//----------------------------------------------------------------------------------
// Minimal raygui-like widgets (plain raylib re-implementation)
//----------------------------------------------------------------------------------
private static void GuiLabel(Rectangle bounds, string text, int fontSize)
{
DrawText(text, (int)bounds.X, (int)(bounds.Y + (bounds.Height - fontSize) / 2), fontSize, Color.DarkGray);
}
private static bool GuiButton(Rectangle bounds, string text, int fontSize)
{
bool pressed = false;
Vector2 mouse = GetMousePosition();
bool hover = CheckCollisionPointRec(mouse, bounds);
Color fill = hover ? (IsMouseButtonDown(MouseButton.Left) ? Color.SkyBlue : Color.LightGray) : Color.RayWhite;
DrawRectangleRec(bounds, fill);
DrawRectangleLinesEx(bounds, 1, hover ? Color.Blue : Color.Gray);
int textWidth = MeasureText(text, fontSize);
DrawText(text, (int)(bounds.X + (bounds.Width - textWidth) / 2), (int)(bounds.Y + (bounds.Height - fontSize) / 2), fontSize, Color.DarkGray);
if (hover && IsMouseButtonReleased(MouseButton.Left))
{
pressed = true;
}
return pressed;
}
private bool GuiTextBox(Rectangle bounds, StringBuilder text, int maxChars, bool editMode, int fontSize)
{
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 - fontSize) / 2), fontSize, Color.DarkGray);
if (editMode && ((framesCounter / 20) % 2 == 0))
{
DrawText("_", (int)bounds.X + 4 + MeasureText(content, fontSize), (int)(bounds.Y + (bounds.Height - fontSize) / 2), fontSize, Color.DarkGray);
}
if (hover && IsMouseButtonPressed(MouseButton.Left))
{
pressed = true;
}
return pressed;
}
private static void GuiTextBoxReadOnly(Rectangle bounds, string text, int fontSize)
{
DrawRectangleRec(bounds, Color.LightGray);
DrawRectangleLinesEx(bounds, 1, Color.Gray);
if (text != null)
{
DrawText(text, (int)bounds.X + 4, (int)(bounds.Y + (bounds.Height - fontSize) / 2), fontSize, Color.Gray);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - compute hash");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new ComputeHash();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,208 @@
/*******************************************************************************************
*
* raylib [core] example - custom frame control
*
* Example complexity rating: [] 4/4
*
* NOTE: WARNING: This is an example for advanced users willing to have full control over
* the frame processes. By default, EndDrawing() calls the following processes:
* 1. Draw remaining batch data: rlDrawRenderBatchActive()
* 2. SwapScreenBuffer()
* 3. Frame time control: WaitTime()
* 4. PollInputEvents()
*
* To avoid steps 2, 3 and 4, flag SUPPORT_CUSTOM_FRAME_CONTROL can be enabled in
* config.h (it requires recompiling raylib). This way those steps are up to the user
*
* Note that enabling this flag invalidates some functions:
* - GetFrameTime()
* - SetTargetFPS()
* - GetFPS()
*
* Example originally created with raylib 4.0, 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) 2021-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Core;
// NOTE: This example is intended to run against a raylib built with SUPPORT_CUSTOM_FRAME_CONTROL,
// where EndDrawing() does NOT swap buffers, wait or poll input, leaving those to the user code
// below. The stock raylib-cs native library is built WITHOUT that flag, so EndDrawing() still
// performs those steps and the manual SwapScreenBuffer()/WaitTime()/PollInputEvents() calls here
// run in addition to them. The port is kept faithful to upstream regardless.
[ExcludeFromBrowser("manual PollInputEvents/SwapScreenBuffer/WaitTime clashes with the emscripten main loop")]
public partial class CustomFrameControl : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Custom Frame Control";
public string Title => "raylib [core] example - custom frame control";
// Custom timming variables
private double previousTime; // Previous time measure
private double currentTime; // Current time measure
private double updateDrawTime; // Update + Draw time
private double waitTime; // Wait time (if target fps required)
private float deltaTime; // Frame time (Update + Draw + Wait time)
private float timeCounter; // Accumulative time counter (seconds)
private float position; // Circle position
private bool pause; // Pause control flag
private int targetFPS; // Our initial target fps
public void Init()
{
previousTime = GetTime();
currentTime = 0.0;
updateDrawTime = 0.0;
waitTime = 0.0;
deltaTime = 0.0f;
timeCounter = 0.0f;
position = 0.0f;
pause = false;
targetFPS = 60;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
#if !BROWSER
// NOTE: On non web platforms the PollInputEvents just works before the inputs checks
PollInputEvents(); // Poll input events (SUPPORT_CUSTOM_FRAME_CONTROL)
#endif
if (IsKeyPressed(KeyboardKey.Space))
{
pause = !pause;
}
if (IsKeyPressed(KeyboardKey.Up))
{
targetFPS += 20;
}
else if (IsKeyPressed(KeyboardKey.Down))
{
targetFPS -= 20;
}
if (targetFPS < 0)
{
targetFPS = 0;
}
if (!pause)
{
position += 200 * deltaTime; // We move at 200 pixels per second
if (position >= GetScreenWidth())
{
position = 0;
}
timeCounter += deltaTime; // We count time (seconds)
}
#if BROWSER
// NOTE: On web platform for some reason the PollInputEvents only works after the inputs
// check, so just call it after check all your inputs (on web)
PollInputEvents(); // Poll input events (SUPPORT_CUSTOM_FRAME_CONTROL)
#endif
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
for (int i = 0; i < GetScreenWidth() / 200; i++)
{
DrawRectangle(200 * i, 0, 1, GetScreenHeight(), Color.SkyBlue);
}
DrawCircle((int)position, GetScreenHeight() / 2 - 25, 50, Color.Red);
DrawText($"{timeCounter * 1000.0f:000} ms", (int)position - 40, GetScreenHeight() / 2 - 100, 20, Color.Maroon);
DrawText($"PosX: {position:000}", (int)position - 50, GetScreenHeight() / 2 + 40, 20, Color.Black);
DrawText("Circle is moving at a constant 200 pixels/sec,\nindependently of the frame rate.", 10, 10, 20, Color.DarkGray);
DrawText("PRESS SPACE to PAUSE MOVEMENT", 10, GetScreenHeight() - 60, 20, Color.Gray);
DrawText("PRESS UP | DOWN to CHANGE TARGET FPS", 10, GetScreenHeight() - 30, 20, Color.Gray);
DrawText($"TARGET FPS: {targetFPS}", GetScreenWidth() - 220, 10, 20, Color.Lime);
if (deltaTime != 0)
{
DrawText($"CURRENT FPS: {(int)(1.0f / deltaTime)}", GetScreenWidth() - 220, 40, 20, Color.Green);
}
EndDrawing();
// NOTE: In case raylib is configured to SUPPORT_CUSTOM_FRAME_CONTROL,
// Events polling, screen buffer swap and frame time control must be managed by the user
SwapScreenBuffer(); // Flip the back buffer to screen (front buffer)
currentTime = GetTime();
updateDrawTime = currentTime - previousTime;
if (targetFPS > 0) // We want a fixed frame rate
{
waitTime = (1.0f / (float)targetFPS) - updateDrawTime;
if (waitTime > 0.0)
{
WaitTime((float)waitTime);
currentTime = GetTime();
deltaTime = (float)(currentTime - previousTime);
}
}
else
{
deltaTime = (float)updateDrawTime; // Framerate could be variable
}
previousTime = currentTime;
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - custom frame control");
// NOTE: Not calling SetTargetFPS(): this example manages frame timing manually with
// WaitTime() (SetTargetFPS/GetFrameTime/GetFPS are invalidated by SUPPORT_CUSTOM_FRAME_CONTROL)
//--------------------------------------------------------------------------------------
var game = new CustomFrameControl();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,27 +1,41 @@
/*******************************************************************************************
*
* raylib [core] example - Custom logging
* raylib [core] example - custom logging
*
* This example has been created using raylib 2.1 (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 Pablo Marcos Oltra (@pamarcos) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2018 Pablo Marcos Oltra (@pamarcos) 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 Pablo Marcos Oltra (@pamarcos) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System;
using System.Runtime.InteropServices;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public unsafe class CustomLogging
public unsafe partial class CustomLogging : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Custom Logging";
public string Title => "raylib [core] example - custom logging";
[UnmanagedCallersOnly(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })]
private static void LogCustom(int logLevel, sbyte* text, sbyte* args)
{
#if BROWSER
// WebAssembly can't invoke the C varargs vsprintf/vsnprintf that Logging.GetLogMessage relies on
// (the wasm runtime traps with "function signature mismatch"), so log the raw, unformatted text.
string message = Marshal.PtrToStringUTF8(new IntPtr(text)) ?? string.Empty;
#else
var message = Logging.GetLogMessage(new IntPtr(text), new IntPtr(args));
/*Console.ForegroundColor = (TraceLogLevel)logLevel switch
@ -36,50 +50,64 @@ public unsafe class CustomLogging
TraceLogLevel.LOG_NONE => ConsoleColor.White,
_ => throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null)
};*/
#endif
Console.WriteLine($"Custom " + message);
// Console.ResetColor();
}
public void Init()
{
// First thing we do is setting our custom logger to ensure everything raylib logs
// will use our own logger instead of its internal one
SetTraceLogCallback(&LogCustom);
}
public void Update()
{
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("Check out the console output to see the custom logger in action!", 60, 200, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
#if !BROWSER
// Restore the default formatting logger on desktop. On WebAssembly we leave the (wasm-safe)
// custom logger in place — Logging.LogConsole formats via vsprintf, which traps on wasm.
SetTraceLogCallback(&Logging.LogConsole);
#endif
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
// First thing we do is setting our custom logger to ensure everything raylib logs
// will use our own logger instead of its internal one
SetTraceLogCallback(&LogCustom);
InitWindow(screenWidth, screenHeight, "raylib [core] example - custom logging");
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new CustomLogging();
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("Check out the console output to see the custom logger in action!", 60, 200, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
SetTraceLogCallback(&Logging.LogConsole);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -15,114 +15,141 @@
*
********************************************************************************************/
using System.Numerics;
namespace Examples.Core;
using static Raylib_cs.Raylib;
public class DeltaTime
public partial class DeltaTime : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
// The speed applied to both circles
private const float speed = 10.0f;
private const float circleRadius = 32.0f;
private int currentFps;
// Store the position for the both of the circles
private Vector2 deltaCircle;
private Vector2 frameCircle;
public string Name => "Core / Delta Time";
public string Title => "raylib [core] example - delta time";
public void Init()
{
currentFps = 60;
// Store the position for the both of the circles
deltaCircle = new Vector2(0, (float)screenHeight / 3.0f);
frameCircle = new Vector2(0, (float)screenHeight * (2.0f / 3.0f));
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Adjust the FPS target based on the mouse wheel
var mouseWheel = GetMouseWheelMove();
if (mouseWheel != 0)
{
currentFps += (int)mouseWheel;
if (currentFps < 0)
{
currentFps = 0;
}
SetTargetFPS(currentFps);
}
// GetFrameTime() returns the time it took to draw the last frame, in seconds (usually called delta time)
// Uses the delta time to make the circle look like it's moving at a "consistent" speed regardless of FPS
// Multiply by 6.0 (an arbitrary value) in order to make the speed
// visually closer to the other circle (at 60 fps), for comparison
deltaCircle.X += GetFrameTime() * 6.0f * speed;
// This circle can move faster or slower visually depending on the FPS
frameCircle.X += 0.1f * speed;
// If either circle is off the screen, reset it back to the start
if (deltaCircle.X > screenWidth)
{
deltaCircle.X = 0;
}
if (frameCircle.X > screenWidth)
{
frameCircle.X = 0;
}
// Reset both circles positions
if (IsKeyPressed(KeyboardKey.R))
{
deltaCircle.X = 0;
frameCircle.X = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw both circles to the screen
DrawCircleV(deltaCircle, circleRadius, Color.Red);
DrawCircleV(frameCircle, circleRadius, Color.Blue);
// Draw the help text
// Determine what help text to show depending on the current FPS target
var fpsText = "";
if (currentFps <= 0)
{
fpsText = $"FPS: unlimited ({GetFPS()})";
}
else
{
fpsText = $"FPS: {GetFPS()} (target: {currentFps})";
}
DrawText(fpsText, 10, 10, 20, Color.DarkGray);
DrawText($"Frame time: {GetFrameTime():F2} ms", 10, 30, 20, Color.DarkGray);
DrawText("Use the scroll wheel to change the fps limit, r to reset", 10, 50, 20, Color.DarkGray);
// Draw the text above the circles
DrawText("FUNC: x += GetFrameTime()*speed", 10, 90, 20, Color.Red);
DrawText("FUNC: x += speed", 10, 240, 20, Color.Blue);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - delta time");
int currentFps = 60;
Vector2 deltaCircle = new Vector2(0, (float)screenHeight / 3.0f);
Vector2 frameCircle = new Vector2(0, (float)screenHeight * (2.0f / 3.0f));
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
const float speed = 10.0f;
const float circleRadius = 32.0f;
var game = new DeltaTime();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// Adjust the FPS target based on the mouse wheel
float mouseWheel = GetMouseWheelMove();
if (mouseWheel != 0)
{
currentFps += (int)mouseWheel;
if (currentFps < 0)
{
currentFps = 0;
}
SetTargetFPS(currentFps);
}
// GetFrameTime() returns the time it took to draw the last frame, in seconds (usually called delta time)
// Uses the delta time to make the circle look like it's moving at a "consistent" speed regardless of FPS
// Multiply by 6.0 (an arbitrary value) in order to make the speed
// visually closer to the other circle (at 60 fps), for comparison
deltaCircle.X += GetFrameTime() * 6.0f * speed;
// This circle can move faster or slower visually depending on the FPS
frameCircle.X += 0.1f * speed;
// If either circle is off the screen, reset it back to the start
if (deltaCircle.X > screenWidth)
{
deltaCircle.X = 0;
}
if (frameCircle.X > screenWidth)
{
frameCircle.X = 0;
}
// Reset both circles positions
if (IsKeyPressed(KeyboardKey.R))
{
deltaCircle.X = 0;
frameCircle.X = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw both circles to the screen
DrawCircleV(deltaCircle, circleRadius, Color.Red);
DrawCircleV(frameCircle, circleRadius, Color.Blue);
// Draw the help text
// Determine what help text to show depending on the current FPS target
var fpsText = "";
if (currentFps <= 0)
{
fpsText = $"FPS: unlimited ({GetFPS()})";
}
else
{
fpsText = $"FPS: {GetFPS()} (target: {currentFps})";
}
DrawText(fpsText, 10, 10, 20, Color.DarkGray);
DrawText($"Frame time: {GetFrameTime():F2} ms", 10, 30, 20, Color.DarkGray);
DrawText("Use the scroll wheel to change the fps limit, r to reset", 10, 50, 20, Color.DarkGray);
// Draw the text above the circles
DrawText("FUNC: x += GetFrameTime()*speed", 10, 90, 20, Color.Red);
DrawText("FUNC: x += speed", 10, 240, 20, Color.Blue);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,201 @@
/*******************************************************************************************
*
* raylib [core] example - directory files
*
* Example complexity rating: [] 1/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)
*
********************************************************************************************/
// NOTE: The original example relies on raygui (GuiButton, GuiLabel, GuiListViewEx) for its UI.
// raygui is not part of the raylib-cs bindings, so the back button, directory label and file
// list view are reimplemented here with plain raylib primitives. The directory navigation
// behaviour (enter directories, go back) is preserved.
namespace Examples.Core;
public partial class DirectoryFiles : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const string FileFilter = "DIRS*;.png;.c";
public string Name => "Core / Directory Files";
public string Title => "raylib [core] example - directory files";
private string directory;
private FilePathList files;
private bool btnBackPressed;
private int listScrollIndex;
private int listItemActive;
private int listItemFocused;
public void Init()
{
directory = GetWorkingDirectoryAsString();
// Load file-paths on current working directory
// NOTE: LoadDirectoryFiles() loads files and directories by default,
// use LoadDirectoryFilesEx() for custom filters and recursive directories loading
//files = LoadDirectoryFiles(directory);
files = LoadDirectoryFilesEx(directory, FileFilter, false);
btnBackPressed = false;
listScrollIndex = 0;
listItemActive = -1;
listItemFocused = -1;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (btnBackPressed)
{
directory = GetPrevDirectoryPath(directory);
UnloadDirectoryFiles(files);
files = LoadDirectoryFilesEx(directory, FileFilter, false);
listScrollIndex = 0;
listItemActive = -1;
listItemFocused = -1;
}
if ((listItemActive >= 0) && (listItemActive < (int)files.Count))
{
string selected = files[(uint)listItemActive];
bool isDirectory = DirectoryExists(selected);
if (isDirectory)
{
directory = selected;
UnloadDirectoryFiles(files);
files = LoadDirectoryFilesEx(directory, FileFilter, false);
listScrollIndex = 0;
listItemActive = -1;
listItemFocused = -1;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
Vector2 mouse = GetMousePosition();
// Back button "<"
Rectangle backBounds = new Rectangle(40.0f, 10.0f, 48, 28);
bool backHover = CheckCollisionPointRec(mouse, backBounds);
DrawRectangleRec(backBounds, backHover ? Color.SkyBlue : Color.LightGray);
DrawRectangleLinesEx(backBounds, 1, Color.Gray);
int backTextWidth = MeasureText("<", 20);
DrawText("<", (int)(backBounds.X + (backBounds.Width - backTextWidth) / 2), (int)(backBounds.Y + 4), 20, Color.DarkGray);
btnBackPressed = backHover && IsMouseButtonReleased(MouseButton.Left);
// Current directory label
DrawText(directory, 40 + 48 + 10, 16, 20, Color.DarkGray);
// File list view
Rectangle listBounds = new Rectangle(0, 50, GetScreenWidth(), GetScreenHeight() - 50);
DrawRectangleRec(listBounds, Color.RayWhite);
DrawRectangleLinesEx(listBounds, 1, Color.Gray);
int count = (int)files.Count;
float rowHeight = 28;
int visibleRows = (int)(listBounds.Height / rowHeight);
bool mouseInList = CheckCollisionPointRec(mouse, listBounds);
if (mouseInList)
{
listScrollIndex -= (int)GetMouseWheelMove();
}
int maxScroll = Math.Max(0, count - visibleRows);
listScrollIndex = Math.Clamp(listScrollIndex, 0, maxScroll);
listItemFocused = -1;
for (int i = 0; i < visibleRows; i++)
{
int itemIndex = listScrollIndex + i;
if (itemIndex >= count)
{
break;
}
Rectangle rowRec = new Rectangle(listBounds.X + 1, listBounds.Y + 1 + i * rowHeight, listBounds.Width - 2, rowHeight);
bool rowHover = mouseInList && CheckCollisionPointRec(mouse, rowRec);
if (itemIndex == listItemActive)
{
DrawRectangleRec(rowRec, Fade(Color.SkyBlue, 0.7f));
}
else if (rowHover)
{
DrawRectangleRec(rowRec, Fade(Color.SkyBlue, 0.3f));
}
if (rowHover)
{
listItemFocused = itemIndex;
if (IsMouseButtonReleased(MouseButton.Left))
{
listItemActive = itemIndex;
}
}
DrawText(files[(uint)itemIndex], (int)rowRec.X + 40, (int)rowRec.Y + 8, 10, Color.DarkGray);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadDirectoryFiles(files);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - directory files");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new DirectoryFiles();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,83 +1,122 @@
/*******************************************************************************************
*
* raylib [core] example - Windows drop files
* raylib [core] example - drop files
*
* This example only works on platforms that support drag ref drop (Windows, Linux, OSX, Html5?)
* Example complexity rating: [] 2/4
*
* This example has been created using raylib 1.3 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* NOTE: This example only works on platforms that support drag & drop (Windows, Linux, OSX, Html5?)
*
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.3, 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) 2015-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class DropFiles
[ExcludeFromBrowser]
public partial class DropFiles : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public const int MaxFilepathRecorded = 4096;
public string Name => "Core / Drop Files";
public string Title => "raylib [core] example - drop files";
private List<string> filePaths;
public void Init()
{
// We will register a maximum of filepaths
filePaths = new();
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsFileDropped())
{
var droppedFiles = GetDroppedFiles();
for (var i = 0; i < droppedFiles.Length; i++)
{
if (filePaths.Count < (MaxFilepathRecorded - 1))
{
filePaths.Add(droppedFiles[i]);
}
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (filePaths.Count == 0)
{
DrawText("Drop your files to this window!", 100, 40, 20, Color.DarkGray);
}
else
{
DrawText("Dropped files:", 100, 40, 20, Color.DarkGray);
for (var i = 0; i < filePaths.Count; i++)
{
if (i % 2 == 0)
{
DrawRectangle(0, 85 + 40 * i, screenWidth, 40, Fade(Color.LightGray, 0.5f));
}
else
{
DrawRectangle(0, 85 + 40 * i, screenWidth, 40, Fade(Color.LightGray, 0.3f));
}
DrawText(filePaths[i], 120, 100 + 40 * i, 10, Color.Gray);
}
DrawText("Drop new files...", 100, 110 + 40 * filePaths.Count, 20, Color.DarkGray);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - drop files");
string[] files = new string[0];
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new DropFiles();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsFileDropped())
{
files = Raylib.GetDroppedFiles();
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (files.Length == 0)
{
DrawText("Drop your files to this window!", 100, 40, 20, Color.DarkGray);
}
else
{
DrawText("Dropped files:", 100, 40, 20, Color.DarkGray);
for (int i = 0; i < files.Length; i++)
{
if (i % 2 == 0)
{
DrawRectangle(0, 85 + 40 * i, screenWidth, 40, ColorAlpha(Color.LightGray, 0.5f));
}
else
{
DrawRectangle(0, 85 + 40 * i, screenWidth, 40, ColorAlpha(Color.LightGray, 0.3f));
}
DrawText(files[i], 120, 100 + 40 * i, 10, Color.Gray);
}
DrawText("Drop new files...", 100, 110 + 40 * files.Length, 20, Color.DarkGray);
}
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,169 @@
/*******************************************************************************************
*
* raylib [core] example - highdpi demo
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.0, last time updated with raylib 5.5
*
* Example contributed by Jonathan Marler (@marler8997) 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 Jonathan Marler (@marler8997)
*
********************************************************************************************/
namespace Examples.Core;
[ExcludeFromBrowser("monitor/DPI APIs are meaningless on the fixed wasm canvas")]
public partial class HighDpiDemo : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / High DPI Demo";
public string Title => "raylib [core] example - highdpi demo";
public ConfigFlags ConfigFlags => ConfigFlags.HighDpiWindow | ConfigFlags.ResizableWindow;
private int logicalGridDescY;
private int logicalGridLabelY;
private int logicalGridTop;
private int logicalGridBottom;
private int pixelGridTop;
private int pixelGridBottom;
private int pixelGridLabelY;
private int pixelGridDescY;
private int cellSize;
private float cellSizePx;
public void Init()
{
SetWindowMinSize(450, 450);
logicalGridDescY = 120;
logicalGridLabelY = logicalGridDescY + 30;
logicalGridTop = logicalGridLabelY + 30;
logicalGridBottom = logicalGridTop + 80;
pixelGridTop = logicalGridBottom - 20;
pixelGridBottom = pixelGridTop + 80;
pixelGridLabelY = pixelGridBottom + 30;
pixelGridDescY = pixelGridLabelY + 30;
cellSize = 50;
cellSizePx = (float)cellSize;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
int monitorCount = GetMonitorCount();
if ((monitorCount > 1) && IsKeyPressed(KeyboardKey.N))
{
SetWindowMonitor((GetCurrentMonitor() + 1) % monitorCount);
}
int currentMonitor = GetCurrentMonitor();
Vector2 dpiScale = GetWindowScaleDPI();
cellSizePx = ((float)cellSize) / dpiScale.X;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
int windowCenter = GetScreenWidth() / 2;
DrawTextCenter($"Dpi Scale: {dpiScale.X:F6}", windowCenter, 30, 40, Color.DarkGray);
DrawTextCenter($"Monitor: {currentMonitor + 1}/{monitorCount} ([N] next monitor)", windowCenter, 70, 20, Color.LightGray);
DrawTextCenter($"Window is {GetScreenWidth()} \"logical points\" wide", windowCenter, logicalGridDescY, 20, Color.Orange);
bool odd = true;
for (int i = cellSize; i < GetScreenWidth(); i += cellSize, odd = !odd)
{
if (odd)
{
DrawRectangle(i, logicalGridTop, cellSize, logicalGridBottom - logicalGridTop, Color.Orange);
}
DrawTextCenter($"{i}", i, logicalGridLabelY, 10, Color.LightGray);
DrawLine(i, logicalGridLabelY + 10, i, logicalGridBottom, Color.Gray);
}
odd = true;
const int minTextSpace = 30;
int lastTextX = -minTextSpace;
for (int i = cellSize; i < GetRenderWidth(); i += cellSize, odd = !odd)
{
int x = (int)(((float)i) / dpiScale.X);
if (odd)
{
DrawRectangle(x, pixelGridTop, (int)cellSizePx, pixelGridBottom - pixelGridTop, new Color(0, 121, 241, 100));
}
DrawLine(x, pixelGridTop, (int)(((float)i) / dpiScale.X), pixelGridLabelY - 10, Color.Gray);
if ((x - lastTextX) >= minTextSpace)
{
DrawTextCenter($"{i}", x, pixelGridLabelY, 10, Color.LightGray);
lastTextX = x;
}
}
DrawTextCenter($"Window is {GetRenderWidth()} \"physical pixels\" wide", windowCenter, pixelGridDescY, 20, Color.Blue);
string text = "Can you see this?";
Vector2 size = MeasureTextEx(GetFontDefault(), text, 20, 3);
Vector2 pos = new Vector2(GetScreenWidth() - size.X - 5, GetScreenHeight() - size.Y - 5);
DrawTextEx(GetFontDefault(), text, pos, 20, 3, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
// Draw text centered on the given position
private static void DrawTextCenter(string text, int x, int y, int fontSize, Color color)
{
Vector2 size = MeasureTextEx(GetFontDefault(), text, (float)fontSize, 3);
Vector2 pos = new Vector2(x - size.X / 2, y - size.Y / 2);
DrawTextEx(GetFontDefault(), text, pos, (float)fontSize, 3, color);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.HighDpiWindow | ConfigFlags.ResizableWindow);
InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi demo");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new HighDpiDemo();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,141 @@
/*******************************************************************************************
*
* raylib [core] example - highdpi testbed
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.0
*
* Example contributed by Ramon Santamaria (@raysan5) 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 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Core;
[ExcludeFromBrowser("fullscreen/borderless/monitor APIs are meaningless on the fixed wasm canvas")]
public partial class HighDpiTestbed : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / High DPI Testbed";
public string Title => "raylib [core] example - highdpi testbed";
public ConfigFlags ConfigFlags => ConfigFlags.ResizableWindow | ConfigFlags.HighDpiWindow;
private Vector2 scaleDpi;
private Vector2 mousePos;
private int currentMonitor;
private Vector2 windowPos;
private int gridSpacing; // Grid spacing in pixels
public void Init()
{
scaleDpi = GetWindowScaleDPI();
mousePos = GetMousePosition();
currentMonitor = GetCurrentMonitor();
windowPos = GetWindowPosition();
gridSpacing = 40;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
mousePos = GetMousePosition();
currentMonitor = GetCurrentMonitor();
scaleDpi = GetWindowScaleDPI();
windowPos = GetWindowPosition();
if (IsKeyPressed(KeyboardKey.Space))
{
ToggleBorderlessWindowed();
}
if (IsKeyPressed(KeyboardKey.F))
{
ToggleFullscreen();
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw grid
for (int h = 0; h < GetScreenHeight() / gridSpacing + 1; h++)
{
DrawText($"{h * gridSpacing:D2}", 4, h * gridSpacing - 4, 10, Color.Gray);
DrawLine(24, h * gridSpacing, GetScreenWidth(), h * gridSpacing, Color.LightGray);
}
for (int v = 0; v < GetScreenWidth() / gridSpacing + 1; v++)
{
DrawText($"{v * gridSpacing:D2}", v * gridSpacing - 10, 4, 10, Color.Gray);
DrawLine(v * gridSpacing, 20, v * gridSpacing, GetScreenHeight(), Color.LightGray);
}
// Draw UI info
DrawText($"CURRENT MONITOR: {currentMonitor + 1}/{GetMonitorCount()} ({GetMonitorWidth(currentMonitor)}x{GetMonitorHeight(currentMonitor)})", 50, 50, 20, Color.DarkGray);
DrawText($"WINDOW POSITION: {(int)windowPos.X}x{(int)windowPos.Y}", 50, 90, 20, Color.DarkGray);
DrawText($"SCREEN SIZE: {GetScreenWidth()}x{GetScreenHeight()}", 50, 130, 20, Color.DarkGray);
DrawText($"RENDER SIZE: {GetRenderWidth()}x{GetRenderHeight()}", 50, 170, 20, Color.DarkGray);
DrawText($"SCALE FACTOR: {scaleDpi.X:F2}x{scaleDpi.Y:F2}", 50, 210, 20, Color.Gray);
// Draw reference rectangles, top-left and bottom-right corners
DrawRectangle(0, 0, 30, 60, Color.Red);
DrawRectangle(GetScreenWidth() - 30, GetScreenHeight() - 60, 30, 60, Color.Blue);
// Draw mouse position
DrawCircleV(GetMousePosition(), 20, Color.Maroon);
DrawRectangleRec(new Rectangle(mousePos.X - 25, mousePos.Y, 50, 2), Color.Black);
DrawRectangleRec(new Rectangle(mousePos.X, mousePos.Y - 25, 2, 50), Color.Black);
DrawText($"[{GetMouseX()},{GetMouseY()}]", (int)mousePos.X - 44,
(mousePos.Y > GetScreenHeight() - 60) ? (int)mousePos.Y - 46 : (int)mousePos.Y + 30, 20, Color.Black);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
// TODO: Unload all loaded resources at this point
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(ConfigFlags.ResizableWindow | ConfigFlags.HighDpiWindow);
InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi testbed");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new HighDpiTestbed();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,255 @@
/*******************************************************************************************
*
* raylib [core] example - input actions
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.6
*
* Example contributed by Jett (@JettMonstersGoBoom) 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 Jett (@JettMonstersGoBoom)
*
********************************************************************************************/
// Simple example for decoding input as actions, allowing remapping of input to different keys or gamepad buttons
// For example instead of using `IsKeyDown(KEY_LEFT)`, you can use `IsActionDown(ACTION_LEFT)`
// which can be reassigned to e.g. KEY_A and also assigned to a gamepad button. the action will trigger with either gamepad or keys
namespace Examples.Core;
public partial class InputActions : IExample
{
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
private enum ActionType
{
NoAction = 0,
ActionUp,
ActionDown,
ActionLeft,
ActionRight,
ActionFire,
MaxAction
}
// Key and button inputs
private struct ActionInput
{
public KeyboardKey Key;
public GamepadButton Button;
}
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Input Actions";
public string Title => "raylib [core] example - input actions";
private int gamepadIndex; // Gamepad default index
private ActionInput[] actionInputs;
private int actionSet;
private bool releaseAction;
private Vector2 position;
private Vector2 size;
public void Init()
{
gamepadIndex = 0;
actionInputs = new ActionInput[(int)ActionType.MaxAction];
// Set default actions
actionSet = 0;
SetActionsDefault();
releaseAction = false;
position = new Vector2(400.0f, 200.0f);
size = new Vector2(40.0f, 40.0f);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
gamepadIndex = 0; // Set gamepad being checked
if (IsActionDown(ActionType.ActionUp))
{
position.Y -= 2;
}
if (IsActionDown(ActionType.ActionDown))
{
position.Y += 2;
}
if (IsActionDown(ActionType.ActionLeft))
{
position.X -= 2;
}
if (IsActionDown(ActionType.ActionRight))
{
position.X += 2;
}
if (IsActionPressed(ActionType.ActionFire))
{
position.X = (screenWidth - size.X) / 2;
position.Y = (screenHeight - size.Y) / 2;
}
// Register release action for one frame
releaseAction = false;
if (IsActionReleased(ActionType.ActionFire))
{
releaseAction = true;
}
// Switch control scheme by pressing TAB
if (IsKeyPressed(KeyboardKey.Tab))
{
actionSet = (actionSet == 0) ? 1 : 0;
if (actionSet == 0)
{
SetActionsDefault();
}
else
{
SetActionsCursor();
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.Gray);
DrawRectangleV(position, size, releaseAction ? Color.Blue : Color.Red);
DrawText((actionSet == 0) ? "Current input set: WASD (default)" : "Current input set: Arrow keys", 10, 10, 20, Color.White);
DrawText("Use TAB key to toggles Actions keyset", 10, 50, 20, Color.Green);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Check action key/button pressed
// NOTE: Combines key pressed and gamepad button pressed in one action
private bool IsActionPressed(ActionType action)
{
bool result = false;
if (action < ActionType.MaxAction)
{
result = (IsKeyPressed(actionInputs[(int)action].Key) || IsGamepadButtonPressed(gamepadIndex, actionInputs[(int)action].Button));
}
return result;
}
// Check action key/button released
// NOTE: Combines key released and gamepad button released in one action
private bool IsActionReleased(ActionType action)
{
bool result = false;
if (action < ActionType.MaxAction)
{
result = (IsKeyReleased(actionInputs[(int)action].Key) || IsGamepadButtonReleased(gamepadIndex, actionInputs[(int)action].Button));
}
return result;
}
// Check action key/button down
// NOTE: Combines key down and gamepad button down in one action
private bool IsActionDown(ActionType action)
{
bool result = false;
if (action < ActionType.MaxAction)
{
result = (IsKeyDown(actionInputs[(int)action].Key) || IsGamepadButtonDown(gamepadIndex, actionInputs[(int)action].Button));
}
return result;
}
// Set the "default" keyset
// NOTE: Here WASD and gamepad buttons on the left side for movement
private void SetActionsDefault()
{
actionInputs[(int)ActionType.ActionUp].Key = KeyboardKey.W;
actionInputs[(int)ActionType.ActionDown].Key = KeyboardKey.S;
actionInputs[(int)ActionType.ActionLeft].Key = KeyboardKey.A;
actionInputs[(int)ActionType.ActionRight].Key = KeyboardKey.D;
actionInputs[(int)ActionType.ActionFire].Key = KeyboardKey.Space;
actionInputs[(int)ActionType.ActionUp].Button = GamepadButton.LeftFaceUp;
actionInputs[(int)ActionType.ActionDown].Button = GamepadButton.LeftFaceDown;
actionInputs[(int)ActionType.ActionLeft].Button = GamepadButton.LeftFaceLeft;
actionInputs[(int)ActionType.ActionRight].Button = GamepadButton.LeftFaceRight;
actionInputs[(int)ActionType.ActionFire].Button = GamepadButton.RightFaceDown;
}
// Set the "alternate" keyset
// NOTE: Here cursor keys and gamepad buttons on the right side for movement
private void SetActionsCursor()
{
actionInputs[(int)ActionType.ActionUp].Key = KeyboardKey.Up;
actionInputs[(int)ActionType.ActionDown].Key = KeyboardKey.Down;
actionInputs[(int)ActionType.ActionLeft].Key = KeyboardKey.Left;
actionInputs[(int)ActionType.ActionRight].Key = KeyboardKey.Right;
actionInputs[(int)ActionType.ActionFire].Key = KeyboardKey.Space;
actionInputs[(int)ActionType.ActionUp].Button = GamepadButton.RightFaceUp;
actionInputs[(int)ActionType.ActionDown].Button = GamepadButton.RightFaceDown;
actionInputs[(int)ActionType.ActionLeft].Button = GamepadButton.RightFaceLeft;
actionInputs[(int)ActionType.ActionRight].Button = GamepadButton.RightFaceRight;
actionInputs[(int)ActionType.ActionFire].Button = GamepadButton.LeftFaceDown;
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - input actions");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new InputActions();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,32 +1,31 @@
/*******************************************************************************************
*
* raylib [core] example - input gamepad
*
* Example complexity rating: [] 1/4
*
* NOTE: This example requires a Gamepad connected to the system
* raylib is configured to work with the following gamepads:
* - Xbox 360 Controller (Xbox 360, Xbox One)
* - PLAYSTATION(R)3 Controller
* Check raylib.h for buttons configuration
*
* Example originally created with raylib 1.1, 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) 2013-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
*
* raylib [core] example - input gamepad
*
* Example complexity rating: [] 1/4
*
* NOTE: This example requires a Gamepad connected to the system
* raylib is configured to work with the following gamepads:
* - Xbox 360 Controller (Xbox 360, Xbox One)
* - PLAYSTATION(R)3 Controller
* Check raylib.h for buttons configuration
*
* Example originally created with raylib 1.1, 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) 2013-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Core;
public class InputGamepad
public partial class InputGamepad : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
// NOTE: Gamepad name ID depends on drivers and OS
// These are some possible names the gamepads could have.
public const string XBOX_ALIAS_1 = "xbox";
@ -34,320 +33,503 @@ public class InputGamepad
public const string PS_ALIAS_1 = "playstation";
public const string PS_ALIAS_2 = "sony";
// Set axis deadzones
private const float leftStickDeadzoneX = 0.1f;
private const float leftStickDeadzoneY = 0.1f;
private const float rightStickDeadzoneX = 0.1f;
private const float rightStickDeadzoneY = 0.1f;
private const float leftTriggerDeadzone = -0.9f;
private const float rightTriggerDeadzone = -0.9f;
private Texture2D texPs3Pad;
private Texture2D texXboxPad;
private Rectangle vibrateButton;
private int gamepad; // which gamepad to display
public string Name => "Core / Input Gamepad";
public string Title => "raylib [core] example - input gamepad";
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
public void Init()
{
texPs3Pad = LoadTexture("resources/ps3.png");
texXboxPad = LoadTexture("resources/xbox.png");
vibrateButton = new Rectangle();
gamepad = 0; // which gamepad to display
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.Left) && gamepad > 0)
{
gamepad--;
}
if (IsKeyPressed(KeyboardKey.Right))
{
gamepad++;
}
var mousePosition = GetMousePosition();
vibrateButton = new Rectangle(10, 70.0f + 20 * GetGamepadAxisCount(gamepad) + 20, 75, 24);
if (IsMouseButtonPressed(MouseButton.Left) && CheckCollisionPointRec(mousePosition, vibrateButton))
{
SetGamepadVibration(gamepad, 1.0f, 1.0f, 1.0f);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (IsGamepadAvailable(gamepad))
{
var gamepadName = GetGamepadName_(gamepad);
DrawText($"GP{gamepad}: {gamepadName}", 10, 10, 10, Color.Black);
// Get axis values
var leftStickX = GetGamepadAxisMovement(gamepad, GamepadAxis.LeftX);
var leftStickY = GetGamepadAxisMovement(gamepad, GamepadAxis.LeftY);
var rightStickX = GetGamepadAxisMovement(gamepad, GamepadAxis.RightX);
var rightStickY = GetGamepadAxisMovement(gamepad, GamepadAxis.RightY);
var leftTrigger = GetGamepadAxisMovement(gamepad, GamepadAxis.LeftTrigger);
var rightTrigger = GetGamepadAxisMovement(gamepad, GamepadAxis.RightTrigger);
// Calculate deadzones
if (leftStickX > -leftStickDeadzoneX && leftStickX < leftStickDeadzoneX)
{
leftStickX = 0.0f;
}
if (leftStickY > -leftStickDeadzoneY && leftStickY < leftStickDeadzoneY)
{
leftStickY = 0.0f;
}
if (rightStickX > -rightStickDeadzoneX && rightStickX < rightStickDeadzoneX)
{
rightStickX = 0.0f;
}
if (rightStickY > -rightStickDeadzoneY && rightStickY < rightStickDeadzoneY)
{
rightStickY = 0.0f;
}
if (leftTrigger < leftTriggerDeadzone)
{
leftTrigger = -1.0f;
}
if (rightTrigger < rightTriggerDeadzone)
{
rightTrigger = -1.0f;
}
if (gamepadName.Contains(XBOX_ALIAS_1, StringComparison.OrdinalIgnoreCase) ||
gamepadName.Contains(XBOX_ALIAS_2, StringComparison.OrdinalIgnoreCase))
{
DrawTexture(texXboxPad, 0, 0, Color.DarkGray);
// Draw buttons: xbox home
if (IsGamepadButtonDown(gamepad, GamepadButton.Middle))
{
DrawCircle(394, 89, 19, Color.Red);
}
// Draw buttons: basic
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight))
{
DrawCircle(436, 150, 9, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft))
{
DrawCircle(352, 150, 9, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft))
{
DrawCircle(501, 151, 15, Color.Blue);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown))
{
DrawCircle(536, 187, 15, Color.Lime);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight))
{
DrawCircle(572, 151, 15, Color.Maroon);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp))
{
DrawCircle(536, 115, 15, Color.Gold);
}
// Draw buttons: d-pad
DrawRectangle(317, 202, 19, 71, Color.Black);
DrawRectangle(293, 228, 69, 19, Color.Black);
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp))
{
DrawRectangle(317, 202, 19, 26, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown))
{
DrawRectangle(317, 202 + 45, 19, 26, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft))
{
DrawRectangle(292, 228, 25, 19, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight))
{
DrawRectangle(292 + 44, 228, 26, 19, Color.Red);
}
// Draw buttons: left-right back
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1))
{
DrawCircle(259, 61, 20, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1))
{
DrawCircle(536, 61, 20, Color.Red);
}
// Draw axis: left joystick
var leftGamepadColor = Color.Black;
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftThumb))
{
leftGamepadColor = Color.Red;
}
DrawCircle(259, 152, 39, Color.Black);
DrawCircle(259, 152, 34, Color.LightGray);
DrawCircle(259 + (int)(leftStickX * 20), 152 + (int)(leftStickY * 20), 25, leftGamepadColor);
// Draw axis: right joystick
var rightGamepadColor = Color.Black;
if (IsGamepadButtonDown(gamepad, GamepadButton.RightThumb))
{
rightGamepadColor = Color.Red;
}
DrawCircle(461, 237, 38, Color.Black);
DrawCircle(461, 237, 33, Color.LightGray);
DrawCircle(461 + (int)(rightStickX * 20), 237 + (int)(rightStickY * 20), 25, rightGamepadColor);
// Draw axis: left-right triggers
DrawRectangle(170, 30, 15, 70, Color.Gray);
DrawRectangle(604, 30, 15, 70, Color.Gray);
DrawRectangle(170, 30, 15, (int)(((1 + leftTrigger) / 2) * 70), Color.Red);
DrawRectangle(604, 30, 15, (int)(((1 + rightTrigger) / 2) * 70), Color.Red);
}
else if (gamepadName.Contains(PS_ALIAS_1, StringComparison.OrdinalIgnoreCase) || gamepadName.Contains(PS_ALIAS_2, StringComparison.OrdinalIgnoreCase))
{
DrawTexture(texPs3Pad, 0, 0, Color.DarkGray);
// Draw buttons: ps
if (IsGamepadButtonDown(gamepad, GamepadButton.Middle))
{
DrawCircle(396, 222, 13, Color.Red);
}
// Draw buttons: basic
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft))
{
DrawRectangle(328, 170, 32, 13, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight))
{
DrawTriangle(
new Vector2(436, 168),
new Vector2(436, 185),
new Vector2(464, 177),
Color.Red
);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp))
{
DrawCircle(557, 144, 13, Color.Lime);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight))
{
DrawCircle(586, 173, 13, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown))
{
DrawCircle(557, 203, 13, Color.Violet);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft))
{
DrawCircle(527, 173, 13, Color.Pink);
}
// Draw buttons: d-pad
DrawRectangle(225, 132, 24, 84, Color.Black);
DrawRectangle(195, 161, 84, 25, Color.Black);
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp))
{
DrawRectangle(225, 132, 24, 29, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown))
{
DrawRectangle(225, 132 + 54, 24, 30, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft))
{
DrawRectangle(195, 161, 30, 25, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight))
{
DrawRectangle(195 + 54, 161, 30, 25, Color.Red);
}
// Draw buttons: left-right back buttons
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1))
{
DrawCircle(239, 82, 20, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1))
{
DrawCircle(557, 82, 20, Color.Red);
}
// Draw axis: left joystick
var leftGamepadColor = Color.Black;
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftThumb))
{
leftGamepadColor = Color.Red;
}
DrawCircle(319, 255, 35, Color.Black);
DrawCircle(319, 255, 31, Color.LightGray);
DrawCircle(319 + (int)(leftStickX * 20), 255 + (int)(leftStickY * 20), 25, leftGamepadColor);
// Draw axis: right joystick
var rightGamepadColor = Color.Black;
if (IsGamepadButtonDown(gamepad, GamepadButton.RightThumb))
{
rightGamepadColor = Color.Red;
}
DrawCircle(475, 255, 35, Color.Black);
DrawCircle(475, 255, 31, Color.LightGray);
DrawCircle(475 + (int)(rightStickX * 20), 255 + (int)(rightStickY * 20), 25, rightGamepadColor);
// Draw axis: left-right triggers
DrawRectangle(169, 48, 15, 70, Color.Gray);
DrawRectangle(611, 48, 15, 70, Color.Gray);
DrawRectangle(169, 48, 15, (int)(((1 + leftTrigger) / 2) * 70), Color.Red);
DrawRectangle(611, 48, 15, (int)(((1 + rightTrigger) / 2) * 70), Color.Red);
}
else
{
// Draw background: generic
DrawRectangleRounded(new Rectangle(175, 110, 460, 220), 0.3f, 16, Color.DarkGray);
// Draw buttons: basic
DrawCircle(365, 170, 12, Color.RayWhite);
DrawCircle(405, 170, 12, Color.RayWhite);
DrawCircle(445, 170, 12, Color.RayWhite);
DrawCircle(516, 191, 17, Color.RayWhite);
DrawCircle(551, 227, 17, Color.RayWhite);
DrawCircle(587, 191, 17, Color.RayWhite);
DrawCircle(551, 155, 17, Color.RayWhite);
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft))
{
DrawCircle(365, 170, 10, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.Middle))
{
DrawCircle(405, 170, 10, Color.Green);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight))
{
DrawCircle(445, 170, 10, Color.Blue);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft))
{
DrawCircle(516, 191, 15, Color.Gold);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown))
{
DrawCircle(551, 227, 15, Color.Blue);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight))
{
DrawCircle(587, 191, 15, Color.Green);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp))
{
DrawCircle(551, 155, 15, Color.Red);
}
// Draw buttons: d-pad
DrawRectangle(245, 145, 28, 88, Color.RayWhite);
DrawRectangle(215, 174, 88, 29, Color.RayWhite);
DrawRectangle(247, 147, 24, 84, Color.Black);
DrawRectangle(217, 176, 84, 25, Color.Black);
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp))
{
DrawRectangle(247, 147, 24, 29, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown))
{
DrawRectangle(247, 147 + 54, 24, 30, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft))
{
DrawRectangle(217, 176, 30, 25, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight))
{
DrawRectangle(217 + 54, 176, 30, 25, Color.Red);
}
// Draw buttons: left-right back
DrawRectangleRounded(new Rectangle(215, 98, 100, 10), 0.5f, 16, Color.DarkGray);
DrawRectangleRounded(new Rectangle(495, 98, 100, 10), 0.5f, 16, Color.DarkGray);
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1))
{
DrawRectangleRounded(new Rectangle(215, 98, 100, 10), 0.5f, 16, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1))
{
DrawRectangleRounded(new Rectangle(495, 98, 100, 10), 0.5f, 16, Color.Red);
}
// Draw axis: left joystick
var leftGamepadColor = Color.Black;
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftThumb))
{
leftGamepadColor = Color.Red;
}
DrawCircle(345, 260, 40, Color.Black);
DrawCircle(345, 260, 35, Color.LightGray);
DrawCircle(345 + (int)(leftStickX * 20), 260 + (int)(leftStickY * 20), 25, leftGamepadColor);
// Draw axis: right joystick
var rightGamepadColor = Color.Black;
if (IsGamepadButtonDown(gamepad, GamepadButton.RightThumb))
{
rightGamepadColor = Color.Red;
}
DrawCircle(465, 260, 40, Color.Black);
DrawCircle(465, 260, 35, Color.LightGray);
DrawCircle(465 + (int)(rightStickX * 20), 260 + (int)(rightStickY * 20), 25, rightGamepadColor);
// Draw axis: left-right triggers
DrawRectangle(151, 110, 15, 70, Color.Gray);
DrawRectangle(644, 110, 15, 70, Color.Gray);
DrawRectangle(151, 110, 15, (int)(((1 + leftTrigger) / 2) * 70), Color.Red);
DrawRectangle(644, 110, 15, (int)(((1 + rightTrigger) / 2) * 70), Color.Red);
}
DrawText($"DETECTED AXIS [{GetGamepadAxisCount(gamepad)}]:", 10, 50, 10, Color.Maroon);
for (var i = 0; i < GetGamepadAxisCount(gamepad); i++)
{
DrawText(
$"AXIS {i}: {GetGamepadAxisMovement(gamepad, (GamepadAxis)i):F2}",
20,
70 + 20 * i,
10,
Color.DarkGray
);
}
// Draw vibrate button
DrawRectangleRec(vibrateButton, Color.SkyBlue);
DrawText("VIBRATE", (int)(vibrateButton.X + 14), (int)(vibrateButton.Y + 1), 10, Color.DarkGray);
if (GetGamepadButtonPressed() != (int)GamepadButton.Unknown)
{
DrawText($"DETECTED BUTTON: {GetGamepadButtonPressed()}", 10, 430, 10, Color.Red);
}
else
{
DrawText("DETECTED BUTTON: NONE", 10, 430, 10, Color.Gray);
}
}
else
{
DrawText($"GP{gamepad}: NOT DETECTED", 10, 10, 10, Color.Gray);
DrawTexture(texXboxPad, 0, 0, Color.LightGray);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadTexture(texPs3Pad);
UnloadTexture(texXboxPad);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
SetConfigFlags(ConfigFlags.Msaa4xHint); // Set MSAA 4X hint before windows creation
// Set MSAA 4X hint before windows creation
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [core] example - gamepad input");
InitWindow(screenWidth, screenHeight, "raylib [core] example - input gamepad");
Texture2D texPs3Pad = LoadTexture("resources/ps3.png");
Texture2D texXboxPad = LoadTexture("resources/xbox.png");
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
int gamepad = 0;
Rectangle vibrateButton = new Rectangle();
var game = new InputGamepad();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.Left) && gamepad > 0)
{
gamepad--;
}
if (IsKeyPressed(KeyboardKey.Right))
{
gamepad++;
}
Vector2 mousePosition = GetMousePosition();
vibrateButton = new Rectangle(10, 70.0f + 20 * GetGamepadAxisCount(gamepad) + 20, 75, 24);
if (IsMouseButtonPressed(MouseButton.Left) && CheckCollisionPointRec(mousePosition, vibrateButton))
{
SetGamepadVibration(gamepad, 1.0f, 1.0f, 1.0f);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (IsGamepadAvailable(gamepad))
{
string gamepadName = GetGamepadName_(gamepad);
DrawText($"GP{gamepad}: {gamepadName}", 10, 10, 10, Color.Black);
if (gamepadName.Contains(XBOX_ALIAS_1, StringComparison.OrdinalIgnoreCase) ||
gamepadName.Contains(XBOX_ALIAS_2, StringComparison.OrdinalIgnoreCase))
{
DrawTexture(texXboxPad, 0, 0, Color.DarkGray);
// Draw buttons: xbox home
if (IsGamepadButtonDown(gamepad, GamepadButton.Middle))
{
DrawCircle(394, 89, 19, Color.Red);
}
// Draw buttons: basic
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight))
{
DrawCircle(436, 150, 9, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft))
{
DrawCircle(352, 150, 9, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft))
{
DrawCircle(501, 151, 15, Color.Blue);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown))
{
DrawCircle(536, 187, 15, Color.Lime);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight))
{
DrawCircle(572, 151, 15, Color.Maroon);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp))
{
DrawCircle(536, 115, 15, Color.Gold);
}
// Draw buttons: d-pad
DrawRectangle(317, 202, 19, 71, Color.Black);
DrawRectangle(293, 228, 69, 19, Color.Black);
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp))
{
DrawRectangle(317, 202, 19, 26, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown))
{
DrawRectangle(317, 202 + 45, 19, 26, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft))
{
DrawRectangle(292, 228, 25, 19, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight))
{
DrawRectangle(292 + 44, 228, 26, 19, Color.Red);
}
// Draw buttons: left-right back
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1))
{
DrawCircle(259, 61, 20, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1))
{
DrawCircle(536, 61, 20, Color.Red);
}
// Draw axis: left joystick
DrawCircle(259, 152, 39, Color.Black);
DrawCircle(259, 152, 34, Color.LightGray);
DrawCircle(
259 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftX) * 20),
152 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftY) * 20),
25,
Color.Black
);
// Draw axis: right joystick
DrawCircle(461, 237, 38, Color.Black);
DrawCircle(461, 237, 33, Color.LightGray);
DrawCircle(
461 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.RightX) * 20),
237 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.RightY) * 20),
25, Color.Black
);
// Draw axis: left-right triggers
float leftTriggerX = GetGamepadAxisMovement(gamepad, GamepadAxis.LeftTrigger);
float rightTriggerX = GetGamepadAxisMovement(gamepad, GamepadAxis.RightTrigger);
DrawRectangle(170, 30, 15, 70, Color.Gray);
DrawRectangle(604, 30, 15, 70, Color.Gray);
DrawRectangle(170, 30, 15, (int)(((1.0f + leftTriggerX) / 2.0f) * 70), Color.Red);
DrawRectangle(604, 30, 15, (int)(((1.0f + rightTriggerX) / 2.0f) * 70), Color.Red);
}
else if (gamepadName.Contains(PS_ALIAS_1, StringComparison.OrdinalIgnoreCase) || gamepadName.Contains(PS_ALIAS_2, StringComparison.OrdinalIgnoreCase))
{
DrawTexture(texPs3Pad, 0, 0, Color.DarkGray);
// Draw buttons: ps
if (IsGamepadButtonDown(gamepad, GamepadButton.Middle))
{
DrawCircle(396, 222, 13, Color.Red);
}
// Draw buttons: basic
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleLeft))
{
DrawRectangle(328, 170, 32, 13, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.MiddleRight))
{
DrawTriangle(
new Vector2(436, 168),
new Vector2(436, 185),
new Vector2(464, 177),
Color.Red
);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceUp))
{
DrawCircle(557, 144, 13, Color.Lime);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceRight))
{
DrawCircle(586, 173, 13, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceDown))
{
DrawCircle(557, 203, 13, Color.Violet);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightFaceLeft))
{
DrawCircle(527, 173, 13, Color.Pink);
}
// Draw buttons: d-pad
DrawRectangle(225, 132, 24, 84, Color.Black);
DrawRectangle(195, 161, 84, 25, Color.Black);
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceUp))
{
DrawRectangle(225, 132, 24, 29, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceDown))
{
DrawRectangle(225, 132 + 54, 24, 30, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceLeft))
{
DrawRectangle(195, 161, 30, 25, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftFaceRight))
{
DrawRectangle(195 + 54, 161, 30, 25, Color.Red);
}
// Draw buttons: left-right back buttons
if (IsGamepadButtonDown(gamepad, GamepadButton.LeftTrigger1))
{
DrawCircle(239, 82, 20, Color.Red);
}
if (IsGamepadButtonDown(gamepad, GamepadButton.RightTrigger1))
{
DrawCircle(557, 82, 20, Color.Red);
}
// Draw axis: left joystick
DrawCircle(319, 255, 35, Color.Black);
DrawCircle(319, 255, 31, Color.LightGray);
DrawCircle(
319 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftX) * 20),
255 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.LeftY) * 20),
25,
Color.Black
);
// Draw axis: right joystick
DrawCircle(475, 255, 35, Color.Black);
DrawCircle(475, 255, 31, Color.LightGray);
DrawCircle(
475 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.RightX) * 20),
255 + (int)(GetGamepadAxisMovement(gamepad, GamepadAxis.RightY) * 20),
25,
Color.Black
);
// Draw axis: left-right triggers
float leftTriggerX = GetGamepadAxisMovement(gamepad, GamepadAxis.LeftTrigger);
float rightTriggerX = GetGamepadAxisMovement(gamepad, GamepadAxis.RightTrigger);
DrawRectangle(169, 48, 15, 70, Color.Gray);
DrawRectangle(611, 48, 15, 70, Color.Gray);
DrawRectangle(169, 48, 15, (int)(((1.0f - leftTriggerX) / 2.0f) * 70), Color.Red);
DrawRectangle(611, 48, 15, (int)(((1.0f - rightTriggerX) / 2.0f) * 70), Color.Red);
}
else
{
DrawText("- GENERIC GAMEPAD -", 280, 180, 20, Color.Gray);
// TODO: Draw generic gamepad
}
DrawText($"DETECTED AXIS [{GetGamepadAxisCount(gamepad)}]:", 10, 50, 10, Color.Maroon);
for (int i = 0; i < GetGamepadAxisCount(gamepad); i++)
{
DrawText(
$"AXIS {i}: {GetGamepadAxisMovement(gamepad, (GamepadAxis)i)}",
20,
70 + 20 * i,
10,
Color.DarkGray
);
}
DrawRectangleRec(vibrateButton, Color.SkyBlue);
DrawText("VIBRATE", (int)(vibrateButton.X + 14), (int)(vibrateButton.Y + 1), 10, Color.DarkGray);
if (GetGamepadButtonPressed() != (int)GamepadButton.Unknown)
{
DrawText($"DETECTED BUTTON: {GetGamepadButtonPressed()}", 10, 430, 10, Color.Red);
}
else
{
DrawText("DETECTED BUTTON: NONE", 10, 430, 10, Color.Gray);
}
}
else
{
DrawText($"GP{gamepad}: NOT DETECTED", 10, 10, 10, Color.Gray);
DrawTexture(texXboxPad, 0, 0, Color.LightGray);
}
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadTexture(texPs3Pad);
UnloadTexture(texXboxPad);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -13,150 +13,178 @@
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class InputGestures
public partial class InputGestures : IExample
{
public const int MaxGestureStrings = 20;
private const int screenWidth = 800;
private const int screenHeight = 450;
private Vector2 touchPosition;
private Rectangle touchArea;
private int gesturesCount;
private string[] gestureStrings;
private Gesture currentGesture;
private Gesture lastGesture;
public string Name => "Core / Input Gestures";
public string Title => "raylib [core] example - input gestures";
public void Init()
{
touchPosition = new(0, 0);
touchArea = new(220, 10, screenWidth - 230, screenHeight - 20);
gesturesCount = 0;
gestureStrings = new string[MaxGestureStrings];
currentGesture = Gesture.None;
lastGesture = Gesture.None;
// SetGesturesEnabled(0b0000000000001001); // Enable only some gestures to be detected
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
lastGesture = currentGesture;
currentGesture = GetGestureDetected();
touchPosition = GetTouchPosition(0);
if (CheckCollisionPointRec(touchPosition, touchArea) && (currentGesture != Gesture.None))
{
if (currentGesture != lastGesture)
{
// Store gesture string
switch ((Gesture)currentGesture)
{
case Gesture.Tap:
gestureStrings[gesturesCount] = "GESTURE TAP";
break;
case Gesture.DoubleTap:
gestureStrings[gesturesCount] = "GESTURE DOUBLETAP";
break;
case Gesture.Hold:
gestureStrings[gesturesCount] = "GESTURE HOLD";
break;
case Gesture.Drag:
gestureStrings[gesturesCount] = "GESTURE DRAG";
break;
case Gesture.SwipeRight:
gestureStrings[gesturesCount] = "GESTURE SWIPE RIGHT";
break;
case Gesture.SwipeLeft:
gestureStrings[gesturesCount] = "GESTURE SWIPE LEFT";
break;
case Gesture.SwipeUp:
gestureStrings[gesturesCount] = "GESTURE SWIPE UP";
break;
case Gesture.SwipeDown:
gestureStrings[gesturesCount] = "GESTURE SWIPE DOWN";
break;
case Gesture.PinchIn:
gestureStrings[gesturesCount] = "GESTURE PINCH IN";
break;
case Gesture.PinchOut:
gestureStrings[gesturesCount] = "GESTURE PINCH OUT";
break;
default:
break;
}
gesturesCount++;
// Reset gestures strings
if (gesturesCount >= MaxGestureStrings)
{
for (var i = 0; i < MaxGestureStrings; i++)
{
gestureStrings[i] = " ";
}
gesturesCount = 0;
}
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawRectangleRec(touchArea, Color.Gray);
DrawRectangle(225, 15, screenWidth - 240, screenHeight - 30, Color.RayWhite);
DrawText("GESTURES TEST AREA", screenWidth - 270, screenHeight - 40, 20, Fade(Color.Gray, 0.5f));
for (var i = 0; i < gesturesCount; i++)
{
if (i % 2 == 0)
{
DrawRectangle(10, 30 + 20 * i, 200, 20, Fade(Color.LightGray, 0.5f));
}
else
{
DrawRectangle(10, 30 + 20 * i, 200, 20, Fade(Color.LightGray, 0.3f));
}
if (i < gesturesCount - 1)
{
DrawText(gestureStrings[i], 35, 36 + 20 * i, 10, Color.DarkGray);
}
else
{
DrawText(gestureStrings[i], 35, 36 + 20 * i, 10, Color.Maroon);
}
}
DrawRectangleLines(10, 29, 200, screenHeight - 50, Color.Gray);
DrawText("DETECTED GESTURES", 50, 15, 10, Color.Gray);
if (currentGesture != Gesture.None)
{
DrawCircleV(touchPosition, 30, Color.Maroon);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures");
Vector2 touchPosition = new(0, 0);
Rectangle touchArea = new(220, 10, screenWidth - 230, screenHeight - 20);
int gesturesCount = 0;
string[] gestureStrings = new string[MaxGestureStrings];
Gesture currentGesture = Gesture.None;
Gesture lastGesture = Gesture.None;
// SetGesturesEnabled(0b0000000000001001); // Enable only some gestures to be detected
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new InputGestures();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
lastGesture = currentGesture;
currentGesture = GetGestureDetected();
touchPosition = GetTouchPosition(0);
if (CheckCollisionPointRec(touchPosition, touchArea) && (currentGesture != Gesture.None))
{
if (currentGesture != lastGesture)
{
// Store gesture string
switch ((Gesture)currentGesture)
{
case Gesture.Tap:
gestureStrings[gesturesCount] = "GESTURE TAP";
break;
case Gesture.DoubleTap:
gestureStrings[gesturesCount] = "GESTURE DOUBLETAP";
break;
case Gesture.Hold:
gestureStrings[gesturesCount] = "GESTURE HOLD";
break;
case Gesture.Drag:
gestureStrings[gesturesCount] = "GESTURE DRAG";
break;
case Gesture.SwipeRight:
gestureStrings[gesturesCount] = "GESTURE SWIPE RIGHT";
break;
case Gesture.SwipeLeft:
gestureStrings[gesturesCount] = "GESTURE SWIPE LEFT";
break;
case Gesture.SwipeUp:
gestureStrings[gesturesCount] = "GESTURE SWIPE UP";
break;
case Gesture.SwipeDown:
gestureStrings[gesturesCount] = "GESTURE SWIPE DOWN";
break;
case Gesture.PinchIn:
gestureStrings[gesturesCount] = "GESTURE PINCH IN";
break;
case Gesture.PinchOut:
gestureStrings[gesturesCount] = "GESTURE PINCH OUT";
break;
default:
break;
}
gesturesCount++;
// Reset gestures strings
if (gesturesCount >= MaxGestureStrings)
{
for (int i = 0; i < MaxGestureStrings; i++)
{
gestureStrings[i] = " ";
}
gesturesCount = 0;
}
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawRectangleRec(touchArea, Color.Gray);
DrawRectangle(225, 15, screenWidth - 240, screenHeight - 30, Color.RayWhite);
DrawText("GESTURES TEST AREA", screenWidth - 270, screenHeight - 40, 20, ColorAlpha(Color.Gray, 0.5f));
for (int i = 0; i < gesturesCount; i++)
{
if (i % 2 == 0)
{
DrawRectangle(10, 30 + 20 * i, 200, 20, ColorAlpha(Color.LightGray, 0.5f));
}
else
{
DrawRectangle(10, 30 + 20 * i, 200, 20, ColorAlpha(Color.LightGray, 0.3f));
}
if (i < gesturesCount - 1)
{
DrawText(gestureStrings[i], 35, 36 + 20 * i, 10, Color.DarkGray);
}
else
{
DrawText(gestureStrings[i], 35, 36 + 20 * i, 10, Color.Maroon);
}
}
DrawRectangleLines(10, 29, 200, screenHeight - 50, Color.Gray);
DrawText("DETECTED GESTURES", 50, 15, 10, Color.Gray);
if (currentGesture != Gesture.None)
{
DrawCircleV(touchPosition, 30, Color.Maroon);
}
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,406 +1,450 @@
/*******************************************************************************************
*
* raylib [core] example - input gestures testbed
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.0, last time updated with raylib 6.0
*
* Example contributed by ubkp (@ubkp) 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) 2023-2025 ubkp (@ubkp)
*
********************************************************************************************/
using System.Numerics;
*
* raylib [core] example - input gestures testbed
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.0, last time updated with raylib 6.0
*
* Example contributed by ubkp (@ubkp) 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) 2023-2025 ubkp (@ubkp)
*
********************************************************************************************/
namespace Examples.Core;
using static Raylib_cs.Raylib;
public class InputGesturesTestBed
public partial class InputGesturesTestBed : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public const int GESTURE_LOG_SIZE = 20;
public const int MAX_TOUCH_COUNT = 32;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
public string Name => "Core / Input Gestures Test Bed";
public static int Main()
public string Title => "raylib [core] example - input gestures testbed";
private Vector2 messagePosition;
// Last gesture variables definitions
private Gesture lastGesture;
private Vector2 lastGesturePosition;
// Gesture log variables definitions
// NOTE: The gesture log uses an array (as an inverted circular queue) to store the performed gestures
private string[] gestureLog;
// NOTE: The index for the inverted circular queue (moving from last to first direction, then looping around)
private int gestureLogIndex;
private Gesture previousGesture;
// Log mode values:
// - 0 shows repeated events
// - 1 hides repeated events
// - 2 shows repeated events but hide hold events
// - 3 hides repeated events and hide hold events
private int logMode;
private Color gestureColor;
private Rectangle logButton1;
private Rectangle logButton2;
private Vector2 gestureLogPosition;
// Protractor variables definitions
private float angleLength;
private float currentAngleDegrees;
private Vector2 finalVector;
private Vector2 protractorPosition;
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures testbed");
Vector2 messagePosition = new Vector2(160, 7);
messagePosition = new Vector2(160, 7);
// Last gesture variables definitions
Gesture lastGesture = 0;
Vector2 lastGesturePosition = new Vector2(165, 130);
lastGesture = 0;
lastGesturePosition = new Vector2(165, 130);
// Gesture log variables definitions
// NOTE: The gesture log uses an array (as an inverted circular queue) to store the performed gestures
string[] gestureLog = new string[GESTURE_LOG_SIZE + 1];
for (int i = 0; i < GESTURE_LOG_SIZE; i++)
gestureLog = new string[GESTURE_LOG_SIZE + 1];
for (var i = 0; i < GESTURE_LOG_SIZE; i++)
{
gestureLog[i] = new string(new char[12]);
}
;
// NOTE: The index for the inverted circular queue (moving from last to first direction, then looping around)
int gestureLogIndex = GESTURE_LOG_SIZE;
Gesture previousGesture = 0;
gestureLogIndex = GESTURE_LOG_SIZE;
previousGesture = 0;
// Log mode values:
// - 0 shows repeated events
// - 1 hides repeated events
// - 2 shows repeated events but hide hold events
// - 3 hides repeated events and hide hold events
int logMode = 1;
logMode = 1;
Color gestureColor = new Color(0, 0, 0, 255);
Rectangle logButton1 = new Rectangle(53, 7, 48, 26);
Rectangle logButton2 = new Rectangle(108, 7, 36, 26);
Vector2 gestureLogPosition = new Vector2(10, 10);
gestureColor = new Color(0, 0, 0, 255);
logButton1 = new Rectangle(53, 7, 48, 26);
logButton2 = new Rectangle(108, 7, 36, 26);
gestureLogPosition = new Vector2(10, 10);
// Protractor variables definitions
float angleLength = 90.0f;
float currentAngleDegrees = 0.0f;
Vector2 finalVector = new Vector2(0.0f, 0.0f);
Vector2 protractorPosition = new Vector2(266.0f, 315.0f);
angleLength = 90.0f;
currentAngleDegrees = 0.0f;
finalVector = new Vector2(0.0f, 0.0f);
protractorPosition = new Vector2(266.0f, 315.0f);
}
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
public void Update()
{
// Update
//--------------------------------------------------------------------------------------
// Handle common gestures data
int i, ii; // Iterators that will be reused by all for loops
var currentGesture = GetGestureDetected();
var currentDragDegrees = GetGestureDragAngle();
var currentPitchDegrees = GetGesturePinchAngle();
var touchCount = GetTouchPointCount();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
// Handle last gesture
if ((currentGesture != 0) && ((int)currentGesture != 4) && (currentGesture != previousGesture))
{
// Update
//--------------------------------------------------------------------------------------
// Handle common gestures data
int i, ii; // Iterators that will be reused by all for loops
Gesture currentGesture = GetGestureDetected();
float currentDragDegrees = GetGestureDragAngle();
float currentPitchDegrees = GetGesturePinchAngle();
int touchCount = GetTouchPointCount();
lastGesture = currentGesture; // Filter the meaningful gestures (1, 2, 8 to 512) for the display
}
// Handle last gesture
if ((currentGesture != 0) && ((int)currentGesture != 4) && (currentGesture != previousGesture))
// Handle gesture log
if (IsMouseButtonReleased(MouseButton.Left))
{
if (CheckCollisionPointRec(GetMousePosition(), logButton1))
{
lastGesture = currentGesture; // Filter the meaningful gestures (1, 2, 8 to 512) for the display
}
// Handle gesture log
if (IsMouseButtonReleased(MouseButton.Left))
{
if (CheckCollisionPointRec(GetMousePosition(), logButton1))
switch (logMode)
{
switch (logMode)
{
case 3:
logMode = 2;
break;
case 2:
logMode = 3;
break;
case 1:
logMode = 0;
break;
default:
logMode = 1;
break;
}
}
else if (CheckCollisionPointRec(GetMousePosition(), logButton2))
{
switch (logMode)
{
case 3:
logMode = 1;
break;
case 2:
logMode = 0;
break;
case 1:
logMode = 3;
break;
default:
logMode = 2;
break;
}
case 3:
logMode = 2;
break;
case 2:
logMode = 3;
break;
case 1:
logMode = 0;
break;
default:
logMode = 1;
break;
}
}
int fillLog = 0; // Gate variable to be used to allow or not the gesture log to be filled
if (currentGesture != 0)
else if (CheckCollisionPointRec(GetMousePosition(), logButton2))
{
if (logMode == 3) // 3 hides repeated events and hide hold events
switch (logMode)
{
if ((((int)currentGesture != 4) && (currentGesture != previousGesture)) || ((int)currentGesture < 3))
{
fillLog = 1;
}
case 3:
logMode = 1;
break;
case 2:
logMode = 0;
break;
case 1:
logMode = 3;
break;
default:
logMode = 2;
break;
}
else if (logMode == 2) // 2 shows repeated events but hide hold events
{
if ((int)currentGesture != 4)
{
fillLog = 1;
}
}
else if (logMode == 1) // 1 hides repeated events
{
if (currentGesture != previousGesture)
{
fillLog = 1;
}
}
else // 0 shows repeated events
}
}
var fillLog = 0; // Gate variable to be used to allow or not the gesture log to be filled
if (currentGesture != 0)
{
if (logMode == 3) // 3 hides repeated events and hide hold events
{
if ((((int)currentGesture != 4) && (currentGesture != previousGesture)) || ((int)currentGesture < 3))
{
fillLog = 1;
}
}
if (fillLog > 0) // If one of the conditions from logMode was met, fill the gesture log
else if (logMode == 2) // 2 shows repeated events but hide hold events
{
previousGesture = currentGesture;
gestureColor = GetGestureColor((int)currentGesture);
if (gestureLogIndex <= 0)
if ((int)currentGesture != 4)
{
gestureLogIndex = GESTURE_LOG_SIZE;
}
gestureLogIndex--;
// Copy the gesture respective name to the gesture log array
gestureLog[gestureLogIndex] = GetGestureName((int)currentGesture);
}
// Handle protractor
if ((int)currentGesture > 255)
{
currentAngleDegrees = currentPitchDegrees; // Pinch In and Pinch Out
}
else if ((int)currentGesture > 15)
{
currentAngleDegrees = currentDragDegrees; // Swipe Right, Swipe Left, Swipe Up and Swipe Down
}
else if (currentGesture > 0)
{
currentAngleDegrees = 0.0f; // Tap, Doubletap, Hold and Grab
}
float currentAngleRadians =
((currentAngleDegrees + 90.0f) * MathF.PI / 180); // Convert the current angle to Radians
// Calculate the final vector for display
finalVector = new Vector2(
(angleLength * MathF.Sin(currentAngleRadians)) + protractorPosition.X,
(angleLength * MathF.Cos(currentAngleRadians)) + protractorPosition.Y
)
;
// Handle touch and mouse pointer points
Vector2[] touchPosition = new Vector2[MAX_TOUCH_COUNT];
Vector2 mousePosition = Vector2.Zero;
if (currentGesture != Gesture.None)
{
if (touchCount != 0)
{
for (i = 0; i < touchCount; i++)
{
touchPosition[i] = GetTouchPosition(i); // Fill the touch positions
}
}
else
{
mousePosition = GetMousePosition();
fillLog = 1;
}
}
//--------------------------------------------------------------------------------------
// Draw
//--------------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw common elements
DrawText("*", (int)messagePosition.X + 5, (int)messagePosition.Y + 5, 10, Color.Black);
DrawText("Example optimized for Web/HTML5\non Smartphones with Touch Screen.", (int)messagePosition.X + 15,
(int)messagePosition.Y + 5, 10, Color.Black);
DrawText("*", (int)messagePosition.X + 5, (int)messagePosition.Y + 35, 10, Color.Black);
DrawText("While running on Desktop Web Browsers,\ninspect and turn on Touch Emulation.",
(int)messagePosition.X + 15, (int)messagePosition.Y + 35, 10, Color.Black);
// Draw last gesture
DrawText("Last gesture", (int)lastGesturePosition.X + 33, (int)lastGesturePosition.Y - 47, 20, Color.Black);
DrawText("Swipe Tap Pinch Touch", (int)lastGesturePosition.X + 17,
(int)lastGesturePosition.Y - 18, 10, Color.Black);
DrawRectangle((int)lastGesturePosition.X + 20, (int)lastGesturePosition.Y, 20, 20,
lastGesture == Gesture.SwipeUp ? Color.Red : Color.LightGray);
DrawRectangle((int)lastGesturePosition.X, (int)lastGesturePosition.Y + 20, 20, 20,
lastGesture == Gesture.SwipeLeft ? Color.Red : Color.LightGray);
DrawRectangle((int)lastGesturePosition.X + 40, (int)lastGesturePosition.Y + 20, 20, 20,
lastGesture == Gesture.SwipeRight ? Color.Red : Color.LightGray);
DrawRectangle((int)lastGesturePosition.X + 20, (int)lastGesturePosition.Y + 40, 20, 20,
lastGesture == Gesture.SwipeDown ? Color.Red : Color.LightGray);
DrawCircle((int)lastGesturePosition.X + 80, (int)lastGesturePosition.Y + 16, 10,
lastGesture == Gesture.Tap ? Color.Blue : Color.LightGray);
DrawRing(new Vector2(
lastGesturePosition.X + 103, lastGesturePosition.Y + 16
), 6.0f, 11.0f, 0.0f, 360.0f, 0, lastGesture == Gesture.Drag ? Color.Lime : Color.LightGray);
DrawCircle((int)lastGesturePosition.X + 80, (int)lastGesturePosition.Y + 43, 10,
lastGesture == Gesture.DoubleTap ? Color.SkyBlue : Color.LightGray);
DrawCircle((int)lastGesturePosition.X + 103, (int)lastGesturePosition.Y + 43, 10,
lastGesture == Gesture.DoubleTap ? Color.SkyBlue : Color.LightGray);
DrawTriangle(new Vector2(
lastGesturePosition.X + 122, lastGesturePosition.Y + 16
), new Vector2(
lastGesturePosition.X + 137, lastGesturePosition.Y + 26
), new Vector2(
lastGesturePosition.X + 137, lastGesturePosition.Y + 6
), lastGesture == Gesture.PinchOut ? Color.Orange : Color.LightGray);
DrawTriangle(new Vector2(
lastGesturePosition.X + 147, lastGesturePosition.Y + 6
), new Vector2(
lastGesturePosition.X + 147, lastGesturePosition.Y + 26
), new Vector2(
lastGesturePosition.X + 162, lastGesturePosition.Y + 16
), lastGesture == Gesture.PinchOut ? Color.Orange : Color.Gray);
DrawTriangle(new Vector2(
lastGesturePosition.X + 125, lastGesturePosition.Y + 33
), new Vector2(
lastGesturePosition.X + 125, lastGesturePosition.Y + 53
), new Vector2(
lastGesturePosition.X + 140, lastGesturePosition.Y + 43
), lastGesture == Gesture.PinchIn ? Color.Violet : Color.LightGray);
DrawTriangle(new Vector2(
lastGesturePosition.X + 144, lastGesturePosition.Y + 43
), new Vector2(
lastGesturePosition.X + 159, lastGesturePosition.Y + 53
), new Vector2(
lastGesturePosition.X + 159, lastGesturePosition.Y + 33
), lastGesture == Gesture.PinchIn ? Color.Violet : Color.LightGray);
for (i = 0; i < 4; i++)
else if (logMode == 1) // 1 hides repeated events
{
DrawCircle((int)lastGesturePosition.X + 180, (int)lastGesturePosition.Y + 7 + i * 15, 5,
touchCount <= i ? Color.LightGray : gestureColor);
}
// Draw gesture log
DrawText("Log", (int)gestureLogPosition.X, (int)gestureLogPosition.Y, 20, Color.Black);
// Loop in both directions to print the gesture log array in the inverted order (and looping around if the index started somewhere in the middle)
for (i = 0, ii = gestureLogIndex; i < GESTURE_LOG_SIZE; i++, ii = (ii + 1) % GESTURE_LOG_SIZE)
{
DrawText(gestureLog[ii], (int)gestureLogPosition.X, (int)gestureLogPosition.Y + 410 - i * 20, 20,
(i == 0 ? gestureColor : Color.LightGray));
}
Color logButton1Color, logButton2Color;
switch (logMode)
{
case 3:
logButton1Color = Color.Maroon;
logButton2Color = Color.Maroon;
break;
case 2:
logButton1Color = Color.Gray;
logButton2Color = Color.Maroon;
break;
case 1:
logButton1Color = Color.Maroon;
logButton2Color = Color.Gray;
break;
default:
logButton1Color = Color.Gray;
logButton2Color = Color.Gray;
break;
}
DrawRectangleRec(logButton1, logButton1Color);
DrawText("Hide", (int)logButton1.X + 7, (int)logButton1.Y + 3, 10, Color.White);
DrawText("Repeat", (int)logButton1.X + 7, (int)logButton1.Y + 13, 10, Color.White);
DrawRectangleRec(logButton2, logButton2Color);
DrawText("Hide", (int)logButton1.X + 62, (int)logButton1.Y + 3, 10, Color.White);
DrawText("Hold", (int)logButton1.X + 62, (int)logButton1.Y + 13, 10, Color.White);
// Draw protractor
DrawText("Angle", (int)protractorPosition.X + 55, (int)protractorPosition.Y + 76, 10, Color.Black);
// Note: Official it's using raylibs functions for string manipulation. But in C# it will end up in an unsafe handling.
string angleString = currentAngleDegrees.ToString("F3");
int angleStringDot = angleString.IndexOf('.');
string angleStringTrim = angleString.Substring(0, angleStringDot + 3);
DrawText(angleStringTrim, (int)protractorPosition.X + 55, (int)protractorPosition.Y + 92, 20, gestureColor);
DrawCircleV(protractorPosition, 80.0f, Color.White);
DrawLineEx(new Vector2(
protractorPosition.X - 90, protractorPosition.Y
), new Vector2(
protractorPosition.X + 90, protractorPosition.Y
), 3.0f, Color.LightGray);
DrawLineEx(new Vector2(
protractorPosition.X, protractorPosition.Y - 90
), new Vector2(
protractorPosition.X, protractorPosition.Y + 90
), 3.0f, Color.LightGray);
DrawLineEx(new Vector2(
protractorPosition.X - 80, protractorPosition.Y - 45
), new Vector2(
protractorPosition.X + 80, protractorPosition.Y + 45
), 3.0f, Color.Green);
DrawLineEx(new Vector2(
protractorPosition.X - 80, protractorPosition.Y + 45
), new Vector2(
protractorPosition.X + 80, protractorPosition.Y - 45
), 3.0f, Color.Green);
DrawText("0", (int)protractorPosition.X + 96, (int)protractorPosition.Y - 9, 20, Color.Black);
DrawText("30", (int)protractorPosition.X + 74, (int)protractorPosition.Y - 68, 20, Color.Black);
DrawText("90", (int)protractorPosition.X - 11, (int)protractorPosition.Y - 110, 20, Color.Black);
DrawText("150", (int)protractorPosition.X - 100, (int)protractorPosition.Y - 68, 20, Color.Black);
DrawText("180", (int)protractorPosition.X - 124, (int)protractorPosition.Y - 9, 20, Color.Black);
DrawText("210", (int)protractorPosition.X - 100, (int)protractorPosition.Y + 50, 20, Color.Black);
DrawText("270", (int)protractorPosition.X - 18, (int)protractorPosition.Y + 92, 20, Color.Black);
DrawText("330", (int)protractorPosition.X + 72, (int)protractorPosition.Y + 50, 20, Color.Black);
if (currentAngleDegrees != 0.0f)
{
DrawLineEx(protractorPosition, finalVector, 3.0f, gestureColor);
}
// Draw touch and mouse pointer points
if (currentGesture != Gesture.None)
{
if (touchCount != 0)
if (currentGesture != previousGesture)
{
for (i = 0; i < touchCount; i++)
{
DrawCircleV(touchPosition[i], 50.0f, Fade(gestureColor, 0.5f));
DrawCircleV(touchPosition[i], 5.0f, gestureColor);
}
if (touchCount == 2)
{
DrawLineEx(touchPosition[0], touchPosition[1], (((int)currentGesture == 512) ? 8.0f : 12.0f),
gestureColor);
}
}
else
{
DrawCircleV(mousePosition, 35.0f, Fade(gestureColor, 0.5f));
DrawCircleV(mousePosition, 5.0f, gestureColor);
fillLog = 1;
}
}
EndDrawing();
//--------------------------------------------------------------------------------------
else // 0 shows repeated events
{
fillLog = 1;
}
}
if (fillLog > 0) // If one of the conditions from logMode was met, fill the gesture log
{
previousGesture = currentGesture;
gestureColor = GetGestureColor((int)currentGesture);
if (gestureLogIndex <= 0)
{
gestureLogIndex = GESTURE_LOG_SIZE;
}
gestureLogIndex--;
// Copy the gesture respective name to the gesture log array
gestureLog[gestureLogIndex] = GetGestureName((int)currentGesture);
}
// Handle protractor
if ((int)currentGesture > 255)
{
currentAngleDegrees = currentPitchDegrees; // Pinch In and Pinch Out
}
else if ((int)currentGesture > 15)
{
currentAngleDegrees = currentDragDegrees; // Swipe Right, Swipe Left, Swipe Up and Swipe Down
}
else if (currentGesture > 0)
{
currentAngleDegrees = 0.0f; // Tap, Doubletap, Hold and Grab
}
var currentAngleRadians =
((currentAngleDegrees + 90.0f) * MathF.PI / 180); // Convert the current angle to Radians
// Calculate the final vector for display
finalVector = new Vector2(
(angleLength * MathF.Sin(currentAngleRadians)) + protractorPosition.X,
(angleLength * MathF.Cos(currentAngleRadians)) + protractorPosition.Y
);
// Handle touch and mouse pointer points
var touchPosition = new Vector2[MAX_TOUCH_COUNT];
var mousePosition = Vector2.Zero;
if (currentGesture != Gesture.None)
{
if (touchCount != 0)
{
for (i = 0; i < touchCount; i++)
{
touchPosition[i] = GetTouchPosition(i); // Fill the touch positions
}
}
else
{
mousePosition = GetMousePosition();
}
}
//--------------------------------------------------------------------------------------
// Draw
//--------------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw common elements
DrawText("*", (int)messagePosition.X + 5, (int)messagePosition.Y + 5, 10, Color.Black);
DrawText("Example optimized for Web/HTML5\non Smartphones with Touch Screen.", (int)messagePosition.X + 15,
(int)messagePosition.Y + 5, 10, Color.Black);
DrawText("*", (int)messagePosition.X + 5, (int)messagePosition.Y + 35, 10, Color.Black);
DrawText("While running on Desktop Web Browsers,\ninspect and turn on Touch Emulation.",
(int)messagePosition.X + 15, (int)messagePosition.Y + 35, 10, Color.Black);
// Draw last gesture
DrawText("Last gesture", (int)lastGesturePosition.X + 33, (int)lastGesturePosition.Y - 47, 20, Color.Black);
DrawText("Swipe Tap Pinch Touch", (int)lastGesturePosition.X + 17,
(int)lastGesturePosition.Y - 18, 10, Color.Black);
DrawRectangle((int)lastGesturePosition.X + 20, (int)lastGesturePosition.Y, 20, 20,
lastGesture == Gesture.SwipeUp ? Color.Red : Color.LightGray);
DrawRectangle((int)lastGesturePosition.X, (int)lastGesturePosition.Y + 20, 20, 20,
lastGesture == Gesture.SwipeLeft ? Color.Red : Color.LightGray);
DrawRectangle((int)lastGesturePosition.X + 40, (int)lastGesturePosition.Y + 20, 20, 20,
lastGesture == Gesture.SwipeRight ? Color.Red : Color.LightGray);
DrawRectangle((int)lastGesturePosition.X + 20, (int)lastGesturePosition.Y + 40, 20, 20,
lastGesture == Gesture.SwipeDown ? Color.Red : Color.LightGray);
DrawCircle((int)lastGesturePosition.X + 80, (int)lastGesturePosition.Y + 16, 10,
lastGesture == Gesture.Tap ? Color.Blue : Color.LightGray);
DrawRing(new Vector2(
lastGesturePosition.X + 103, lastGesturePosition.Y + 16
), 6.0f, 11.0f, 0.0f, 360.0f, 0, lastGesture == Gesture.Drag ? Color.Lime : Color.LightGray);
DrawCircle((int)lastGesturePosition.X + 80, (int)lastGesturePosition.Y + 43, 10,
lastGesture == Gesture.DoubleTap ? Color.SkyBlue : Color.LightGray);
DrawCircle((int)lastGesturePosition.X + 103, (int)lastGesturePosition.Y + 43, 10,
lastGesture == Gesture.DoubleTap ? Color.SkyBlue : Color.LightGray);
DrawTriangle(new Vector2(
lastGesturePosition.X + 122, lastGesturePosition.Y + 16
), new Vector2(
lastGesturePosition.X + 137, lastGesturePosition.Y + 26
), new Vector2(
lastGesturePosition.X + 137, lastGesturePosition.Y + 6
), lastGesture == Gesture.PinchOut ? Color.Orange : Color.LightGray);
DrawTriangle(new Vector2(
lastGesturePosition.X + 147, lastGesturePosition.Y + 6
), new Vector2(
lastGesturePosition.X + 147, lastGesturePosition.Y + 26
), new Vector2(
lastGesturePosition.X + 162, lastGesturePosition.Y + 16
), lastGesture == Gesture.PinchOut ? Color.Orange : Color.Gray);
DrawTriangle(new Vector2(
lastGesturePosition.X + 125, lastGesturePosition.Y + 33
), new Vector2(
lastGesturePosition.X + 125, lastGesturePosition.Y + 53
), new Vector2(
lastGesturePosition.X + 140, lastGesturePosition.Y + 43
), lastGesture == Gesture.PinchIn ? Color.Violet : Color.LightGray);
DrawTriangle(new Vector2(
lastGesturePosition.X + 144, lastGesturePosition.Y + 43
), new Vector2(
lastGesturePosition.X + 159, lastGesturePosition.Y + 53
), new Vector2(
lastGesturePosition.X + 159, lastGesturePosition.Y + 33
), lastGesture == Gesture.PinchIn ? Color.Violet : Color.LightGray);
for (i = 0; i < 4; i++)
{
DrawCircle((int)lastGesturePosition.X + 180, (int)lastGesturePosition.Y + 7 + i * 15, 5,
touchCount <= i ? Color.LightGray : gestureColor);
}
// Draw gesture log
DrawText("Log", (int)gestureLogPosition.X, (int)gestureLogPosition.Y, 20, Color.Black);
// Loop in both directions to print the gesture log array in the inverted order (and looping around if the index started somewhere in the middle)
for (i = 0, ii = gestureLogIndex; i < GESTURE_LOG_SIZE; i++, ii = (ii + 1) % GESTURE_LOG_SIZE)
{
DrawText(gestureLog[ii], (int)gestureLogPosition.X, (int)gestureLogPosition.Y + 410 - i * 20, 20,
(i == 0 ? gestureColor : Color.LightGray));
}
Color logButton1Color, logButton2Color;
switch (logMode)
{
case 3:
logButton1Color = Color.Maroon;
logButton2Color = Color.Maroon;
break;
case 2:
logButton1Color = Color.Gray;
logButton2Color = Color.Maroon;
break;
case 1:
logButton1Color = Color.Maroon;
logButton2Color = Color.Gray;
break;
default:
logButton1Color = Color.Gray;
logButton2Color = Color.Gray;
break;
}
DrawRectangleRec(logButton1, logButton1Color);
DrawText("Hide", (int)logButton1.X + 7, (int)logButton1.Y + 3, 10, Color.White);
DrawText("Repeat", (int)logButton1.X + 7, (int)logButton1.Y + 13, 10, Color.White);
DrawRectangleRec(logButton2, logButton2Color);
DrawText("Hide", (int)logButton1.X + 62, (int)logButton1.Y + 3, 10, Color.White);
DrawText("Hold", (int)logButton1.X + 62, (int)logButton1.Y + 13, 10, Color.White);
// Draw protractor
DrawText("Angle", (int)protractorPosition.X + 55, (int)protractorPosition.Y + 76, 10, Color.Black);
// Note: Official it's using raylibs functions for string manipulation. But in C# it will end up in an unsafe handling.
var angleString = currentAngleDegrees.ToString("F3");
var angleStringDot = angleString.IndexOf('.');
var angleStringTrim = angleString[..(angleStringDot + 3)];
DrawText(angleStringTrim, (int)protractorPosition.X + 55, (int)protractorPosition.Y + 92, 20, gestureColor);
DrawCircleV(protractorPosition, 80.0f, Color.White);
DrawLineEx(new Vector2(
protractorPosition.X - 90, protractorPosition.Y
), new Vector2(
protractorPosition.X + 90, protractorPosition.Y
), 3.0f, Color.LightGray);
DrawLineEx(new Vector2(
protractorPosition.X, protractorPosition.Y - 90
), new Vector2(
protractorPosition.X, protractorPosition.Y + 90
), 3.0f, Color.LightGray);
DrawLineEx(new Vector2(
protractorPosition.X - 80, protractorPosition.Y - 45
), new Vector2(
protractorPosition.X + 80, protractorPosition.Y + 45
), 3.0f, Color.Green);
DrawLineEx(new Vector2(
protractorPosition.X - 80, protractorPosition.Y + 45
), new Vector2(
protractorPosition.X + 80, protractorPosition.Y - 45
), 3.0f, Color.Green);
DrawText("0", (int)protractorPosition.X + 96, (int)protractorPosition.Y - 9, 20, Color.Black);
DrawText("30", (int)protractorPosition.X + 74, (int)protractorPosition.Y - 68, 20, Color.Black);
DrawText("90", (int)protractorPosition.X - 11, (int)protractorPosition.Y - 110, 20, Color.Black);
DrawText("150", (int)protractorPosition.X - 100, (int)protractorPosition.Y - 68, 20, Color.Black);
DrawText("180", (int)protractorPosition.X - 124, (int)protractorPosition.Y - 9, 20, Color.Black);
DrawText("210", (int)protractorPosition.X - 100, (int)protractorPosition.Y + 50, 20, Color.Black);
DrawText("270", (int)protractorPosition.X - 18, (int)protractorPosition.Y + 92, 20, Color.Black);
DrawText("330", (int)protractorPosition.X + 72, (int)protractorPosition.Y + 50, 20, Color.Black);
if (currentAngleDegrees != 0.0f)
{
DrawLineEx(protractorPosition, finalVector, 3.0f, gestureColor);
}
// Draw touch and mouse pointer points
if (currentGesture != Gesture.None)
{
if (touchCount != 0)
{
for (i = 0; i < touchCount; i++)
{
DrawCircleV(touchPosition[i], 50.0f, Fade(gestureColor, 0.5f));
DrawCircleV(touchPosition[i], 5.0f, gestureColor);
}
if (touchCount == 2)
{
DrawLineEx(touchPosition[0], touchPosition[1], (((int)currentGesture == 512) ? 8.0f : 12.0f),
gestureColor);
}
}
else
{
DrawCircleV(mousePosition, 35.0f, Fade(gestureColor, 0.5f));
DrawCircleV(mousePosition, 5.0f, gestureColor);
}
}
EndDrawing();
//--------------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - input gestures testbed");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new InputGesturesTestBed();
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
@ -409,7 +453,8 @@ public class InputGesturesTestBed
return 0;
}
static string GetGestureName(int gesture)
// Get text string for gesture value
private static string GetGestureName(int gesture)
{
switch (gesture)
{
@ -441,7 +486,7 @@ public class InputGesturesTestBed
}
// Get color for gesture value
static Color GetGestureColor(int gesture)
private static Color GetGestureColor(int gesture)
{
switch (gesture)
{

View file

@ -13,69 +13,89 @@
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class InputKeys
public partial class InputKeys : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Input Keys";
public string Title => "raylib [core] example - input keys";
private Vector2 ballPosition;
public void Init()
{
ballPosition = new((float)screenWidth / 2, (float)screenHeight / 2);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyDown(KeyboardKey.Right))
{
ballPosition.X += 2.0f;
}
if (IsKeyDown(KeyboardKey.Left))
{
ballPosition.X -= 2.0f;
}
if (IsKeyDown(KeyboardKey.Up))
{
ballPosition.Y -= 2.0f;
}
if (IsKeyDown(KeyboardKey.Down))
{
ballPosition.Y += 2.0f;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("move the ball with arrow keys", 10, 10, 20, Color.DarkGray);
DrawCircleV(ballPosition, 50, Color.Maroon);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - input keys");
InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard input");
Vector2 ballPosition = new((float)screenWidth / 2, (float)screenHeight / 2);
SetTargetFPS(60); // Set target frames-per-second
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new InputKeys();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyDown(KeyboardKey.Right))
{
ballPosition.X += 2.0f;
}
if (IsKeyDown(KeyboardKey.Left))
{
ballPosition.X -= 2.0f;
}
if (IsKeyDown(KeyboardKey.Up))
{
ballPosition.Y -= 2.0f;
}
if (IsKeyDown(KeyboardKey.Down))
{
ballPosition.Y += 2.0f;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("move the ball with arrow keys", 10, 10, 20, Color.DarkGray);
DrawCircleV(ballPosition, 50, Color.Maroon);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -14,100 +14,124 @@
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class InputMouse
public partial class InputMouse : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Input Mouse";
public string Title => "raylib [core] example - input mouse";
private Vector2 ballPosition;
private Color ballColor;
public void Init()
{
ballPosition = new(-100.0f, -100.0f);
ballColor = Color.DarkBlue;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.H))
{
if (IsCursorHidden())
{
ShowCursor();
}
else
{
HideCursor();
}
}
ballPosition = GetMousePosition();
if (IsMouseButtonPressed(MouseButton.Left))
{
ballColor = Color.Maroon;
}
else if (IsMouseButtonPressed(MouseButton.Middle))
{
ballColor = Color.Lime;
}
else if (IsMouseButtonPressed(MouseButton.Right))
{
ballColor = Color.DarkBlue;
}
else if (IsMouseButtonPressed(MouseButton.Side))
{
ballColor = Color.Purple;
}
else if (IsMouseButtonPressed(MouseButton.Extra))
{
ballColor = Color.Yellow;
}
else if (IsMouseButtonPressed(MouseButton.Forward))
{
ballColor = Color.Orange;
}
else if (IsMouseButtonPressed(MouseButton.Back))
{
ballColor = Color.Beige;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawCircleV(ballPosition, 40, ballColor);
DrawText("move ball with mouse and click mouse button to change color", 10, 10, 20, Color.DarkGray);
DrawText("Press 'H' to toggle cursor visibility", 10, 30, 20, Color.DarkGray);
if (IsCursorHidden())
{
DrawText("CURSOR HIDDEN", 20, 60, 20, Color.Red);
}
else
{
DrawText("CURSOR VISIBLE", 20, 60, 20, Color.Lime);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - input mouse");
InitWindow(screenWidth, screenHeight, "raylib [core] example - mouse input");
Vector2 ballPosition = new(-100.0f, -100.0f);
Color ballColor = Color.DarkBlue;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//---------------------------------------------------------------------------------------
var game = new InputMouse();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.H))
{
if (IsCursorHidden())
{
ShowCursor();
}
else
{
HideCursor();
}
}
ballPosition = GetMousePosition();
if (IsMouseButtonPressed(MouseButton.Left))
{
ballColor = Color.Maroon;
}
else if (IsMouseButtonPressed(MouseButton.Middle))
{
ballColor = Color.Lime;
}
else if (IsMouseButtonPressed(MouseButton.Right))
{
ballColor = Color.DarkBlue;
}
else if (IsMouseButtonPressed(MouseButton.Extra))
{
ballColor = Color.Yellow;
}
else if (IsMouseButtonPressed(MouseButton.Forward))
{
ballColor = Color.Orange;
}
else if (IsMouseButtonPressed(MouseButton.Back))
{
ballColor = Color.Beige;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawCircleV(ballPosition, 40, ballColor);
DrawText("move ball with mouse and click mouse button to change color", 10, 10, 20, Color.DarkGray);
DrawText("Press 'H' to toggle cursor visibility", 10, 30, 20, Color.DarkGray);
if (IsCursorHidden())
{
DrawText("CURSOR HIDDEN", 20, 60, 20, Color.Red);
}
else
{
DrawText("CURSOR VISIBLE", 20, 60, 20, Color.Lime);
}
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -13,52 +13,74 @@
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class InputMouseWheel
public partial class InputMouseWheel : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Mouse Wheel";
public string Title => "raylib [core] example - input mouse wheel";
private int boxPositionY;
private int scrollSpeed; // Scrolling speed in pixels
public void Init()
{
boxPositionY = screenHeight / 2 - 40;
scrollSpeed = 4; // Scrolling speed in pixels
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
boxPositionY -= (int)(GetMouseWheelMove() * scrollSpeed);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawRectangle(screenWidth / 2 - 40, boxPositionY, 80, 80, Color.Maroon);
DrawText("Use mouse wheel to move the cube up and down!", 10, 10, 20, Color.Gray);
DrawText($"Box position Y: {boxPositionY:000}", 10, 40, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - input mouse wheel");
int boxPositionY = screenHeight / 2 - 40;
int scrollSpeed = 4; // Scrolling speed in pixels
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new InputMouseWheel();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
boxPositionY -= (int)(GetMouseWheelMove() * scrollSpeed);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawRectangle(screenWidth / 2 - 40, boxPositionY, 80, 80, Color.Maroon);
DrawText("Use mouse wheel to move the cube up and down!", 10, 10, 20, Color.Gray);
DrawText($"Box position Y: {boxPositionY}", 10, 40, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -15,79 +15,100 @@
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class InputMultitouch
public partial class InputMultitouch : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int MaxTouchPoints = 10;
public string Name => "Core / Input Multitouch";
public string Title => "raylib [core] example - input multitouch";
private Vector2[] touchPositions;
public void Init()
{
touchPositions = new Vector2[MaxTouchPoints];
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Get the touch point count ( how many fingers are touching the screen )
var tCount = GetTouchPointCount();
// Clamp touch points available ( set the maximum touch points allowed )
if (tCount > MaxTouchPoints)
{
tCount = MaxTouchPoints;
}
// Get touch points positions
for (var i = 0; i < tCount; i++)
{
touchPositions[i] = GetTouchPosition(i);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
for (var i = 0; i < tCount; i++)
{
// Make sure point is not (0, 0) as this means there is no touch for it
if ((touchPositions[i].X > 0) && (touchPositions[i].Y > 0))
{
// Draw circle and touch index number
DrawCircleV(touchPositions[i], 34, Color.Orange);
DrawText(i.ToString(),
(int)touchPositions[i].X - 10,
(int)touchPositions[i].Y - 70,
40,
Color.Black
);
}
}
DrawText("touch the screen at multiple locations to get multiple balls", 10, 10, 20, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - input multitouch");
const int MaxTouchPoints = 10;
Vector2[] touchPositions = new Vector2[MaxTouchPoints];
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//---------------------------------------------------------------------------------------
var game = new InputMultitouch();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// Get the touch point count (how many fingers are touching the screen )
int tCount = GetTouchPointCount();
// Clamp touch points available (set the maximum touch points allowed )
if (tCount > MaxTouchPoints)
{
tCount = MaxTouchPoints;
}
// Get touch points positions
for (int i = 0; i < tCount; i++)
{
touchPositions[i] = GetTouchPosition(i);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
for (int i = 0; i < tCount; i++)
{
// Make sure point is not (0, 0) as this means there is no touch for it
if ((touchPositions[i].X > 0) && (touchPositions[i].Y > 0))
{
// Draw circle and touch index number
DrawCircleV(touchPositions[i], 34, Color.Orange);
DrawText(i.ToString(),
(int)touchPositions[i].X - 10,
(int)touchPositions[i].Y - 70,
40,
Color.Black
);
}
}
DrawText("touch the screen at multiple locations to get multiple balls", 10, 10, 20, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -1,27 +1,23 @@
/*******************************************************************************************
*
* raylib [core] example - input virtual controls
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.0, last time updated with raylib 5.0
*
* Example contributed by GreenSnakeLinux (@GreenSnakeLinux),
* reviewed by Ramon Santamaria (@raysan5), oblerion (@oblerion) and danilwhale (@danilwhale)
*
* 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 GreenSnakeLinux (@GreenSnakeLinux) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
*
* raylib [core] example - input virtual controls
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.0, last time updated with raylib 5.0
*
* Example contributed by GreenSnakeLinux (@GreenSnakeLinux),
* reviewed by Ramon Santamaria (@raysan5), oblerion (@oblerion) and danilwhale (@danilwhale)
*
* 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 GreenSnakeLinux (@GreenSnakeLinux) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Core;
using static Raylib_cs.Raylib;
public enum PadButton
{
BUTTON_NONE = -1,
@ -32,21 +28,31 @@ public enum PadButton
BUTTON_MAX
}
public class InputVirtualControls
public partial class InputVirtualControls : IExample
{
public static int Main()
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Input Virtual Controls";
public string Title => "raylib [core] example - input virtual controls";
private Vector2 padPosition;
private float buttonRadius;
private Vector2[] buttonPositions;
private Vector2[][] arrowTris;
private Color[] buttonLabelColors;
private int pressedButton;
private Vector2 inputPosition;
private Vector2 playerPosition;
private float playerSpeed;
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
padPosition = new Vector2(100, 350);
buttonRadius = 30;
InitWindow(screenWidth, screenHeight, "raylib [core] example - input virtual controls");
Vector2 padPosition = new Vector2(100, 350);
float buttonRadius = 30;
Vector2[] buttonPositions =
buttonPositions =
[
new Vector2(
padPosition.X,padPosition.Y - buttonRadius * 1.5f
@ -62,7 +68,7 @@ public class InputVirtualControls
) // Down
];
Vector2[][] arrowTris = [
arrowTris = [
// Up
[
new Vector2(
@ -114,107 +120,126 @@ public class InputVirtualControls
]
;
Color[] buttonLabelColors = [
buttonLabelColors = [
Color.Yellow, // Up
Color.Blue, // Left
Color.Red, // Right
Color.Green // Down
];
int pressedButton = (int)PadButton.BUTTON_NONE;
Vector2 inputPosition = new Vector2(0, 0);
pressedButton = (int)PadButton.BUTTON_NONE;
inputPosition = new Vector2(0, 0);
Vector2 playerPosition = new Vector2((float)screenWidth / 2, (float)screenHeight / 2);
float playerSpeed = 75f;
playerPosition = new Vector2((float)screenWidth / 2, (float)screenHeight / 2);
playerSpeed = 75f;
}
public void Update()
{
// Update
//--------------------------------------------------------------------------
if ((GetTouchPointCount() > 0))
{
inputPosition = GetTouchPosition(0); // Use touch position
}
else
{
inputPosition = GetMousePosition(); // Use mouse position
}
// Reset pressed button to none
pressedButton = (int)PadButton.BUTTON_NONE;
// Make sure user is pressing left mouse button if they're from desktop
if ((GetTouchPointCount() > 0) ||
((GetTouchPointCount() == 0) && IsMouseButtonDown(MouseButton.Left)))
{
// Find nearest D-Pad button to the input position
for (var i = 0; i < (int)PadButton.BUTTON_MAX; i++)
{
var distX = MathF.Abs(buttonPositions[i].X - inputPosition.X);
var distY = MathF.Abs(buttonPositions[i].Y - inputPosition.Y);
if ((distX + distY < buttonRadius))
{
pressedButton = i;
break;
}
}
}
// Move player according to pressed button
switch ((PadButton)pressedButton)
{
case PadButton.BUTTON_UP:
playerPosition.Y -= playerSpeed * GetFrameTime();
break;
case PadButton.BUTTON_LEFT:
playerPosition.X -= playerSpeed * GetFrameTime();
break;
case PadButton.BUTTON_RIGHT:
playerPosition.X += playerSpeed * GetFrameTime();
break;
case PadButton.BUTTON_DOWN:
playerPosition.Y += playerSpeed * GetFrameTime();
break;
default:
break;
}
//--------------------------------------------------------------------------
// Draw
//--------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw world
DrawCircleV(playerPosition, 50, Color.Maroon);
// Draw GUI
for (var i = 0; i < (int)PadButton.BUTTON_MAX; i++)
{
DrawCircleV(buttonPositions[i], buttonRadius, (i == pressedButton) ? Color.DarkGray : Color.Black);
DrawTriangle(
arrowTris[i][0],
arrowTris[i][1],
arrowTris[i][2],
buttonLabelColors[i]
);
}
DrawText("move the player with D-Pad buttons", 10, 10, 20, Color.DarkGray);
EndDrawing();
//--------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - input virtual controls");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new InputVirtualControls();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//--------------------------------------------------------------------------
if ((GetTouchPointCount() > 0))
{
inputPosition = GetTouchPosition(0); // Use touch position
}
else
{
inputPosition = GetMousePosition(); // Use mouse position
}
// Reset pressed button to none
pressedButton = (int)PadButton.BUTTON_NONE;
// Make sure user is pressing left mouse button if they're from desktop
if ((GetTouchPointCount() > 0) ||
((GetTouchPointCount() == 0) && IsMouseButtonDown(MouseButton.Left)))
{
// Find nearest D-Pad button to the input position
for (int i = 0; i < (int)PadButton.BUTTON_MAX; i++)
{
float distX = MathF.Abs(buttonPositions[i].X - inputPosition.X);
float distY = MathF.Abs(buttonPositions[i].Y - inputPosition.Y);
if ((distX + distY < buttonRadius))
{
pressedButton = i;
break;
}
}
}
// Move player according to pressed button
switch ((PadButton)pressedButton)
{
case PadButton.BUTTON_UP:
playerPosition.Y -= playerSpeed * GetFrameTime();
break;
case PadButton.BUTTON_LEFT:
playerPosition.X -= playerSpeed * GetFrameTime();
break;
case PadButton.BUTTON_RIGHT:
playerPosition.X += playerSpeed * GetFrameTime();
break;
case PadButton.BUTTON_DOWN:
playerPosition.Y += playerSpeed * GetFrameTime();
break;
default:
break;
}
;
//--------------------------------------------------------------------------
// Draw
//--------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw world
DrawCircleV(playerPosition, 50, Color.Maroon);
// Draw GUI
for (int i = 0; i < (int)PadButton.BUTTON_MAX; i++)
{
DrawCircleV(buttonPositions[i], buttonRadius, (i == pressedButton) ? Color.DarkGray : Color.Black);
DrawTriangle(
arrowTris[i][0],
arrowTris[i][1],
arrowTris[i][2],
buttonLabelColors[i]
);
}
DrawText("move the player with D-Pad buttons", 10, 10, 20, Color.DarkGray);
EndDrawing();
//--------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context

View file

@ -0,0 +1,510 @@
/*******************************************************************************************
*
* raylib [core] example - keyboard testbed
*
* Example complexity rating: [] 2/4
*
* NOTE: raylib defined keys refer to ENG-US Keyboard layout,
* mapping to other layouts is up to the user
*
* Example originally created with raylib 5.6, last time updated with raylib 5.6
*
* 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) 2026 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Core;
public partial class KeyboardTestbed : IExample
{
private const int KeyRecSpacing = 4; // Space in pixels between key rectangles
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Keyboard Testbed";
public string Title => "raylib [core] example - keyboard testbed";
private int[] line01KeyWidths;
private int[] line01Keys;
private int[] line02KeyWidths;
private int[] line02Keys;
private int[] line03KeyWidths;
private int[] line03Keys;
private int[] line04KeyWidths;
private int[] line04Keys;
private int[] line05KeyWidths;
private int[] line05Keys;
private int[] line06KeyWidths;
private int[] line06Keys;
private Vector2 keyboardOffset;
public void Init()
{
SetExitKey(KeyboardKey.Null); // Avoid exit on KEY_ESCAPE
// Keyboard line 01
line01KeyWidths = new int[15];
for (int i = 0; i < 15; i++)
{
line01KeyWidths[i] = 45;
}
line01KeyWidths[13] = 62; // PRINTSCREEN
line01Keys = new int[]
{
(int)KeyboardKey.Escape, (int)KeyboardKey.F1, (int)KeyboardKey.F2, (int)KeyboardKey.F3, (int)KeyboardKey.F4, (int)KeyboardKey.F5,
(int)KeyboardKey.F6, (int)KeyboardKey.F7, (int)KeyboardKey.F8, (int)KeyboardKey.F9, (int)KeyboardKey.F10, (int)KeyboardKey.F11,
(int)KeyboardKey.F12, (int)KeyboardKey.PrintScreen, (int)KeyboardKey.Pause
};
// Keyboard line 02
line02KeyWidths = new int[15];
for (int i = 0; i < 15; i++)
{
line02KeyWidths[i] = 45;
}
line02KeyWidths[0] = 25; // GRAVE
line02KeyWidths[13] = 82; // BACKSPACE
line02Keys = new int[]
{
(int)KeyboardKey.Grave, (int)KeyboardKey.One, (int)KeyboardKey.Two, (int)KeyboardKey.Three, (int)KeyboardKey.Four,
(int)KeyboardKey.Five, (int)KeyboardKey.Six, (int)KeyboardKey.Seven, (int)KeyboardKey.Eight, (int)KeyboardKey.Nine,
(int)KeyboardKey.Zero, (int)KeyboardKey.Minus, (int)KeyboardKey.Equal, (int)KeyboardKey.Backspace, (int)KeyboardKey.Delete
};
// Keyboard line 03
line03KeyWidths = new int[15];
for (int i = 0; i < 15; i++)
{
line03KeyWidths[i] = 45;
}
line03KeyWidths[0] = 50; // TAB
line03KeyWidths[13] = 57; // BACKSLASH
line03Keys = new int[]
{
(int)KeyboardKey.Tab, (int)KeyboardKey.Q, (int)KeyboardKey.W, (int)KeyboardKey.E, (int)KeyboardKey.R, (int)KeyboardKey.T, (int)KeyboardKey.Y,
(int)KeyboardKey.U, (int)KeyboardKey.I, (int)KeyboardKey.O, (int)KeyboardKey.P, (int)KeyboardKey.LeftBracket,
(int)KeyboardKey.RightBracket, (int)KeyboardKey.Backslash, (int)KeyboardKey.Insert
};
// Keyboard line 04
line04KeyWidths = new int[14];
for (int i = 0; i < 14; i++)
{
line04KeyWidths[i] = 45;
}
line04KeyWidths[0] = 68; // CAPS
line04KeyWidths[12] = 88; // ENTER
line04Keys = new int[]
{
(int)KeyboardKey.CapsLock, (int)KeyboardKey.A, (int)KeyboardKey.S, (int)KeyboardKey.D, (int)KeyboardKey.F, (int)KeyboardKey.G,
(int)KeyboardKey.H, (int)KeyboardKey.J, (int)KeyboardKey.K, (int)KeyboardKey.L, (int)KeyboardKey.Semicolon,
(int)KeyboardKey.Apostrophe, (int)KeyboardKey.Enter, (int)KeyboardKey.PageUp
};
// Keyboard line 05
line05KeyWidths = new int[14];
for (int i = 0; i < 14; i++)
{
line05KeyWidths[i] = 45;
}
line05KeyWidths[0] = 80; // LSHIFT
line05KeyWidths[11] = 76; // RSHIFT
line05Keys = new int[]
{
(int)KeyboardKey.LeftShift, (int)KeyboardKey.Z, (int)KeyboardKey.X, (int)KeyboardKey.C, (int)KeyboardKey.V, (int)KeyboardKey.B,
(int)KeyboardKey.N, (int)KeyboardKey.M, (int)KeyboardKey.Comma, (int)KeyboardKey.Period, /*KEY_MINUS*/
(int)KeyboardKey.Slash, (int)KeyboardKey.RightShift, (int)KeyboardKey.Up, (int)KeyboardKey.PageDown
};
// Keyboard line 06
line06KeyWidths = new int[11];
for (int i = 0; i < 11; i++)
{
line06KeyWidths[i] = 45;
}
line06KeyWidths[0] = 80; // LCTRL
line06KeyWidths[3] = 208; // SPACE
line06KeyWidths[7] = 60; // RCTRL
line06Keys = new int[]
{
(int)KeyboardKey.LeftControl, (int)KeyboardKey.LeftSuper, (int)KeyboardKey.LeftAlt,
(int)KeyboardKey.Space, (int)KeyboardKey.RightAlt, 162, (int)KeyboardKey.Null,
(int)KeyboardKey.RightControl, (int)KeyboardKey.Left, (int)KeyboardKey.Down, (int)KeyboardKey.Right
};
keyboardOffset = new Vector2(26, 80);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
int key = GetKeyPressed(); // Get pressed keycode
if (key > 0)
{
TraceLog(TraceLogLevel.Info, $"KEYBOARD TESTBED: KEY PRESSED: {key}");
}
int ch = GetCharPressed(); // Get pressed char for text input, using OS mapping
if (ch > 0)
{
TraceLog(TraceLogLevel.Info, $"KEYBOARD TESTBED: CHAR PRESSED: {(char)ch} ({ch})");
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("KEYBOARD LAYOUT: ENG-US", 26, 38, 20, Color.LightGray);
// Keyboard line 01 - 15 keys
// ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, IMP, CLOSE
for (int i = 0, recOffsetX = 0; i < 15; i++)
{
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y, (float)line01KeyWidths[i], 30.0f), line01Keys[i]);
recOffsetX += line01KeyWidths[i] + KeyRecSpacing;
}
// Keyboard line 02 - 15 keys
// `, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -, =, BACKSPACE, DEL
for (int i = 0, recOffsetX = 0; i < 15; i++)
{
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y + 30 + KeyRecSpacing, (float)line02KeyWidths[i], 38.0f), line02Keys[i]);
recOffsetX += line02KeyWidths[i] + KeyRecSpacing;
}
// Keyboard line 03 - 15 keys
// TAB, Q, W, E, R, T, Y, U, I, O, P, [, ], \, INS
for (int i = 0, recOffsetX = 0; i < 15; i++)
{
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y + 30 + 38 + KeyRecSpacing * 2, (float)line03KeyWidths[i], 38.0f), line03Keys[i]);
recOffsetX += line03KeyWidths[i] + KeyRecSpacing;
}
// Keyboard line 04 - 14 keys
// MAYUS, A, S, D, F, G, H, J, K, L, ;, ', ENTER, REPAG
for (int i = 0, recOffsetX = 0; i < 14; i++)
{
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y + 30 + 38 * 2 + KeyRecSpacing * 3, (float)line04KeyWidths[i], 38.0f), line04Keys[i]);
recOffsetX += line04KeyWidths[i] + KeyRecSpacing;
}
// Keyboard line 05 - 14 keys
// LSHIFT, Z, X, C, V, B, N, M, ,, ., /, RSHIFT, UP, AVPAG
for (int i = 0, recOffsetX = 0; i < 14; i++)
{
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y + 30 + 38 * 3 + KeyRecSpacing * 4, (float)line05KeyWidths[i], 38.0f), line05Keys[i]);
recOffsetX += line05KeyWidths[i] + KeyRecSpacing;
}
// Keyboard line 06 - 11 keys
// LCTRL, WIN, LALT, SPACE, ALTGR, \, FN, RCTRL, LEFT, DOWN, RIGHT
for (int i = 0, recOffsetX = 0; i < 11; i++)
{
GuiKeyboardKey(new Rectangle(keyboardOffset.X + recOffsetX, keyboardOffset.Y + 30 + 38 * 4 + KeyRecSpacing * 5, (float)line06KeyWidths[i], 38.0f), line06Keys[i]);
recOffsetX += line06KeyWidths[i] + KeyRecSpacing;
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
//------------------------------------------------------------------------------------
// Module Functions Definition
//------------------------------------------------------------------------------------
// Get keyboard keycode as text (US keyboard)
// NOTE: Mapping for other keyboard layouts can be done here
private static string GetKeyText(int key)
{
switch ((KeyboardKey)key)
{
case KeyboardKey.Apostrophe:
return "'"; // Key: '
case KeyboardKey.Comma:
return ","; // Key: ,
case KeyboardKey.Minus:
return "-"; // Key: -
case KeyboardKey.Period:
return "."; // Key: .
case KeyboardKey.Slash:
return "/"; // Key: /
case KeyboardKey.Zero:
return "0"; // Key: 0
case KeyboardKey.One:
return "1"; // Key: 1
case KeyboardKey.Two:
return "2"; // Key: 2
case KeyboardKey.Three:
return "3"; // Key: 3
case KeyboardKey.Four:
return "4"; // Key: 4
case KeyboardKey.Five:
return "5"; // Key: 5
case KeyboardKey.Six:
return "6"; // Key: 6
case KeyboardKey.Seven:
return "7"; // Key: 7
case KeyboardKey.Eight:
return "8"; // Key: 8
case KeyboardKey.Nine:
return "9"; // Key: 9
case KeyboardKey.Semicolon:
return ";"; // Key: ;
case KeyboardKey.Equal:
return "="; // Key: =
case KeyboardKey.A:
return "A"; // Key: A | a
case KeyboardKey.B:
return "B"; // Key: B | b
case KeyboardKey.C:
return "C"; // Key: C | c
case KeyboardKey.D:
return "D"; // Key: D | d
case KeyboardKey.E:
return "E"; // Key: E | e
case KeyboardKey.F:
return "F"; // Key: F | f
case KeyboardKey.G:
return "G"; // Key: G | g
case KeyboardKey.H:
return "H"; // Key: H | h
case KeyboardKey.I:
return "I"; // Key: I | i
case KeyboardKey.J:
return "J"; // Key: J | j
case KeyboardKey.K:
return "K"; // Key: K | k
case KeyboardKey.L:
return "L"; // Key: L | l
case KeyboardKey.M:
return "M"; // Key: M | m
case KeyboardKey.N:
return "N"; // Key: N | n
case KeyboardKey.O:
return "O"; // Key: O | o
case KeyboardKey.P:
return "P"; // Key: P | p
case KeyboardKey.Q:
return "Q"; // Key: Q | q
case KeyboardKey.R:
return "R"; // Key: R | r
case KeyboardKey.S:
return "S"; // Key: S | s
case KeyboardKey.T:
return "T"; // Key: T | t
case KeyboardKey.U:
return "U"; // Key: U | u
case KeyboardKey.V:
return "V"; // Key: V | v
case KeyboardKey.W:
return "W"; // Key: W | w
case KeyboardKey.X:
return "X"; // Key: X | x
case KeyboardKey.Y:
return "Y"; // Key: Y | y
case KeyboardKey.Z:
return "Z"; // Key: Z | z
case KeyboardKey.LeftBracket:
return "["; // Key: [
case KeyboardKey.Backslash:
return "\\"; // Key: '\'
case KeyboardKey.RightBracket:
return "]"; // Key: ]
case KeyboardKey.Grave:
return "`"; // Key: `
case KeyboardKey.Space:
return "SPACE"; // Key: Space
case KeyboardKey.Escape:
return "ESC"; // Key: Esc
case KeyboardKey.Enter:
return "ENTER"; // Key: Enter
case KeyboardKey.Tab:
return "TAB"; // Key: Tab
case KeyboardKey.Backspace:
return "BACK"; // Key: Backspace
case KeyboardKey.Insert:
return "INS"; // Key: Ins
case KeyboardKey.Delete:
return "DEL"; // Key: Del
case KeyboardKey.Right:
return "RIGHT"; // Key: Cursor right
case KeyboardKey.Left:
return "LEFT"; // Key: Cursor left
case KeyboardKey.Down:
return "DOWN"; // Key: Cursor down
case KeyboardKey.Up:
return "UP"; // Key: Cursor up
case KeyboardKey.PageUp:
return "PGUP"; // Key: Page up
case KeyboardKey.PageDown:
return "PGDOWN"; // Key: Page down
case KeyboardKey.Home:
return "HOME"; // Key: Home
case KeyboardKey.End:
return "END"; // Key: End
case KeyboardKey.CapsLock:
return "CAPS"; // Key: Caps lock
case KeyboardKey.ScrollLock:
return "LOCK"; // Key: Scroll down
case KeyboardKey.NumLock:
return "NUMLOCK"; // Key: Num lock
case KeyboardKey.PrintScreen:
return "PRINTSCR"; // Key: Print screen
case KeyboardKey.Pause:
return "PAUSE"; // Key: Pause
case KeyboardKey.F1:
return "F1"; // Key: F1
case KeyboardKey.F2:
return "F2"; // Key: F2
case KeyboardKey.F3:
return "F3"; // Key: F3
case KeyboardKey.F4:
return "F4"; // Key: F4
case KeyboardKey.F5:
return "F5"; // Key: F5
case KeyboardKey.F6:
return "F6"; // Key: F6
case KeyboardKey.F7:
return "F7"; // Key: F7
case KeyboardKey.F8:
return "F8"; // Key: F8
case KeyboardKey.F9:
return "F9"; // Key: F9
case KeyboardKey.F10:
return "F10"; // Key: F10
case KeyboardKey.F11:
return "F11"; // Key: F11
case KeyboardKey.F12:
return "F12"; // Key: F12
case KeyboardKey.LeftShift:
return "LSHIFT"; // Key: Shift left
case KeyboardKey.LeftControl:
return "LCTRL"; // Key: Control left
case KeyboardKey.LeftAlt:
return "LALT"; // Key: Alt left
case KeyboardKey.LeftSuper:
return "WIN"; // Key: Super left
case KeyboardKey.RightShift:
return "RSHIFT"; // Key: Shift right
case KeyboardKey.RightControl:
return "RCTRL"; // Key: Control right
case KeyboardKey.RightAlt:
return "ALTGR"; // Key: Alt right
case KeyboardKey.RightSuper:
return "RSUPER"; // Key: Super right
case KeyboardKey.KeyboardMenu:
return "KBMENU"; // Key: KB menu
case KeyboardKey.Kp0:
return "KP0"; // Key: Keypad 0
case KeyboardKey.Kp1:
return "KP1"; // Key: Keypad 1
case KeyboardKey.Kp2:
return "KP2"; // Key: Keypad 2
case KeyboardKey.Kp3:
return "KP3"; // Key: Keypad 3
case KeyboardKey.Kp4:
return "KP4"; // Key: Keypad 4
case KeyboardKey.Kp5:
return "KP5"; // Key: Keypad 5
case KeyboardKey.Kp6:
return "KP6"; // Key: Keypad 6
case KeyboardKey.Kp7:
return "KP7"; // Key: Keypad 7
case KeyboardKey.Kp8:
return "KP8"; // Key: Keypad 8
case KeyboardKey.Kp9:
return "KP9"; // Key: Keypad 9
case KeyboardKey.KpDecimal:
return "KPDEC"; // Key: Keypad .
case KeyboardKey.KpDivide:
return "KPDIV"; // Key: Keypad /
case KeyboardKey.KpMultiply:
return "KPMUL"; // Key: Keypad *
case KeyboardKey.KpSubtract:
return "KPSUB"; // Key: Keypad -
case KeyboardKey.KpAdd:
return "KPADD"; // Key: Keypad +
case KeyboardKey.KpEnter:
return "KPENTER"; // Key: Keypad Enter
case KeyboardKey.KpEqual:
return "KPEQU"; // Key: Keypad =
default:
return "";
}
}
// Draw keyboard key
private static void GuiKeyboardKey(Rectangle bounds, int key)
{
if (key == (int)KeyboardKey.Null)
{
DrawRectangleLinesEx(bounds, 2.0f, Color.LightGray);
}
else
{
if (IsKeyDown((KeyboardKey)key))
{
DrawRectangleLinesEx(bounds, 2.0f, Color.Maroon);
DrawText(GetKeyText(key), (int)(bounds.X + 4), (int)(bounds.Y + 4), 10, Color.Maroon);
}
else
{
DrawRectangleLinesEx(bounds, 2.0f, Color.DarkGray);
DrawText(GetKeyText(key), (int)(bounds.X + 4), (int)(bounds.Y + 4), 10, Color.DarkGray);
}
}
if (CheckCollisionPointRec(GetMousePosition(), bounds))
{
DrawRectangleRec(bounds, Fade(Color.Red, 0.2f));
DrawRectangleLinesEx(bounds, 3.0f, Color.Red);
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard testbed");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new KeyboardTestbed();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,153 +1,183 @@
/*******************************************************************************************
*
* raylib example - loading thread
* raylib [core] example - loading thread
*
* This example has been created using raylib 2.5 (www.raylib.com)
* NOTE: raylib is NOT thread-safe: the loading thread only updates plain data
* (progress counter and loaded flag); all raylib calls happen on the main thread.
*
* Example originally created with raylib 2.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Threading;
using static Raylib_cs.Raylib;
using static Raylib_cs.Color;
using static Raylib_cs.KeyboardKey;
using System.Diagnostics;
namespace Examples.Core;
enum State
[ExcludeFromBrowser("System.Threading.Thread is unsupported on single-threaded wasm")]
public partial class LoadingThread : IExample
{
STATE_WAITING,
STATE_LOADING,
STATE_FINISHED
}
const int screenWidth = 800;
const int screenHeight = 450;
public class LoadingThread
{
// C# bool is atomic. Used for synchronization
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables#atomicity-of-variable-references
// Data Loaded completion indicator
static bool dataLoaded = false;
public string Name => "Core / Loading Thread";
// Data progress accumulator
static int dataProgress = 0;
public string Title => "raylib [core] example - loading thread";
enum State
{
Waiting,
Loading,
Finished
}
// Loading data thread; a Thread can only be started once, so a fresh one
// is created for every load
Thread loadingThread;
// Data loaded completion indicator; volatile so the main thread sees the
// background thread's writes
volatile bool dataLoaded;
// Data progress accumulator (0..500, the progress bar width in pixels)
volatile int dataProgress;
State state;
int framesCounter;
public void Init()
{
loadingThread = null;
dataLoaded = false;
dataProgress = 0;
state = State.Waiting;
framesCounter = 0;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
switch (state)
{
case State.Waiting:
if (IsKeyPressed(KeyboardKey.Enter))
{
loadingThread = new Thread(LoadDataThread) { IsBackground = true };
loadingThread.Start();
TraceLog(TraceLogLevel.Info, "Loading thread initialized successfully");
state = State.Loading;
}
break;
case State.Loading:
framesCounter++;
if (dataLoaded)
{
framesCounter = 0;
loadingThread.Join();
TraceLog(TraceLogLevel.Info, "Loading thread terminated");
state = State.Finished;
}
break;
case State.Finished:
if (IsKeyPressed(KeyboardKey.Enter))
{
// Reset everything to launch again
dataLoaded = false;
dataProgress = 0;
state = State.Waiting;
}
break;
default:
break;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
switch (state)
{
case State.Waiting:
DrawText("PRESS ENTER to START LOADING DATA", 150, 170, 20, Color.DarkGray);
break;
case State.Loading:
DrawRectangle(150, 200, dataProgress, 60, Color.SkyBlue);
if ((framesCounter / 15) % 2 == 0)
{
DrawText("LOADING DATA...", 240, 210, 40, Color.DarkBlue);
}
break;
case State.Finished:
DrawRectangle(150, 200, 500, 60, Color.Lime);
DrawText("DATA LOADED!", 250, 210, 40, Color.Green);
break;
default:
break;
}
DrawRectangleLines(150, 200, 500, 60, Color.DarkGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - loading thread");
// Loading data thread id
Thread thread = new(new ThreadStart(LoadDataThread));
State state = State.STATE_WAITING;
int framesCounter = 0;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new LoadingThread();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
switch (state)
{
case State.STATE_WAITING:
{
if (IsKeyPressed(KEY_ENTER))
{
thread.Start();
//int error = pthread_create(ref, NULL, ref, NULL);
//if (error != 0) TraceLog(TraceLogLevel.LOG_ERROR, "Error creating loading thread");
//else TraceLog(TraceLogLevel.LOG_INFO, "Loading thread initialized successfully");
state = State.STATE_LOADING;
}
}
break;
case State.STATE_LOADING:
{
framesCounter++;
if (dataLoaded)
{
framesCounter = 0;
state = State.STATE_FINISHED;
}
}
break;
case State.STATE_FINISHED:
{
if (IsKeyPressed(KEY_ENTER))
{
// Reset everything to launch again
// atomic_store(ref, false);
dataProgress = 0;
state = State.STATE_WAITING;
}
}
break;
default: break;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
switch (state)
{
case State.STATE_WAITING:
DrawText("PRESS ENTER to START LOADING DATA", 150, 170, 20, DARKGRAY);
break;
case State.STATE_LOADING:
{
DrawRectangle(150, 200, dataProgress, 60, SKYBLUE);
if ((framesCounter / 15) % 2 == 0) DrawText("LOADING DATA...", 240, 210, 40, DARKBLUE);
}
break;
case State.STATE_FINISHED:
{
DrawRectangle(150, 200, 500, 60, LIME);
DrawText("DATA LOADED!", 250, 210, 40, GREEN);
}
break;
default: break;
}
DrawRectangleLines(150, 200, 500, 60, DARKGRAY);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
// Loading data thread function definition
static void LoadDataThread()
void LoadDataThread()
{
int timeCounter = 0; // Time counted in ms
// clock_t prevTime = clock(); // Previous time
int timeCounter = 0; // Time counted in ms
var stopwatch = Stopwatch.StartNew();
// We simulate data loading with a time counter for 5 seconds
while (timeCounter < 5000)
{
//clock_t currentTime = clock() - prevTime;
//timeCounter = currentTime*1000/CLOCKS_PER_SEC;
timeCounter += 1;
timeCounter = (int)stopwatch.ElapsedMilliseconds;
// We accumulate time over a global variable to be used in
// main thread as a progress bar
@ -158,4 +188,3 @@ public class LoadingThread
dataLoaded = true;
}
}

View file

@ -0,0 +1,205 @@
/*******************************************************************************************
*
* raylib [core] example - monitor detector
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.6
*
* Example contributed by Maicon Santana (@maiconpintoabreu) 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 Maicon Santana (@maiconpintoabreu)
*
********************************************************************************************/
namespace Examples.Core;
[ExcludeFromBrowser("GetMonitorCount() is not implemented on the wasm target")]
public partial class MonitorDetector : IExample
{
private const int MaxMonitors = 10;
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Monitor Detector";
public string Title => "raylib [core] example - monitor detector";
// Monitor info
private struct MonitorInfo
{
public Vector2 Position;
public string Name;
public int Width;
public int Height;
public int PhysicalWidth;
public int PhysicalHeight;
public int RefreshRate;
}
private MonitorInfo[] monitors;
private int currentMonitorIndex;
private int monitorCount;
public void Init()
{
monitors = new MonitorInfo[MaxMonitors];
currentMonitorIndex = GetCurrentMonitor();
monitorCount = 0;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Variables to find the max x and Y to calculate the scale
int maxWidth = 1;
int maxHeight = 1;
// Monitor offset is to fix when monitor position x is negative
int monitorOffsetX = 0;
// Rebuild monitors array every frame
monitorCount = GetMonitorCount();
for (int i = 0; i < monitorCount; i++)
{
monitors[i] = new MonitorInfo
{
Position = GetMonitorPosition(i),
Name = GetMonitorName_(i),
Width = GetMonitorWidth(i),
Height = GetMonitorHeight(i),
PhysicalWidth = GetMonitorPhysicalWidth(i),
PhysicalHeight = GetMonitorPhysicalHeight(i),
RefreshRate = GetMonitorRefreshRate(i)
};
if (monitors[i].Position.X < monitorOffsetX)
{
monitorOffsetX = -(int)monitors[i].Position.X;
}
int width = (int)monitors[i].Position.X + monitors[i].Width;
int height = (int)monitors[i].Position.Y + monitors[i].Height;
if (maxWidth < width)
{
maxWidth = width;
}
if (maxHeight < height)
{
maxHeight = height;
}
}
if (IsKeyPressed(KeyboardKey.Enter) && (monitorCount > 1))
{
currentMonitorIndex += 1;
// Set index to 0 if the last one
if (currentMonitorIndex == monitorCount)
{
currentMonitorIndex = 0;
}
SetWindowMonitor(currentMonitorIndex); // Move window to currentMonitorIndex
}
else
{
currentMonitorIndex = GetCurrentMonitor(); // Get currentMonitorIndex if manually moved
}
float monitorScale = 0.6f;
if (maxHeight > (maxWidth + monitorOffsetX))
{
monitorScale *= ((float)screenHeight / (float)maxHeight);
}
else
{
monitorScale *= ((float)screenWidth / (float)(maxWidth + monitorOffsetX));
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("Press [Enter] to move window to next monitor available", 20, 20, 20, Color.DarkGray);
DrawRectangleLines(20, 60, screenWidth - 40, screenHeight - 100, Color.DarkGray);
// Draw Monitor Rectangles with information inside
for (int i = 0; i < monitorCount; i++)
{
// Calculate retangle position and size using monitorScale
Rectangle rec = new Rectangle(
(monitors[i].Position.X + monitorOffsetX) * monitorScale + 140,
monitors[i].Position.Y * monitorScale + 80,
monitors[i].Width * monitorScale,
monitors[i].Height * monitorScale
);
// Draw monitor name and information inside the rectangle
DrawText($"[{i}] {monitors[i].Name}", (int)rec.X + 10, (int)rec.Y + (int)(100 * monitorScale), (int)(120 * monitorScale), Color.Blue);
DrawText(
$"Resolution: [{monitors[i].Width}px x {monitors[i].Height}px]\nRefreshRate: [{monitors[i].RefreshRate}hz]\nPhysical Size: [{monitors[i].PhysicalWidth}mm x {monitors[i].PhysicalHeight}mm]\nPosition: {monitors[i].Position.X,3:F0} x {monitors[i].Position.Y,3:F0}",
(int)rec.X + 10, (int)rec.Y + (int)(200 * monitorScale), (int)(120 * monitorScale), Color.DarkGray);
// Highlight current monitor
if (i == currentMonitorIndex)
{
DrawRectangleLinesEx(rec, 5, Color.Red);
Vector2 windowPosition = new Vector2((GetWindowPosition().X + monitorOffsetX) * monitorScale + 140, GetWindowPosition().Y * monitorScale + 80);
// Draw window position based on monitors
DrawRectangleV(windowPosition, new Vector2(screenWidth * monitorScale, screenHeight * monitorScale), Fade(Color.Green, 0.5f));
}
else
{
DrawRectangleLinesEx(rec, 5, Color.Gray);
}
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - monitor detector");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new MonitorDetector();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,119 +1,162 @@
/*******************************************************************************************
*
* raylib [core] example - Picking in 3d mode
* raylib [core] example - 3d picking
*
* This example has been created using raylib 1.3 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.3, 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) 2015-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class Picking3d
public partial class Picking3d : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Picking 3D";
public string Title => "raylib [core] example - 3d picking";
private Camera3D camera;
private Vector3 cubePosition;
private Vector3 cubeSize;
private Ray ray; // Picking line ray
private RayCollision collision; // Ray collision hit info
public void Init()
{
// Define the camera to look into our 3d world
camera = new Camera3D();
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
camera.FovY = 45.0f; // Camera field-of-view Y
camera.Projection = CameraProjection.Perspective; // Camera projection type
cubePosition = new(0.0f, 1.0f, 0.0f);
cubeSize = new(2.0f, 2.0f, 2.0f);
ray = new(); // Picking line ray
collision = new(); // Ray collision hit info
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsCursorHidden())
{
UpdateCamera(ref camera, CameraMode.FirstPerson);
}
// Toggle camera controls
if (IsMouseButtonPressed(MouseButton.Right))
{
if (IsCursorHidden())
{
EnableCursor();
}
else
{
DisableCursor();
}
}
if (IsMouseButtonPressed(MouseButton.Left))
{
if (!collision.Hit)
{
ray = GetScreenToWorldRay(GetMousePosition(), camera);
// Check collision between ray and box
BoundingBox box = new(
cubePosition - cubeSize / 2,
cubePosition + cubeSize / 2
);
collision = GetRayCollisionBox(ray, box);
}
else
{
collision.Hit = false;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
if (collision.Hit)
{
DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Red);
DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Maroon);
DrawCubeWires(cubePosition, cubeSize.X + 0.2f, cubeSize.Y + 0.2f, cubeSize.Z + 0.2f, Color.Green);
}
else
{
DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Gray);
DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.DarkGray);
}
DrawRay(ray, Color.Maroon);
DrawGrid(10, 1.0f);
EndMode3D();
DrawText("Try clicking on the box with your mouse!", 240, 10, 20, Color.DarkGray);
if (collision.Hit)
{
var posX = (screenWidth - MeasureText("BOX SELECTED", 30)) / 2;
DrawText("BOX SELECTED", posX, (int)(screenHeight * 0.1f), 30, Color.Green);
}
DrawText("Right click mouse to toggle camera controls", 10, 430, 10, Color.Gray);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d picking");
// Define the camera to look into our 3d world
Camera3D camera;
camera.Position = new Vector3(10.0f, 10.0f, 10.0f);
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.FovY = 45.0f;
camera.Projection = CameraProjection.Perspective;
Vector3 cubePosition = new(0.0f, 1.0f, 0.0f);
Vector3 cubeSize = new(2.0f, 2.0f, 2.0f);
// Picking line ray
Ray ray = new(new Vector3(0.0f, 0.0f, 0.0f), Vector3.Zero);
RayCollision collision = new();
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new Picking3d();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.Free);
if (IsMouseButtonPressed(MouseButton.Left))
{
if (!collision.Hit)
{
ray = GetScreenToWorldRay(GetMousePosition(), camera);
// Check collision between ray and box
BoundingBox box = new(
cubePosition - cubeSize / 2,
cubePosition + cubeSize / 2
);
collision = GetRayCollisionBox(ray, box);
}
else
{
collision.Hit = false;
}
ray = GetScreenToWorldRay(GetMousePosition(), camera);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
if (collision.Hit)
{
DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Red);
DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Maroon);
DrawCubeWires(cubePosition, cubeSize.X + 0.2f, cubeSize.Y + 0.2f, cubeSize.Z + 0.2f, Color.Green);
}
else
{
DrawCube(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.Gray);
DrawCubeWires(cubePosition, cubeSize.X, cubeSize.Y, cubeSize.Z, Color.DarkGray);
}
DrawRay(ray, Color.Maroon);
DrawGrid(10, 1.0f);
EndMode3D();
DrawText("Try selecting the box with mouse!", 240, 10, 20, Color.DarkGray);
if (collision.Hit)
{
int posX = (screenWidth - MeasureText("BOX SELECTED", 30)) / 2;
DrawText("BOX SELECTED", posX, (int)(screenHeight * 0.1f), 30, Color.Green);
}
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,180 @@
/*******************************************************************************************
*
* raylib [core] example - random sequence
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 5.0, last time updated with raylib 5.0
*
* Example contributed by Dalton Overmyer (@REDl3east) 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) 2023-2025 Dalton Overmyer (@REDl3east)
*
********************************************************************************************/
using static Raylib_cs.Raymath;
namespace Examples.Core;
public partial class RandomSequence : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Random Sequence";
public string Title => "raylib [core] example - random sequence";
private struct ColorRect
{
public Color Color;
public Rectangle Rect;
}
private int rectCount;
private float rectSize;
private ColorRect[] rectangles;
public void Init()
{
rectCount = 20;
rectSize = (float)screenWidth / rectCount;
rectangles = GenerateRandomColorRectSequence(rectCount, rectSize, screenWidth, 0.75f * screenHeight);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.Space))
{
ShuffleColorRectSequence(rectangles, rectCount);
}
if (IsKeyPressed(KeyboardKey.Up))
{
rectCount++;
rectSize = (float)screenWidth / rectCount;
// Re-generate random sequence with new count
rectangles = GenerateRandomColorRectSequence(rectCount, rectSize, screenWidth, 0.75f * screenHeight);
}
if (IsKeyPressed(KeyboardKey.Down))
{
if (rectCount >= 4)
{
rectCount--;
rectSize = (float)screenWidth / rectCount;
// Re-generate random sequence with new count
rectangles = GenerateRandomColorRectSequence(rectCount, rectSize, screenWidth, 0.75f * screenHeight);
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
for (int i = 0; i < rectCount; i++)
{
DrawRectangleRec(rectangles[i].Rect, rectangles[i].Color);
DrawText("Press SPACE to shuffle the current sequence", 10, screenHeight - 96, 20, Color.Black);
DrawText("Press UP to add a rectangle and generate a new sequence", 10, screenHeight - 64, 20, Color.Black);
DrawText("Press DOWN to remove a rectangle and generate a new sequence", 10, screenHeight - 32, 20, Color.Black);
}
DrawText($"Count: {rectCount} rectangles", 10, 10, 20, Color.Maroon);
DrawFPS(screenWidth - 80, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
private static Color GenerateRandomColor()
{
return new Color(
GetRandomValue(0, 255),
GetRandomValue(0, 255),
GetRandomValue(0, 255),
255
);
}
private static ColorRect[] GenerateRandomColorRectSequence(float rectCount, float rectWidth, float screenWidth, float screenHeight)
{
ColorRect[] rectangles = new ColorRect[(int)rectCount];
int[] seq = GetRandomSequence((uint)rectCount, 0, (int)rectCount - 1);
float rectSeqWidth = rectCount * rectWidth;
float startX = (screenWidth - rectSeqWidth) * 0.5f;
for (int i = 0; i < rectCount; i++)
{
int rectHeight = (int)Remap(seq[i], 0, rectCount - 1, 0, screenHeight);
rectangles[i].Color = GenerateRandomColor();
rectangles[i].Rect = new Rectangle(startX + i * rectWidth, screenHeight - rectHeight, rectWidth, rectHeight);
}
return rectangles;
}
private static void ShuffleColorRectSequence(ColorRect[] rectangles, int rectCount)
{
int[] seq = GetRandomSequence((uint)rectCount, 0, rectCount - 1);
for (int i1 = 0; i1 < rectCount; i1++)
{
int i2 = seq[i1];
// Swap only the color and height
ColorRect tmp = rectangles[i1];
rectangles[i1].Color = rectangles[i2].Color;
rectangles[i1].Rect.Height = rectangles[i2].Rect.Height;
rectangles[i1].Rect.Y = rectangles[i2].Rect.Y;
rectangles[i2].Color = tmp.Color;
rectangles[i2].Rect.Height = tmp.Rect.Height;
rectangles[i2].Rect.Y = tmp.Rect.Y;
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - random sequence");
SetTargetFPS(60);
var game = new RandomSequence();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,69 +1,95 @@
/*******************************************************************************************
*
* raylib [core] example - Generate random values
* raylib [core] example - random values
*
* This example has been created using raylib 1.1 (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.1, last time updated with raylib 1.1
*
* 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.Core;
public class RandomValues
public partial class RandomValues : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Random Values";
public string Title => "raylib [core] example - random values";
private int randValue; // Get a random integer number between -8 and 5 (both included)
private int framesCounter; // Variable used to count frames
public void Init()
{
// SetRandomSeed(0xaabbccff); // Set a custom random seed if desired, by default: "time(NULL)"
randValue = GetRandomValue(-8, 5); // Get a random integer number between -8 and 5 (both included)
framesCounter = 0; // Variable used to count frames
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
framesCounter++;
// Every two seconds (120 frames) a new random value is generated
if (((framesCounter / 120) % 2) == 1)
{
randValue = GetRandomValue(-8, 5);
framesCounter = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("Every 2 seconds a new random value is generated:", 130, 100, 20, Color.Maroon);
DrawText($"{randValue}", 360, 180, 80, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - random values");
InitWindow(screenWidth, screenHeight, "raylib [core] example - generate random values");
// Variable used to count frames
int framesCounter = 0;
// Get a random integer number between -8 and 5 (both included)
int randValue = GetRandomValue(-8, 5);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new RandomValues();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
framesCounter++;
// Every two seconds (120 frames) a new random value is generated
if (((framesCounter / 120) % 2) == 1)
{
randValue = GetRandomValue(-8, 5);
framesCounter = 0;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("Every 2 seconds a new random value is generated:", 130, 100, 20, Color.Maroon);
DrawText($"{randValue}", 360, 180, 80, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,135 @@
/*******************************************************************************************
*
* raylib [core] example - render texture
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.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) 2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Core;
public partial class RenderTextureDemo : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
// Define a render texture to render
private const int renderTextureWidth = 300;
private const int renderTextureHeight = 300;
public string Name => "Core / Render Texture";
public string Title => "raylib [core] example - render texture";
private RenderTexture2D target;
private Vector2 ballPosition;
private Vector2 ballSpeed;
private int ballRadius;
private float rotation;
public void Init()
{
target = LoadRenderTexture(renderTextureWidth, renderTextureHeight);
ballPosition = new Vector2(renderTextureWidth / 2.0f, renderTextureHeight / 2.0f);
ballSpeed = new Vector2(5.0f, 4.0f);
ballRadius = 20;
rotation = 0.0f;
}
public void Update()
{
// Update
//-----------------------------------------------------
// Ball movement logic
ballPosition.X += ballSpeed.X;
ballPosition.Y += ballSpeed.Y;
// Check walls collision for bouncing
if ((ballPosition.X >= (renderTextureWidth - ballRadius)) || (ballPosition.X <= ballRadius))
{
ballSpeed.X *= -1.0f;
}
if ((ballPosition.Y >= (renderTextureHeight - ballRadius)) || (ballPosition.Y <= ballRadius))
{
ballSpeed.Y *= -1.0f;
}
// Render texture rotation
rotation += 0.5f;
//-----------------------------------------------------
// Draw
//-----------------------------------------------------
// Draw our scene to the render texture
BeginTextureMode(target);
ClearBackground(Color.SkyBlue);
DrawRectangle(0, 0, 20, 20, Color.Red);
DrawCircleV(ballPosition, ballRadius, Color.Maroon);
EndTextureMode();
// Draw render texture to main framebuffer
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw our render texture with rotation applied
// NOTE 1: We set the origin of the texture to the center of the render texture
// NOTE 2: We flip vertically the texture setting negative source rectangle height
DrawTexturePro(target.Texture,
new Rectangle(0, 0, target.Texture.Width, -target.Texture.Height),
new Rectangle(screenWidth / 2.0f, screenHeight / 2.0f, target.Texture.Width, target.Texture.Height),
new Vector2(target.Texture.Width / 2.0f, target.Texture.Height / 2.0f), rotation, Color.White);
DrawText("DRAWING BOUNCING BALL INSIDE RENDER TEXTURE!", 10, screenHeight - 40, 20, Color.Black);
DrawFPS(10, 10);
EndDrawing();
//-----------------------------------------------------
}
public void Unload()
{
UnloadRenderTexture(target);
}
public static int Main()
{
// Initialization
//---------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - render texture");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//----------------------------------------------------------
var game = new RenderTextureDemo();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//---------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//----------------------------------------------------------
return 0;
}
}

View file

@ -1,82 +1,108 @@
/*******************************************************************************************
*
* raylib [core] example - Scissor test
* raylib [core] example - scissor test
*
* 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: [] 1/4
*
* Example originally created with raylib 2.5, last time updated with raylib 3.0
*
* Example contributed by Chris Dill (@MysteriousSpace) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2019 Chris Dill (@MysteriousSpace)
* 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 Chris Dill (@MysteriousSpace)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class ScissorTest
public partial class ScissorTest : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Scissor Test";
public string Title => "raylib [core] example - scissor test";
private Rectangle scissorArea;
private bool scissorMode;
public void Init()
{
scissorArea = new(0, 0, 300, 300);
scissorMode = true;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.S))
{
scissorMode = !scissorMode;
}
// Centre the scissor area around the mouse position
scissorArea.X = GetMouseX() - scissorArea.Width / 2;
scissorArea.Y = GetMouseY() - scissorArea.Height / 2;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (scissorMode)
{
BeginScissorMode((int)scissorArea.X, (int)scissorArea.Y, (int)scissorArea.Width, (int)scissorArea.Height);
}
// Draw full screen rectangle and some text
// NOTE: Only part defined by scissor area will be rendered
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Color.Red);
DrawText("Move the mouse around to reveal this text!", 190, 200, 20, Color.LightGray);
if (scissorMode)
{
EndScissorMode();
}
DrawRectangleLinesEx(scissorArea, 1, Color.Black);
DrawText("Press S to toggle scissor test", 10, 10, 20, Color.Black);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - scissor test");
Rectangle scissorArea = new(0, 0, 300, 300);
bool scissorMode = true;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new ScissorTest();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.S))
{
scissorMode = !scissorMode;
}
// Centre the scissor area around the mouse position
scissorArea.X = GetMouseX() - scissorArea.Width / 2;
scissorArea.Y = GetMouseY() - scissorArea.Height / 2;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (scissorMode)
{
BeginScissorMode((int)scissorArea.X, (int)scissorArea.Y, (int)scissorArea.Width, (int)scissorArea.Height);
}
// Draw full screen rectangle and some text
// NOTE: Only part defined by scissor area will be rendered
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Color.Red);
DrawText("Move the mouse around to reveal this text!", 190, 200, 20, Color.LightGray);
if (scissorMode)
{
EndScissorMode();
}
DrawRectangleLinesEx(scissorArea, 1, Color.Black);
DrawText("Press S to toggle scissor test", 10, 10, 20, Color.Black);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -0,0 +1,394 @@
/*******************************************************************************************
*
* raylib [core] example - screen recording
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.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) 2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Core;
// NOTE: The upstream C example records frames into an animated GIF using the bundled msf_gif.h
// single-header library. raylib-cs does not bind msf_gif, so this port replaces it with a small,
// self-contained GIF89a encoder (GifRecorder, below) that uses a fixed 3-3-2 RGB palette. The
// rest of the example (rendering, CTRL+R toggle, saving to <appdir>/screenrecording.gif) mirrors
// upstream. Frame capture via LoadImageFromScreen() is slow and can cause stuttering, as noted
// upstream.
[ExcludeFromBrowser("desktop screen capture + gif file export, no web equivalent")]
public partial class ScreenRecording : IExample
{
private const int GIF_RECORD_FRAMERATE = 5; // Record framerate, we get a frame every N frames
private const int MAX_SINEWAVE_POINTS = 256;
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Screen Recording";
public string Title => "raylib [core] example - screen recording";
private bool gifRecording; // GIF recording state
private uint gifFrameCounter; // GIF frames counter
private GifRecorder gifState; // GIF context state
private Vector2 circlePosition;
private float timeCounter;
private Vector2[] sinePoints;
public void Init()
{
gifRecording = false;
gifFrameCounter = 0;
gifState = new GifRecorder();
circlePosition = new Vector2(0.0f, screenHeight / 2.0f);
timeCounter = 0.0f;
// Get sine wave points for line drawing
sinePoints = new Vector2[MAX_SINEWAVE_POINTS];
for (int i = 0; i < MAX_SINEWAVE_POINTS; i++)
{
sinePoints[i].X = i * GetScreenWidth() / 180.0f;
sinePoints[i].Y = screenHeight / 2.0f + 150 * MathF.Sin((2 * MathF.PI / 1.5f) * (1.0f / 60.0f) * (float)i); // Calculate for 60 fps
}
}
public unsafe void Update()
{
// Update
//----------------------------------------------------------------------------------
// Update circle sinusoidal movement
timeCounter += GetFrameTime();
circlePosition.X += GetScreenWidth() / 180.0f;
circlePosition.Y = screenHeight / 2.0f + 150 * MathF.Sin((2 * MathF.PI / 1.5f) * timeCounter);
if (circlePosition.X > screenWidth)
{
circlePosition.X = 0.0f;
circlePosition.Y = screenHeight / 2.0f;
timeCounter = 0.0f;
}
// Start-Stop GIF recording on CTRL+R
if (IsKeyDown(KeyboardKey.LeftControl) && IsKeyPressed(KeyboardKey.R))
{
if (gifRecording)
{
// Stop current recording and save file
gifRecording = false;
byte[] result = gifState.End();
SaveFileData(result, $"{GetApplicationDirectoryString()}/screenrecording.gif");
TraceLog(TraceLogLevel.Info, "Finish animated GIF recording");
}
else
{
// Start a new recording
gifRecording = true;
gifFrameCounter = 0;
gifState.Begin(GetRenderWidth(), GetRenderHeight());
TraceLog(TraceLogLevel.Info, "Start animated GIF recording");
}
}
if (gifRecording)
{
gifFrameCounter++;
// NOTE: We record one gif frame depending on the desired gif framerate
if (gifFrameCounter > GIF_RECORD_FRAMERATE)
{
// Get image data for the current frame (from backbuffer)
// WARNING: This process is quite slow, it can generate stuttering
Image imScreen = LoadImageFromScreen();
// Add the frame to the gif recording, providing and "estimated" time for display in centiseconds
int delayCs = (int)((1.0f / 60.0f) * GIF_RECORD_FRAMERATE) / 10;
gifState.AddFrame((byte*)imScreen.Data, imScreen.Width, imScreen.Height, imScreen.Width * 4, delayCs);
gifFrameCounter = 0;
UnloadImage(imScreen); // Free image data
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
for (int i = 0; i < (MAX_SINEWAVE_POINTS - 1); i++)
{
DrawLineV(sinePoints[i], sinePoints[i + 1], Color.Maroon);
DrawCircleV(sinePoints[i], 3, Color.Maroon);
}
DrawCircleV(circlePosition, 30, Color.Red);
DrawFPS(10, 10);
/*
// Draw record indicator
// WARNING: If drawn here, it will appear in the recorded image,
// use a render texture instead for the recording and LoadImageFromTexture(rt.texture)
if (gifRecording)
{
// Display the recording indicator every half-second
if ((int)(GetTime()/0.5)%2 == 1)
{
DrawCircle(30, GetScreenHeight() - 20, 10, Color.Maroon);
DrawText("GIF RECORDING", 50, GetScreenHeight() - 25, 10, Color.Red);
}
}
*/
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
// If still recording a GIF on close window, just finish
if (gifRecording)
{
gifState.End();
gifRecording = false;
}
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - screen recording");
var game = new ScreenRecording();
game.Init();
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// 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;
}
// Minimal self-contained animated GIF89a encoder (replacement for msf_gif.h)
// Uses a fixed 3-3-2 RGB global palette and standard GIF-variant LZW compression.
private class GifRecorder
{
private List<byte> output;
private int width;
private int height;
// LZW bit-packing state (per-frame)
private int bitBuffer;
private int bitCount;
private List<byte> subBlock;
public void Begin(int w, int h)
{
width = w;
height = h;
output = new List<byte>();
// Header
output.AddRange(new byte[] { (byte)'G', (byte)'I', (byte)'F', (byte)'8', (byte)'9', (byte)'a' });
// Logical Screen Descriptor
WriteU16(width);
WriteU16(height);
output.Add(0xF7); // Global color table present, 8-bit color res, 256-entry table
output.Add(0x00); // Background color index
output.Add(0x00); // Pixel aspect ratio
// Global Color Table: 256 entries, 3-3-2 RGB
for (int k = 0; k < 256; k++)
{
int r3 = (k >> 5) & 0x7;
int g3 = (k >> 2) & 0x7;
int b2 = k & 0x3;
output.Add((byte)((r3 << 5) | (r3 << 2) | (r3 >> 1)));
output.Add((byte)((g3 << 5) | (g3 << 2) | (g3 >> 1)));
output.Add((byte)((b2 << 6) | (b2 << 4) | (b2 << 2) | b2));
}
// NETSCAPE2.0 application extension (loop forever)
output.Add(0x21);
output.Add(0xFF);
output.Add(0x0B);
output.AddRange(new byte[] { (byte)'N', (byte)'E', (byte)'T', (byte)'S', (byte)'C', (byte)'A', (byte)'P', (byte)'E', (byte)'2', (byte)'.', (byte)'0' });
output.Add(0x03);
output.Add(0x01);
WriteU16(0); // Loop count (0 = forever)
output.Add(0x00);
}
public unsafe void AddFrame(byte* data, int w, int h, int stride, int delayCs)
{
if (output == null)
{
return;
}
// Graphic Control Extension
output.Add(0x21);
output.Add(0xF9);
output.Add(0x04);
output.Add(0x00); // No transparency, disposal method 0
WriteU16(delayCs);
output.Add(0x00); // Transparent color index
output.Add(0x00); // Block terminator
// Image Descriptor
output.Add(0x2C);
WriteU16(0); // Left
WriteU16(0); // Top
WriteU16(w);
WriteU16(h);
output.Add(0x00); // No local color table, not interlaced
// Map pixels to palette indices (3-3-2)
byte[] indices = new byte[w * h];
for (int y = 0; y < h; y++)
{
int row = y * stride;
int dst = y * w;
for (int x = 0; x < w; x++)
{
byte r = data[row + x * 4 + 0];
byte g = data[row + x * 4 + 1];
byte b = data[row + x * 4 + 2];
indices[dst + x] = (byte)((r & 0xE0) | ((g & 0xE0) >> 3) | (b >> 6));
}
}
// LZW image data
const int minCodeSize = 8;
output.Add((byte)minCodeSize);
bitBuffer = 0;
bitCount = 0;
subBlock = new List<byte>();
int clearCode = 1 << minCodeSize; // 256
int stopCode = clearCode + 1; // 257
int keySize = minCodeSize + 1; // 9
int nkeys = clearCode + 2; // 258
var dict = new Dictionary<int, int>();
WriteBits(clearCode, keySize);
int key = indices[0];
for (int i = 1; i < indices.Length; i++)
{
int p = indices[i];
int combined = (key << 8) | p;
if (dict.TryGetValue(combined, out int existing))
{
key = existing;
}
else
{
WriteBits(key, keySize);
dict[combined] = nkeys;
nkeys++;
if (nkeys == (1 << keySize))
{
if (keySize < 12)
{
keySize++;
}
}
if (nkeys == 0x1000)
{
WriteBits(clearCode, keySize);
dict.Clear();
keySize = minCodeSize + 1;
nkeys = clearCode + 2;
}
key = p;
}
}
WriteBits(key, keySize);
WriteBits(stopCode, keySize);
// Flush remaining bits
if (bitCount > 0)
{
subBlock.Add((byte)(bitBuffer & 0xFF));
bitBuffer = 0;
bitCount = 0;
}
if (subBlock.Count > 0)
{
FlushSubBlock();
}
output.Add(0x00); // Image data block terminator
}
public byte[] End()
{
if (output == null)
{
return Array.Empty<byte>();
}
output.Add(0x3B); // Trailer
byte[] result = output.ToArray();
output = null;
return result;
}
private void WriteBits(int code, int len)
{
bitBuffer |= code << bitCount;
bitCount += len;
while (bitCount >= 8)
{
subBlock.Add((byte)(bitBuffer & 0xFF));
bitBuffer >>= 8;
bitCount -= 8;
if (subBlock.Count == 255)
{
FlushSubBlock();
}
}
}
private void FlushSubBlock()
{
output.Add((byte)subBlock.Count);
output.AddRange(subBlock);
subBlock.Clear();
}
private void WriteU16(int value)
{
output.Add((byte)(value & 0xFF));
output.Add((byte)((value >> 8) & 0xFF));
}
}
}

View file

@ -1,134 +1,210 @@
/*******************************************************************************************
*
* raylib [core] example - smooth pixel-perfect camera
* raylib [core] example - smooth pixelperfect
*
* This example has been created using raylib 3.7 (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 3.7, last time updated with raylib 4.0
*
* Example contributed by Giancamillo Alessandroni (@NotManyIdeasDev) and
* reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2021 Giancamillo Alessandroni (@NotManyIdeasDev) 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) 2021-2025 Giancamillo Alessandroni (@NotManyIdeasDev) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public static class SmoothPixelPerfect
public partial class SmoothPixelPerfect : IExample
{
public static int Main()
private const int screenWidth = 800;
private const int screenHeight = 450;
private const int virtualScreenWidth = 160;
private const int virtualScreenHeight = 90;
private const float virtualRatio = (float)screenWidth / (float)virtualScreenWidth;
public string Name => "Core / Smooth Pixelperfect";
public string Title => "raylib [core] example - smooth pixelperfect";
private Camera2D worldSpaceCamera; // Game world camera
private Camera2D screenSpaceCamera; // Smoothing camera
private RenderTexture2D target;
private Rectangle rec01;
private Rectangle rec02;
private Rectangle rec03;
private Rectangle sourceRec;
private Rectangle destRec;
private Vector2 origin;
private float rotation;
private float cameraX;
private float cameraY;
private bool smoothOn;
private bool overscan;
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
const int virtualScreenWidth = 160;
const int virtualScreenHeight = 90;
const float virtualRatio = (float)screenWidth / (float)virtualScreenWidth;
InitWindow(screenWidth, screenHeight, "raylib [core] example - smooth pixel-perfect camera");
// Game world camera
Camera2D worldSpaceCamera = new();
worldSpaceCamera = new(); // Game world camera
worldSpaceCamera.Zoom = 1.0f;
// Smoothing camera
Camera2D screenSpaceCamera = new();
screenSpaceCamera = new(); // Smoothing camera
screenSpaceCamera.Zoom = 1.0f;
// This is where we'll draw all our objects.
RenderTexture2D target = LoadRenderTexture(virtualScreenWidth, virtualScreenHeight);
// Load render texture to draw all our objects
target = LoadRenderTexture(virtualScreenWidth, virtualScreenHeight);
Rectangle rec01 = new(70.0f, 35.0f, 20.0f, 20.0f);
Rectangle rec02 = new(90.0f, 55.0f, 30.0f, 10.0f);
Rectangle rec03 = new(80.0f, 65.0f, 15.0f, 25.0f);
rec01 = new(70.0f, 35.0f, 20.0f, 20.0f);
rec02 = new(90.0f, 55.0f, 30.0f, 10.0f);
rec03 = new(80.0f, 65.0f, 15.0f, 25.0f);
// The target's height is flipped (in the source Rectangle), due to OpenGL reasons
Rectangle sourceRec = new(
sourceRec = new(
0.0f,
0.0f,
(float)target.Texture.Width,
-(float)target.Texture.Height
);
Rectangle destRec = new(
-virtualRatio,
-virtualRatio,
screenWidth + (virtualRatio * 2),
screenHeight + (virtualRatio * 2)
destRec = new(
(screenWidth - screenWidth / 1.25f) / 2.0f,
(screenHeight - screenHeight / 1.25f) / 2.0f,
screenWidth / 1.25f,
screenHeight / 1.25f
);
Vector2 origin = new(0.0f, 0.0f);
origin = new(0.0f, 0.0f);
float rotation = 0.0f;
rotation = 0.0f;
float cameraX = 0.0f;
float cameraY = 0.0f;
cameraX = 0.0f;
cameraY = 0.0f;
smoothOn = true;
overscan = false;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
rotation += 60.0f * GetFrameTime(); // Rotate the rectangles, 60 degrees per second
// Make the camera move to demonstrate the effect
cameraX = (MathF.Sin((float)GetTime()) * 50.0f) - 10.0f;
cameraY = MathF.Cos((float)GetTime()) * 30.0f;
// Set the camera's target to the values computed above
screenSpaceCamera.Target = new Vector2(cameraX, cameraY);
// Round worldSpace coordinates, keep decimals into screenSpace coordinates
worldSpaceCamera.Target.X = MathF.Truncate(screenSpaceCamera.Target.X);
screenSpaceCamera.Target.X -= worldSpaceCamera.Target.X;
screenSpaceCamera.Target.X *= virtualRatio;
worldSpaceCamera.Target.Y = MathF.Truncate(screenSpaceCamera.Target.Y);
screenSpaceCamera.Target.Y -= worldSpaceCamera.Target.Y;
screenSpaceCamera.Target.Y *= virtualRatio;
if (IsKeyPressed(KeyboardKey.S))
{
smoothOn = !smoothOn;
}
if (IsKeyPressed(KeyboardKey.O))
{
overscan = !overscan;
}
if (overscan)
{
destRec = new Rectangle(
-virtualRatio,
-virtualRatio,
screenWidth + (virtualRatio * 2),
screenHeight + (virtualRatio * 2)
);
}
else
{
destRec = new Rectangle(
(screenWidth - screenWidth / 1.25f) / 2.0f,
(screenHeight - screenHeight / 1.25f) / 2.0f,
screenWidth / 1.25f,
screenHeight / 1.25f
);
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginTextureMode(target);
ClearBackground(Color.RayWhite);
BeginMode2D(worldSpaceCamera);
DrawRectanglePro(rec01, origin, rotation, Color.Black);
DrawRectanglePro(rec02, origin, -rotation, Color.Red);
DrawRectanglePro(rec03, origin, rotation + 45.0f, Color.Blue);
EndMode2D();
EndTextureMode();
BeginDrawing();
ClearBackground(Color.LightGray);
if (smoothOn)
{
BeginMode2D(screenSpaceCamera);
DrawTexturePro(target.Texture, sourceRec, destRec, origin, 0.0f, Color.White);
EndMode2D();
}
else
{
DrawTexturePro(target.Texture, sourceRec, destRec, origin, 0.0f, Color.White);
}
DrawText($"Screen resolution: {screenWidth}x{screenHeight}", 10, 10, 20, Color.DarkBlue);
DrawText($"World resolution: {virtualScreenWidth}x{virtualScreenHeight}", 10, 40, 20, Color.DarkGreen);
DrawText($"Smooth: {(smoothOn ? "ON" : "OFF")}", 10, screenHeight - 60, 20, Color.Red);
DrawText($"Overscan: {(overscan ? "ON" : "OFF")}", 10, screenHeight - 30, 20, Color.Red);
DrawFPS(GetScreenWidth() - 95, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadRenderTexture(target); // Unload render texture
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - smooth pixelperfect");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new SmoothPixelPerfect();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
rotation += 60.0f * GetFrameTime(); // Rotate the rectangles, 60 degrees per second
// Make the camera move to demonstrate the effect
cameraX = (MathF.Sin((float)GetTime()) * 50.0f) - 10.0f;
cameraY = MathF.Cos((float)GetTime()) * 30.0f;
// Set the camera's target to the values computed above
screenSpaceCamera.Target = new Vector2(cameraX, cameraY);
// Round worldSpace coordinates, keep decimals into screenSpace coordinates
worldSpaceCamera.Target.X = (int)screenSpaceCamera.Target.X;
screenSpaceCamera.Target.X -= worldSpaceCamera.Target.X;
screenSpaceCamera.Target.X *= virtualRatio;
worldSpaceCamera.Target.Y = (int)screenSpaceCamera.Target.Y;
screenSpaceCamera.Target.Y -= worldSpaceCamera.Target.Y;
screenSpaceCamera.Target.Y *= virtualRatio;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginTextureMode(target);
ClearBackground(Color.RayWhite);
BeginMode2D(worldSpaceCamera);
DrawRectanglePro(rec01, origin, rotation, Color.Black);
DrawRectanglePro(rec02, origin, -rotation, Color.Red);
DrawRectanglePro(rec03, origin, rotation + 45.0f, Color.Blue);
EndMode2D();
EndTextureMode();
BeginDrawing();
ClearBackground(Color.Red);
BeginMode2D(screenSpaceCamera);
DrawTexturePro(target.Texture, sourceRec, destRec, origin, 0.0f, Color.White);
EndMode2D();
DrawText($"Screen resolution: {screenWidth}x{screenHeight}", 10, 10, 20, Color.DarkBlue);
DrawText($"World resolution: {virtualScreenWidth}x{virtualScreenHeight}", 10, 40, 20, Color.DarkGreen);
DrawFPS(GetScreenWidth() - 95, 10);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadRenderTexture(target);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -1,40 +1,50 @@
/*******************************************************************************************
*
* raylib [core] example - split screen
* raylib [core] example - 3d camera split screen
*
* This example has been created using raylib 3.7 (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 3.7, last time updated with raylib 4.0
*
* Example contributed by Jeffery Myers (@JeffM2501) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2021 Jeffery Myers (@JeffM2501)
* 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) 2021-2025 Jeffery Myers (@JeffM2501)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public unsafe class SplitScreen
public partial class SplitScreen : IExample
{
static Texture2D TextureGrid;
static Camera3D CameraPlayer1;
static Camera3D CameraPlayer2;
private const int screenWidth = 800;
private const int screenHeight = 450;
private Camera3D CameraPlayer1;
private Camera3D CameraPlayer2;
private RenderTexture2D screenPlayer1;
private RenderTexture2D screenPlayer2;
private Rectangle splitScreenRect;
public string Name => "Core / Split Screen";
public string Title => "raylib [core] example - 3d camera split screen";
// Scene drawing
static void DrawScene()
private void DrawScene()
{
int count = 5;
var count = 5;
float spacing = 4;
// Grid of cube trees on a plane to make a "world"
// Simple world plane
DrawPlane(new Vector3(0, 0, 0), new Vector2(50, 50), Color.Beige);
// Draw scene: grid of cube trees on a plane to make a "world"
DrawPlane(new Vector3(0, 0, 0), new Vector2(50, 50), Color.Beige); // Simple world plane
for (float x = -count * spacing; x <= count * spacing; x += spacing)
for (var x = -count * spacing; x <= count * spacing; x += spacing)
{
for (float z = -count * spacing; z <= count * spacing; z += spacing)
for (var z = -count * spacing; z <= count * spacing; z += spacing)
{
DrawCube(new Vector3(x, 1.5f, z), 1, 1, 1, Color.Lime);
DrawCube(new Vector3(x, 0.5f, z), 0.25f, 1, 0.25f, Color.Brown);
@ -46,22 +56,8 @@ public unsafe class SplitScreen
DrawCube(CameraPlayer2.Position, 1, 1, 1, Color.Blue);
}
public static int Main()
public void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - split screen");
// Generate a simple texture to use for trees
Image img = GenImageChecked(256, 256, 32, 32, Color.DarkGray, Color.White);
TextureGrid = LoadTextureFromImage(img);
UnloadImage(img);
SetTextureFilter(TextureGrid, TextureFilter.Anisotropic16X);
SetTextureWrap(TextureGrid, TextureWrap.Clamp);
// Setup player 1 camera and screen
CameraPlayer1.FovY = 45.0f;
CameraPlayer1.Up.Y = 1.0f;
@ -69,7 +65,7 @@ public unsafe class SplitScreen
CameraPlayer1.Position.Z = -3.0f;
CameraPlayer1.Position.Y = 1.0f;
RenderTexture2D screenPlayer1 = LoadRenderTexture(screenWidth / 2, screenHeight);
screenPlayer1 = LoadRenderTexture(screenWidth / 2, screenHeight);
// Setup player two camera and screen
CameraPlayer2.FovY = 45.0f;
@ -78,97 +74,119 @@ public unsafe class SplitScreen
CameraPlayer2.Position.X = -3.0f;
CameraPlayer2.Position.Y = 3.0f;
RenderTexture2D screenPlayer2 = LoadRenderTexture(screenWidth / 2, screenHeight);
screenPlayer2 = LoadRenderTexture(screenWidth / 2, screenHeight);
// Build a flipped rectangle the size of the split view to use for drawing later
Rectangle splitScreenRect = new(
splitScreenRect = new(
0.0f,
0.0f,
(float)screenPlayer1.Texture.Width,
(float)-screenPlayer1.Texture.Height
);
}
SetTargetFPS(60);
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// If anyone moves this frame, how far will they move based on the time since the last frame
// this moves things at 10 world units per second, regardless of the actual FPS
var offsetThisFrame = 10.0f * GetFrameTime();
// Move Player1 forward and backwards (no turning)
if (IsKeyDown(KeyboardKey.W))
{
CameraPlayer1.Position.Z += offsetThisFrame;
CameraPlayer1.Target.Z += offsetThisFrame;
}
else if (IsKeyDown(KeyboardKey.S))
{
CameraPlayer1.Position.Z -= offsetThisFrame;
CameraPlayer1.Target.Z -= offsetThisFrame;
}
// Move Player2 forward and backwards (no turning)
if (IsKeyDown(KeyboardKey.Up))
{
CameraPlayer2.Position.X += offsetThisFrame;
CameraPlayer2.Target.X += offsetThisFrame;
}
else if (IsKeyDown(KeyboardKey.Down))
{
CameraPlayer2.Position.X -= offsetThisFrame;
CameraPlayer2.Target.X -= offsetThisFrame;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
// Draw Player1 view to the render texture
BeginTextureMode(screenPlayer1);
ClearBackground(Color.SkyBlue);
BeginMode3D(CameraPlayer1);
DrawScene();
EndMode3D();
DrawRectangle(0, 0, GetScreenWidth() / 2, 40, Fade(Color.RayWhite, 0.8f));
DrawText("PLAYER1: W/S to move", 10, 10, 20, Color.Maroon);
EndTextureMode();
// Draw Player2 view to the render texture
BeginTextureMode(screenPlayer2);
ClearBackground(Color.SkyBlue);
BeginMode3D(CameraPlayer2);
DrawScene();
EndMode3D();
DrawRectangle(0, 0, GetScreenWidth() / 2, 40, Fade(Color.RayWhite, 0.8f));
DrawText("PLAYER2: UP/DOWN to move", 10, 10, 20, Color.DarkBlue);
EndTextureMode();
// Draw both views render textures to the screen side by side
BeginDrawing();
ClearBackground(Color.Black);
DrawTextureRec(screenPlayer1.Texture, splitScreenRect, new Vector2(0, 0), Color.White);
DrawTextureRec(screenPlayer2.Texture, splitScreenRect, new Vector2(screenWidth / 2.0f, 0), Color.White);
DrawRectangle(GetScreenWidth() / 2 - 2, 0, 4, GetScreenHeight(), Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadRenderTexture(screenPlayer1); // Unload render texture
UnloadRenderTexture(screenPlayer2); // Unload render texture
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera split screen");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new SplitScreen();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// If anyone moves this frame, how far will they move based on the time since the last frame
// this moves thigns at 10 world units per second, regardless of the actual FPS
float offsetThisFrame = 10.0f * GetFrameTime();
// Move Player1 forward and backwards (no turning)
if (IsKeyDown(KeyboardKey.W))
{
CameraPlayer1.Position.Z += offsetThisFrame;
CameraPlayer1.Target.Z += offsetThisFrame;
}
else if (IsKeyDown(KeyboardKey.S))
{
CameraPlayer1.Position.Z -= offsetThisFrame;
CameraPlayer1.Target.Z -= offsetThisFrame;
}
// Move Player2 forward and backwards (no turning)
if (IsKeyDown(KeyboardKey.Up))
{
CameraPlayer2.Position.X += offsetThisFrame;
CameraPlayer2.Target.X += offsetThisFrame;
}
else if (IsKeyDown(KeyboardKey.Down))
{
CameraPlayer2.Position.X -= offsetThisFrame;
CameraPlayer2.Target.X -= offsetThisFrame;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
// Draw Player1 view to the render texture
BeginTextureMode(screenPlayer1);
ClearBackground(Color.SkyBlue);
BeginMode3D(CameraPlayer1);
DrawScene();
EndMode3D();
DrawText("PLAYER 1 W/S to move", 10, 10, 20, Color.Red);
EndTextureMode();
// Draw Player2 view to the render texture
BeginTextureMode(screenPlayer2);
ClearBackground(Color.SkyBlue);
BeginMode3D(CameraPlayer2);
DrawScene();
EndMode3D();
DrawText("PLAYER 2 UP/DOWN to move", 10, 10, 20, Color.Blue);
EndTextureMode();
// Draw both views render textures to the screen side by side
BeginDrawing();
ClearBackground(Color.Black);
DrawTextureRec(screenPlayer1.Texture, splitScreenRect, new Vector2(0, 0), Color.White);
DrawTextureRec(screenPlayer2.Texture, splitScreenRect, new Vector2(screenWidth / 2.0f, 0), Color.White);
EndDrawing();
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadRenderTexture(screenPlayer1);
UnloadRenderTexture(screenPlayer2);
UnloadTexture(TextureGrid);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,227 @@
/*******************************************************************************************
*
* raylib [core] example - 2d camera split screen
*
* Example complexity rating: [] 4/4
*
* Addapted from the core_3d_camera_split_screen example:
* https://github.com/raysan5/raylib/blob/master/examples/core/core_3d_camera_split_screen.c
*
* Example originally created with raylib 4.5, last time updated with raylib 4.5
*
* Example contributed by Gabriel dos Santos Sanches (@gabrielssanches) 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) 2023-2025 Gabriel dos Santos Sanches (@gabrielssanches)
*
********************************************************************************************/
namespace Examples.Core;
public partial class SplitScreen2D : IExample
{
private const int PLAYER_SIZE = 40;
private const int screenWidth = 800;
private const int screenHeight = 440;
public string Name => "Core / 2D Camera Split Screen";
public string Title => "raylib [core] example - 2d camera split screen";
public int Width => screenWidth;
public int Height => screenHeight;
private Rectangle player1;
private Rectangle player2;
private Camera2D camera1;
private Camera2D camera2;
private RenderTexture2D screenCamera1;
private RenderTexture2D screenCamera2;
private Rectangle splitScreenRect;
public void Init()
{
player1 = new Rectangle(200, 200, PLAYER_SIZE, PLAYER_SIZE);
player2 = new Rectangle(250, 200, PLAYER_SIZE, PLAYER_SIZE);
camera1 = new Camera2D();
camera1.Target = new Vector2(player1.X, player1.Y);
camera1.Offset = new Vector2(200.0f, 200.0f);
camera1.Rotation = 0.0f;
camera1.Zoom = 1.0f;
camera2 = new Camera2D();
camera2.Target = new Vector2(player2.X, player2.Y);
camera2.Offset = new Vector2(200.0f, 200.0f);
camera2.Rotation = 0.0f;
camera2.Zoom = 1.0f;
screenCamera1 = LoadRenderTexture(screenWidth / 2, screenHeight);
screenCamera2 = LoadRenderTexture(screenWidth / 2, screenHeight);
// Build a flipped rectangle the size of the split view to use for drawing later
splitScreenRect = new Rectangle(0.0f, 0.0f, (float)screenCamera1.Texture.Width, (float)-screenCamera1.Texture.Height);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyDown(KeyboardKey.S))
{
player1.Y += 3.0f;
}
else if (IsKeyDown(KeyboardKey.W))
{
player1.Y -= 3.0f;
}
if (IsKeyDown(KeyboardKey.D))
{
player1.X += 3.0f;
}
else if (IsKeyDown(KeyboardKey.A))
{
player1.X -= 3.0f;
}
if (IsKeyDown(KeyboardKey.Up))
{
player2.Y -= 3.0f;
}
else if (IsKeyDown(KeyboardKey.Down))
{
player2.Y += 3.0f;
}
if (IsKeyDown(KeyboardKey.Right))
{
player2.X += 3.0f;
}
else if (IsKeyDown(KeyboardKey.Left))
{
player2.X -= 3.0f;
}
camera1.Target = new Vector2(player1.X, player1.Y);
camera2.Target = new Vector2(player2.X, player2.Y);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginTextureMode(screenCamera1);
ClearBackground(Color.RayWhite);
BeginMode2D(camera1);
// Draw full scene with first camera
for (int i = 0; i < screenWidth / PLAYER_SIZE + 1; i++)
{
DrawLineV(new Vector2((float)PLAYER_SIZE * i, 0), new Vector2((float)PLAYER_SIZE * i, (float)screenHeight), Color.LightGray);
}
for (int i = 0; i < screenHeight / PLAYER_SIZE + 1; i++)
{
DrawLineV(new Vector2(0, (float)PLAYER_SIZE * i), new Vector2((float)screenWidth, (float)PLAYER_SIZE * i), Color.LightGray);
}
for (int i = 0; i < screenWidth / PLAYER_SIZE; i++)
{
for (int j = 0; j < screenHeight / PLAYER_SIZE; j++)
{
DrawText($"[{i},{j}]", 10 + PLAYER_SIZE * i, 15 + PLAYER_SIZE * j, 10, Color.LightGray);
}
}
DrawRectangleRec(player1, Color.Red);
DrawRectangleRec(player2, Color.Blue);
EndMode2D();
DrawRectangle(0, 0, GetScreenWidth() / 2, 30, Fade(Color.RayWhite, 0.6f));
DrawText("PLAYER1: W/S/A/D to move", 10, 10, 10, Color.Maroon);
EndTextureMode();
BeginTextureMode(screenCamera2);
ClearBackground(Color.RayWhite);
BeginMode2D(camera2);
// Draw full scene with second camera
for (int i = 0; i < screenWidth / PLAYER_SIZE + 1; i++)
{
DrawLineV(new Vector2((float)PLAYER_SIZE * i, 0), new Vector2((float)PLAYER_SIZE * i, (float)screenHeight), Color.LightGray);
}
for (int i = 0; i < screenHeight / PLAYER_SIZE + 1; i++)
{
DrawLineV(new Vector2(0, (float)PLAYER_SIZE * i), new Vector2((float)screenWidth, (float)PLAYER_SIZE * i), Color.LightGray);
}
for (int i = 0; i < screenWidth / PLAYER_SIZE; i++)
{
for (int j = 0; j < screenHeight / PLAYER_SIZE; j++)
{
DrawText($"[{i},{j}]", 10 + PLAYER_SIZE * i, 15 + PLAYER_SIZE * j, 10, Color.LightGray);
}
}
DrawRectangleRec(player1, Color.Red);
DrawRectangleRec(player2, Color.Blue);
EndMode2D();
DrawRectangle(0, 0, GetScreenWidth() / 2, 30, Fade(Color.RayWhite, 0.6f));
DrawText("PLAYER2: UP/DOWN/LEFT/RIGHT to move", 10, 10, 10, Color.DarkBlue);
EndTextureMode();
// Draw both views render textures to the screen side by side
BeginDrawing();
ClearBackground(Color.Black);
DrawTextureRec(screenCamera1.Texture, splitScreenRect, new Vector2(0, 0), Color.White);
DrawTextureRec(screenCamera2.Texture, splitScreenRect, new Vector2(screenWidth / 2.0f, 0), Color.White);
DrawRectangle(GetScreenWidth() / 2 - 2, 0, 4, GetScreenHeight(), Color.LightGray);
EndDrawing();
}
public void Unload()
{
UnloadRenderTexture(screenCamera1); // Unload render texture
UnloadRenderTexture(screenCamera2); // Unload render texture
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera split screen");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new SplitScreen2D();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,91 +1,118 @@
/*******************************************************************************************
*
* raylib [core] example - Storage save/load values
* raylib [core] example - storage values
*
* 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) 2015 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.4, 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) 2015-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class StorageValues
public partial class StorageValues : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private const string storageDataFile = "storage.data";
// NOTE: Storage positions must start with 0, directly related to file memory layout
enum StorageData
private enum StorageData
{
Score,
HiScore
}
public string Name => "Core / Storage Values";
public string Title => "raylib [core] example - storage values";
private int score = 0;
private int hiscore = 0;
private int framesCounter = 0;
public void Init()
{
score = 0;
hiscore = 0;
framesCounter = 0;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.R))
{
score = GetRandomValue(1000, 2000);
hiscore = GetRandomValue(2000, 4000);
}
if (IsKeyPressed(KeyboardKey.Enter))
{
SaveStorageValue(storageDataFile, (int)StorageData.Score, score);
SaveStorageValue(storageDataFile, (int)StorageData.HiScore, hiscore);
}
else if (IsKeyPressed(KeyboardKey.Space))
{
// NOTE: If requested position could not be found, value 0 is returned
score = LoadStorageValue(storageDataFile, (int)StorageData.Score);
hiscore = LoadStorageValue(storageDataFile, (int)StorageData.HiScore);
}
framesCounter++;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText($"SCORE: {score}", 280, 130, 40, Color.Maroon);
DrawText($"HI-SCORE: {hiscore}", 210, 200, 50, Color.Black);
DrawText($"frames: {framesCounter}", 10, 10, 20, Color.Lime);
DrawText("Press R to generate random numbers", 220, 40, 20, Color.LightGray);
DrawText("Press ENTER to SAVE values", 250, 310, 20, Color.LightGray);
DrawText("Press SPACE to LOAD values", 252, 350, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
const string storageDataFile = "storage.data";
InitWindow(screenWidth, screenHeight, "raylib [core] example - storage values");
InitWindow(screenWidth, screenHeight, "raylib [core] example - storage save/load values");
int score = 0;
int hiscore = 0;
int framesCounter = 0;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new StorageValues();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
if (IsKeyPressed(KeyboardKey.R))
{
score = GetRandomValue(1000, 2000);
hiscore = GetRandomValue(2000, 4000);
}
if (IsKeyPressed(KeyboardKey.Enter))
{
SaveStorageValue(storageDataFile, (int)StorageData.Score, score);
SaveStorageValue(storageDataFile, (int)StorageData.HiScore, hiscore);
}
else if (IsKeyPressed(KeyboardKey.Space))
{
// NOTE: If requested position could not be found, value 0 is returned
score = LoadStorageValue(storageDataFile, (int)StorageData.Score);
hiscore = LoadStorageValue(storageDataFile, (int)StorageData.HiScore);
}
framesCounter++;
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText($"SCORE: {score}", 280, 130, 40, Color.Maroon);
DrawText($"HI-SCORE: {hiscore}", 210, 200, 50, Color.Black);
DrawText($"frames: {framesCounter}", 10, 10, 20, Color.Lime);
DrawText("Press R to generate random numbers", 220, 40, 20, Color.LightGray);
DrawText("Press ENTER to SAVE values", 250, 310, 20, Color.LightGray);
DrawText("Press SPACE to LOAD values", 252, 350, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
@ -97,11 +124,11 @@ public class StorageValues
{
using var fileNameBuffer = fileName.ToUtf8Buffer();
bool success = false;
int dataSize = 0;
int newDataSize = 0;
var success = false;
var dataSize = 0;
var newDataSize = 0;
byte* fileData = LoadFileData(fileNameBuffer.AsPointer(), &dataSize);
var fileData = LoadFileData(fileNameBuffer.AsPointer(), &dataSize);
byte* newFileData = null;
if (fileData != null)
@ -115,13 +142,13 @@ public class StorageValues
if (newFileData != null)
{
// RL_REALLOC succeded
int* dataPtr = (int*)newFileData;
var dataPtr = (int*)newFileData;
dataPtr[position] = value;
}
else
{
// RL_REALLOC failed
int positionInBytes = position * sizeof(int);
var positionInBytes = position * sizeof(int);
TraceLog(
TraceLogLevel.Warning,
@$"FILEIO: [{fileName}] Failed to realloc data ({dataSize}),
@ -140,7 +167,7 @@ public class StorageValues
newDataSize = dataSize;
// Replace value on selected position
int* dataPtr = (int*)newFileData;
var dataPtr = (int*)newFileData;
dataPtr[position] = value;
}
@ -155,7 +182,7 @@ public class StorageValues
dataSize = (position + 1) * sizeof(int);
fileData = (byte*)MemAlloc((uint)dataSize);
int* dataPtr = (int*)fileData;
var dataPtr = (int*)fileData;
dataPtr[position] = value;
success = SaveFileData(fileNameBuffer.AsPointer(), fileData, dataSize);
@ -173,9 +200,9 @@ public class StorageValues
{
using var fileNameBuffer = fileName.ToUtf8Buffer();
int value = 0;
int dataSize = 0;
byte* fileData = LoadFileData(fileNameBuffer.AsPointer(), &dataSize);
var value = 0;
var dataSize = 0;
var fileData = LoadFileData(fileNameBuffer.AsPointer(), &dataSize);
if (fileData != null)
{
@ -188,7 +215,7 @@ public class StorageValues
}
else
{
int* dataPtr = (int*)fileData;
var dataPtr = (int*)fileData;
value = dataPtr[position];
}

View file

@ -0,0 +1,212 @@
/*******************************************************************************************
*
* raylib [core] example - text file loading
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.6
*
* Example contributed by Aanjishnu Bhattacharyya (@NimComPoo-04) 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) 0 Aanjishnu Bhattacharyya (@NimComPoo-04)
*
********************************************************************************************/
using static Raylib_cs.Raymath;
namespace Examples.Core;
// NOTE: The upstream C code mutates the raw char buffers returned by LoadTextLines() in place,
// temporarily null-terminating to reuse MeasureText for word wrapping. This C# port keeps the
// same algorithm but works on managed char arrays: LoadFileText + split on '\n' reproduces
// raylib's LoadTextLines('\n') behaviour, and '\n' characters are inserted where lines wrap.
public partial class TextFileLoading : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Text File Loading";
public string Title => "raylib [core] example - text file loading";
private Camera2D cam;
private string fileName;
private string[] lines;
private int lineCount;
private int fontSize;
private int textTop;
private int wrapWidth;
private int textHeight;
private Rectangle scrollBar;
public void Init()
{
// Setting up the camera
cam = new Camera2D();
cam.Offset = new Vector2(0, 0);
cam.Target = new Vector2(0, 0);
cam.Rotation = 0;
cam.Zoom = 1;
// Loading text file from resources/text_file.txt
fileName = "resources/text_file.txt";
string text = LoadFileText(fileName);
// Loading all the text lines (raylib's LoadTextLines splits on '\n')
lines = text.Split('\n');
lineCount = lines.Length;
// Stylistic choises
fontSize = 20;
textTop = 25 + fontSize; // Top of the screen from where the text is rendered
wrapWidth = screenWidth - 20;
// Wrap the lines as needed
for (int i = 0; i < lineCount; i++)
{
char[] chars = lines[i].ToCharArray();
int len = chars.Length;
int j = 0;
int lastSpace = 0; // Keeping track of last valid space to insert '\n'
int lastWrapStart = 0; // Keeping track of the start of this wrapped line.
while (j <= len)
{
char cur = (j < len) ? chars[j] : '\0';
if (cur == ' ' || cur == '\0')
{
// Making a C style string by "cutting" at the required location so that we can use MeasureText
string sub = new string(chars, lastWrapStart, j - lastWrapStart);
// Checking if the text has crossed the wrapWidth, then going back and inserting a newline
if (MeasureText(sub, fontSize) > wrapWidth)
{
chars[lastSpace] = '\n';
// Since we added a newline the place of wrap changed so we update our lastWrapStart
lastWrapStart = lastSpace + 1;
}
lastSpace = j; // Since we encountered a new space we update our last encountered space location
}
j++;
}
lines[i] = new string(chars);
}
// Calculating the total height so that we can show a scrollbar
textHeight = 0;
for (int i = 0; i < lineCount; i++)
{
Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2);
textHeight += (int)size.Y + 10;
}
// A simple scrollbar on the side to show how far we have read into the file
scrollBar = new Rectangle(
(float)screenWidth - 5,
0,
5,
screenHeight * 100.0f / (textHeight - screenHeight)); // Scrollbar height is just a percentage
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
float scroll = GetMouseWheelMove();
cam.Target.Y -= scroll * fontSize * 1.5f; // Choosing an arbitrary speed for scroll
if (cam.Target.Y < 0)
{
cam.Target.Y = 0; // Snapping to 0 if we go too far back
}
// Ensuring that the camera does not scroll past all text
if (cam.Target.Y > textHeight - screenHeight + textTop)
{
cam.Target.Y = (float)textHeight - screenHeight + textTop;
}
// Computing the position of the scrollBar depending on the percentage of text covered
scrollBar.Y = Lerp((float)textTop, (float)screenHeight - scrollBar.Height, (float)(cam.Target.Y - textTop) / (textHeight - screenHeight));
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode2D(cam);
// Going through all the read lines
for (int i = 0, t = textTop; i < lineCount; i++)
{
// Each time we go through and calculate the height of the text to move the cursor appropriately
Vector2 size;
if (lines[i] != "")
{
size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2);
}
else
{
// Fix for empty line in the text file
size = MeasureTextEx(GetFontDefault(), " ", (float)fontSize, 2);
}
DrawText(lines[i], 10, t, fontSize, Color.Red);
// Inserting extra space for real newlines,
// wrapped lines are rendered closer together
t += (int)size.Y + 10;
}
EndMode2D();
// Header displaying which file is being read currently
DrawRectangle(0, 0, screenWidth, textTop - 10, Color.Beige);
DrawText($"File: {fileName}", 10, 10, fontSize, Color.Maroon);
DrawRectangleRec(scrollBar, Color.Maroon);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - text file loading");
var game = new TextFileLoading();
game.Init();
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// 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;
}
}

389
Examples/Core/UndoRedo.cs Normal file
View file

@ -0,0 +1,389 @@
/*******************************************************************************************
*
* raylib [core] example - undo redo
*
* Example complexity rating: [] 3/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.6
*
* Example contributed 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 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Core;
public partial class UndoRedo : IExample
{
private const int MAX_UNDO_STATES = 26; // Maximum undo states supported for the ring buffer
private const int GRID_CELL_SIZE = 24;
private const int MAX_GRID_CELLS_X = 30;
private const int MAX_GRID_CELLS_Y = 13;
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Undo Redo";
public string Title => "raylib [core] example - undo redo";
// Point struct, like Vector2 but using int
private struct Point
{
public int X;
public int Y;
}
// Player state struct
// NOTE: Contains all player data that needs to be affected by undo/redo
private struct PlayerState
{
public Point Cell;
public Color Color;
}
// Undo/redo system variables
private int currentUndoIndex;
private int firstUndoIndex;
private int lastUndoIndex;
private int undoFrameCounter;
private Vector2 undoInfoPos;
private PlayerState player;
private PlayerState[] states;
// Grid variables
private Vector2 gridPosition;
// Compare two player states (replaces memcmp)
private static bool SameState(in PlayerState a, in PlayerState b)
{
return (a.Cell.X == b.Cell.X) && (a.Cell.Y == b.Cell.Y) &&
(a.Color.R == b.Color.R) && (a.Color.G == b.Color.G) &&
(a.Color.B == b.Color.B) && (a.Color.A == b.Color.A);
}
public void Init()
{
currentUndoIndex = 0;
firstUndoIndex = 0;
lastUndoIndex = 0;
undoFrameCounter = 0;
undoInfoPos = new Vector2(110, 400);
// Init current player state and undo/redo recorded states array
player = new PlayerState();
player.Cell = new Point { X = 10, Y = 10 };
player.Color = Color.Red;
// Init undo buffer to store MAX_UNDO_STATES states
states = new PlayerState[MAX_UNDO_STATES];
// Init all undo states to current state
for (int i = 0; i < MAX_UNDO_STATES; i++)
{
states[i] = player;
}
// Grid variables
gridPosition = new Vector2(40, 60);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Player movement logic
if (IsKeyPressed(KeyboardKey.Right))
{
player.Cell.X++;
}
else if (IsKeyPressed(KeyboardKey.Left))
{
player.Cell.X--;
}
else if (IsKeyPressed(KeyboardKey.Up))
{
player.Cell.Y--;
}
else if (IsKeyPressed(KeyboardKey.Down))
{
player.Cell.Y++;
}
// Make sure player does not go out of bounds
if (player.Cell.X < 0)
{
player.Cell.X = 0;
}
else if (player.Cell.X >= MAX_GRID_CELLS_X)
{
player.Cell.X = MAX_GRID_CELLS_X - 1;
}
if (player.Cell.Y < 0)
{
player.Cell.Y = 0;
}
else if (player.Cell.Y >= MAX_GRID_CELLS_Y)
{
player.Cell.Y = MAX_GRID_CELLS_Y - 1;
}
// Player color change logic
if (IsKeyPressed(KeyboardKey.Space))
{
player.Color.R = (byte)GetRandomValue(20, 255);
player.Color.G = (byte)GetRandomValue(20, 220);
player.Color.B = (byte)GetRandomValue(20, 240);
}
// Undo state change logic
undoFrameCounter++;
// Waiting a number of frames before checking if we should store a new state snapshot
if (undoFrameCounter >= 2) // Checking every 2 frames
{
if (!SameState(states[currentUndoIndex], player))
{
// Move cursor to next available position of the undo ring buffer to record state
currentUndoIndex++;
if (currentUndoIndex >= MAX_UNDO_STATES)
{
currentUndoIndex = 0;
}
if (currentUndoIndex == firstUndoIndex)
{
firstUndoIndex++;
}
if (firstUndoIndex >= MAX_UNDO_STATES)
{
firstUndoIndex = 0;
}
states[currentUndoIndex] = player;
lastUndoIndex = currentUndoIndex;
}
undoFrameCounter = 0;
}
// Recover previous state from buffer: CTRL+Z
if (IsKeyDown(KeyboardKey.LeftControl) && IsKeyPressed(KeyboardKey.Z))
{
if (currentUndoIndex != firstUndoIndex)
{
currentUndoIndex--;
if (currentUndoIndex < 0)
{
currentUndoIndex = MAX_UNDO_STATES - 1;
}
if (!SameState(states[currentUndoIndex], player))
{
player = states[currentUndoIndex];
}
}
}
// Recover next state from buffer: CTRL+Y
if (IsKeyDown(KeyboardKey.LeftControl) && IsKeyPressed(KeyboardKey.Y))
{
if (currentUndoIndex != lastUndoIndex)
{
int nextUndoIndex = currentUndoIndex + 1;
if (nextUndoIndex >= MAX_UNDO_STATES)
{
nextUndoIndex = 0;
}
if (nextUndoIndex != firstUndoIndex)
{
currentUndoIndex = nextUndoIndex;
if (!SameState(states[currentUndoIndex], player))
{
player = states[currentUndoIndex];
}
}
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
// Draw controls info
DrawText("[ARROWS] MOVE PLAYER - [SPACE] CHANGE PLAYER COLOR", 40, 20, 20, Color.DarkGray);
// Draw player visited cells recorded by undo
// NOTE: Remember we are using a ring buffer approach so,
// some cells info could start at the end of the array and end at the beginning
if (lastUndoIndex > firstUndoIndex)
{
for (int i = firstUndoIndex; i < currentUndoIndex; i++)
{
DrawRectangleRec(new Rectangle(gridPosition.X + states[i].Cell.X * GRID_CELL_SIZE, gridPosition.Y + states[i].Cell.Y * GRID_CELL_SIZE,
GRID_CELL_SIZE, GRID_CELL_SIZE), Color.LightGray);
}
}
else if (firstUndoIndex > lastUndoIndex)
{
if ((currentUndoIndex < MAX_UNDO_STATES) && (currentUndoIndex > lastUndoIndex))
{
for (int i = firstUndoIndex; i < currentUndoIndex; i++)
{
DrawRectangleRec(new Rectangle(gridPosition.X + states[i].Cell.X * GRID_CELL_SIZE, gridPosition.Y + states[i].Cell.Y * GRID_CELL_SIZE,
GRID_CELL_SIZE, GRID_CELL_SIZE), Color.LightGray);
}
}
else
{
for (int i = firstUndoIndex; i < MAX_UNDO_STATES; i++)
{
DrawRectangle((int)gridPosition.X + states[i].Cell.X * GRID_CELL_SIZE, (int)gridPosition.Y + states[i].Cell.Y * GRID_CELL_SIZE,
GRID_CELL_SIZE, GRID_CELL_SIZE, Color.LightGray);
}
for (int i = 0; i < currentUndoIndex; i++)
{
DrawRectangle((int)gridPosition.X + states[i].Cell.X * GRID_CELL_SIZE, (int)gridPosition.Y + states[i].Cell.Y * GRID_CELL_SIZE,
GRID_CELL_SIZE, GRID_CELL_SIZE, Color.LightGray);
}
}
}
// Draw game grid
for (int y = 0; y <= MAX_GRID_CELLS_Y; y++)
{
DrawLine((int)gridPosition.X, (int)gridPosition.Y + y * GRID_CELL_SIZE,
(int)gridPosition.X + MAX_GRID_CELLS_X * GRID_CELL_SIZE, (int)gridPosition.Y + y * GRID_CELL_SIZE, Color.Gray);
}
for (int x = 0; x <= MAX_GRID_CELLS_X; x++)
{
DrawLine((int)gridPosition.X + x * GRID_CELL_SIZE, (int)gridPosition.Y,
(int)gridPosition.X + x * GRID_CELL_SIZE, (int)gridPosition.Y + MAX_GRID_CELLS_Y * GRID_CELL_SIZE, Color.Gray);
}
// Draw player
DrawRectangle((int)gridPosition.X + player.Cell.X * GRID_CELL_SIZE, (int)gridPosition.Y + player.Cell.Y * GRID_CELL_SIZE,
GRID_CELL_SIZE + 1, GRID_CELL_SIZE + 1, player.Color);
// Draw undo system buffer info
DrawText("UNDO STATES:", (int)undoInfoPos.X - 85, (int)undoInfoPos.Y + 9, 10, Color.DarkGray);
DrawUndoBuffer(undoInfoPos, firstUndoIndex, lastUndoIndex, currentUndoIndex, 24);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
// Draw undo system visualization logic
// NOTE: Visualizing the ring buffer array, every square can store a player state
private static void DrawUndoBuffer(Vector2 position, int firstUndoIndex, int lastUndoIndex, int currentUndoIndex, int slotSize)
{
// Draw index marks
DrawRectangle((int)position.X + 8 + slotSize * currentUndoIndex, (int)position.Y - 10, 8, 8, Color.Red);
DrawRectangleLines((int)position.X + 2 + slotSize * firstUndoIndex, (int)position.Y + 27, 8, 8, Color.Black);
DrawRectangle((int)position.X + 14 + slotSize * lastUndoIndex, (int)position.Y + 27, 8, 8, Color.Black);
// Draw background gray slots
for (int i = 0; i < MAX_UNDO_STATES; i++)
{
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.LightGray);
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Gray);
}
// Draw occupied slots: firstUndoIndex --> lastUndoIndex
if (firstUndoIndex <= lastUndoIndex)
{
for (int i = firstUndoIndex; i < lastUndoIndex + 1; i++)
{
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.SkyBlue);
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Blue);
}
}
else if (lastUndoIndex < firstUndoIndex)
{
for (int i = firstUndoIndex; i < MAX_UNDO_STATES; i++)
{
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.SkyBlue);
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Blue);
}
for (int i = 0; i < lastUndoIndex + 1; i++)
{
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.SkyBlue);
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Blue);
}
}
// Draw occupied slots: firstUndoIndex --> currentUndoIndex
if (firstUndoIndex < currentUndoIndex)
{
for (int i = firstUndoIndex; i < currentUndoIndex; i++)
{
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Green);
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Lime);
}
}
else if (currentUndoIndex < firstUndoIndex)
{
for (int i = firstUndoIndex; i < MAX_UNDO_STATES; i++)
{
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Green);
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Lime);
}
for (int i = 0; i < currentUndoIndex; i++)
{
DrawRectangle((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Green);
DrawRectangleLines((int)position.X + slotSize * i, (int)position.Y, slotSize, slotSize, Color.Lime);
}
}
// Draw current selected UNDO slot
DrawRectangle((int)position.X + slotSize * currentUndoIndex, (int)position.Y, slotSize, slotSize, Color.Gold);
DrawRectangleLines((int)position.X + slotSize * currentUndoIndex, (int)position.Y, slotSize, slotSize, Color.Orange);
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - undo redo");
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
var game = new UndoRedo();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,380 @@
/*******************************************************************************************
*
* raylib [core] example - viewport scaling
*
* Example complexity rating: [] 2/4
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
* Example contributed by Agnis Aldiņš (@nezvers) 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 Agnis Aldiņš (@nezvers)
*
********************************************************************************************/
namespace Examples.Core;
public partial class ViewportScaling : IExample
{
private const int ResolutionCount = 4; // For iteration purposes and teaching example
private enum ViewportType
{
// Only upscale, useful for pixel art
KeepAspectInteger,
KeepHeightInteger,
KeepWidthInteger,
// Can also downscale
KeepAspect,
KeepHeight,
KeepWidth,
// For itteration purposes and as a teaching example
ViewportTypeCount,
}
// For displaying on GUI
private static readonly string[] ViewportTypeNames = new string[]
{
"KEEP_ASPECT_INTEGER",
"KEEP_HEIGHT_INTEGER",
"KEEP_WIDTH_INTEGER",
"KEEP_ASPECT",
"KEEP_HEIGHT",
"KEEP_WIDTH",
};
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Viewport Scaling";
public string Title => "raylib [core] example - viewport scaling";
public ConfigFlags ConfigFlags => ConfigFlags.ResizableWindow;
// Mutable window size (tracked from GetScreenWidth/GetScreenHeight)
private int curScreenWidth;
private int curScreenHeight;
private Vector2[] resolutionList;
private int resolutionIndex;
private int gameWidth;
private int gameHeight;
private RenderTexture2D target;
private Rectangle sourceRect;
private Rectangle destRect;
private ViewportType viewportType;
// Button rectangles
private Rectangle decreaseResolutionButton;
private Rectangle increaseResolutionButton;
private Rectangle decreaseTypeButton;
private Rectangle increaseTypeButton;
public void Init()
{
curScreenWidth = screenWidth;
curScreenHeight = screenHeight;
// Preset resolutions that could be created by subdividing screen resolution
resolutionList = new Vector2[]
{
new Vector2(64, 64),
new Vector2(256, 240),
new Vector2(320, 180),
// 4K doesn't work with integer scaling but included for example purposes with non-integer scaling
new Vector2(3840, 2160),
};
resolutionIndex = 0;
gameWidth = 64;
gameHeight = 64;
target = default;
sourceRect = default;
destRect = default;
viewportType = ViewportType.KeepAspectInteger;
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
// Button rectangles
decreaseResolutionButton = new Rectangle(200, 30, 10, 10);
increaseResolutionButton = new Rectangle(215, 30, 10, 10);
decreaseTypeButton = new Rectangle(200, 45, 10, 10);
increaseTypeButton = new Rectangle(215, 45, 10, 10);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
if (IsWindowResized())
{
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
}
Vector2 mousePosition = GetMousePosition();
bool mousePressed = IsMouseButtonPressed(MouseButton.Left);
// Check buttons and rescale
if (CheckCollisionPointRec(mousePosition, decreaseResolutionButton) && mousePressed)
{
resolutionIndex = (resolutionIndex + ResolutionCount - 1) % ResolutionCount;
gameWidth = (int)resolutionList[resolutionIndex].X;
gameHeight = (int)resolutionList[resolutionIndex].Y;
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
}
if (CheckCollisionPointRec(mousePosition, increaseResolutionButton) && mousePressed)
{
resolutionIndex = (resolutionIndex + 1) % ResolutionCount;
gameWidth = (int)resolutionList[resolutionIndex].X;
gameHeight = (int)resolutionList[resolutionIndex].Y;
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
}
if (CheckCollisionPointRec(mousePosition, decreaseTypeButton) && mousePressed)
{
viewportType = (ViewportType)(((int)viewportType + (int)ViewportType.ViewportTypeCount - 1) % (int)ViewportType.ViewportTypeCount);
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
}
if (CheckCollisionPointRec(mousePosition, increaseTypeButton) && mousePressed)
{
viewportType = (ViewportType)(((int)viewportType + 1) % (int)ViewportType.ViewportTypeCount);
ResizeRenderSize(viewportType, ref curScreenWidth, ref curScreenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect, ref target);
}
Vector2 textureMousePosition = Screen2RenderTexturePosition(mousePosition, sourceRect, destRect);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
// Draw our scene to the render texture
BeginTextureMode(target);
ClearBackground(Color.White);
DrawCircleV(textureMousePosition, 20.0f, Color.Lime);
EndTextureMode();
// Draw render texture to main framebuffer
BeginDrawing();
ClearBackground(Color.Black);
// Draw our render texture with rotation applied
DrawTexturePro(target.Texture, sourceRect, destRect, new Vector2(0.0f, 0.0f), 0.0f, Color.White);
// Draw Native resolution (GUI or anything)
// Draw info box
Rectangle infoRect = new Rectangle(5, 5, 330, 105);
DrawRectangleRec(infoRect, Fade(Color.LightGray, 0.7f));
DrawRectangleLinesEx(infoRect, 1, Color.Blue);
DrawText($"Window Resolution: {curScreenWidth} x {curScreenHeight}", 15, 15, 10, Color.Black);
DrawText($"Game Resolution: {gameWidth} x {gameHeight}", 15, 30, 10, Color.Black);
DrawText($"Type: {ViewportTypeNames[(int)viewportType]}", 15, 45, 10, Color.Black);
Vector2 scaleRatio = new Vector2(destRect.Width / sourceRect.Width, -destRect.Height / sourceRect.Height);
if (scaleRatio.X < 0.001f || scaleRatio.Y < 0.001f)
{
DrawText("Scale ratio: INVALID", 15, 60, 10, Color.Black);
}
else
{
DrawText($"Scale ratio: {scaleRatio.X:F2} x {scaleRatio.Y:F2}", 15, 60, 10, Color.Black);
}
DrawText($"Source size: {sourceRect.Width:F2} x {-sourceRect.Height:F2}", 15, 75, 10, Color.Black);
DrawText($"Destination size: {destRect.Width:F2} x {destRect.Height:F2}", 15, 90, 10, Color.Black);
// Draw buttons
DrawRectangleRec(decreaseTypeButton, Color.SkyBlue);
DrawRectangleRec(increaseTypeButton, Color.SkyBlue);
DrawRectangleRec(decreaseResolutionButton, Color.SkyBlue);
DrawRectangleRec(increaseResolutionButton, Color.SkyBlue);
DrawText("<", (int)decreaseTypeButton.X + 3, (int)decreaseTypeButton.Y + 1, 10, Color.Black);
DrawText(">", (int)increaseTypeButton.X + 3, (int)increaseTypeButton.Y + 1, 10, Color.Black);
DrawText("<", (int)decreaseResolutionButton.X + 3, (int)decreaseResolutionButton.Y + 1, 10, Color.Black);
DrawText(">", (int)increaseResolutionButton.X + 3, (int)increaseResolutionButton.Y + 1, 10, Color.Black);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadRenderTexture(target);
}
//--------------------------------------------------------------------------------------
// Module Functions Definition
//--------------------------------------------------------------------------------------
private static void KeepAspectCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
{
sourceRect.X = 0.0f;
sourceRect.Y = (float)gameHeight;
sourceRect.Width = (float)gameWidth;
sourceRect.Height = (float)-gameHeight;
int ratioX = (screenWidth / gameWidth);
int ratioY = (screenHeight / gameHeight);
float resizeRatio = (float)((ratioX < ratioY) ? ratioX : ratioY);
destRect.X = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5f);
destRect.Y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5f);
destRect.Width = (float)(int)(gameWidth * resizeRatio);
destRect.Height = (float)(int)(gameHeight * resizeRatio);
}
private static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
{
float resizeRatio = (float)screenHeight / gameHeight;
sourceRect.X = 0.0f;
sourceRect.Y = 0.0f;
sourceRect.Width = (float)(int)(screenWidth / resizeRatio);
sourceRect.Height = (float)-gameHeight;
destRect.X = (float)(int)((screenWidth - (sourceRect.Width * resizeRatio)) * 0.5f);
destRect.Y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5f);
destRect.Width = (float)(int)(sourceRect.Width * resizeRatio);
destRect.Height = (float)(int)(gameHeight * resizeRatio);
}
private static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
{
float resizeRatio = (float)screenWidth / gameWidth;
sourceRect.X = 0.0f;
sourceRect.Y = 0.0f;
sourceRect.Width = (float)gameWidth;
sourceRect.Height = (float)(int)(screenHeight / resizeRatio);
destRect.X = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5f);
destRect.Y = (float)(int)((screenHeight - (sourceRect.Height * resizeRatio)) * 0.5f);
destRect.Width = (float)(int)(gameWidth * resizeRatio);
destRect.Height = (float)(int)(sourceRect.Height * resizeRatio);
sourceRect.Height *= -1.0f;
}
private static void KeepAspectCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
{
sourceRect.X = 0.0f;
sourceRect.Y = (float)gameHeight;
sourceRect.Width = (float)gameWidth;
sourceRect.Height = (float)-gameHeight;
float ratioX = ((float)screenWidth / (float)gameWidth);
float ratioY = ((float)screenHeight / (float)gameHeight);
float resizeRatio = (ratioX < ratioY ? ratioX : ratioY);
destRect.X = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5f);
destRect.Y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5f);
destRect.Width = (float)(int)(gameWidth * resizeRatio);
destRect.Height = (float)(int)(gameHeight * resizeRatio);
}
private static void KeepHeightCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
{
float resizeRatio = ((float)screenHeight / (float)gameHeight);
sourceRect.X = 0.0f;
sourceRect.Y = 0.0f;
sourceRect.Width = (float)(int)((float)screenWidth / resizeRatio);
sourceRect.Height = (float)-gameHeight;
destRect.X = (float)(int)((screenWidth - (sourceRect.Width * resizeRatio)) * 0.5f);
destRect.Y = (float)(int)((screenHeight - (gameHeight * resizeRatio)) * 0.5f);
destRect.Width = (float)(int)(sourceRect.Width * resizeRatio);
destRect.Height = (float)(int)(gameHeight * resizeRatio);
}
private static void KeepWidthCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect)
{
float resizeRatio = ((float)screenWidth / (float)gameWidth);
sourceRect.X = 0.0f;
sourceRect.Y = 0.0f;
sourceRect.Width = (float)gameWidth;
sourceRect.Height = (float)(int)((float)screenHeight / resizeRatio);
destRect.X = (float)(int)((screenWidth - (gameWidth * resizeRatio)) * 0.5f);
destRect.Y = (float)(int)((screenHeight - (sourceRect.Height * resizeRatio)) * 0.5f);
destRect.Width = (float)(int)(gameWidth * resizeRatio);
destRect.Height = (float)(int)(sourceRect.Height * resizeRatio);
sourceRect.Height *= -1.0f;
}
private static void ResizeRenderSize(ViewportType viewportType, ref int screenWidth, ref int screenHeight, int gameWidth, int gameHeight, ref Rectangle sourceRect, ref Rectangle destRect, ref RenderTexture2D target)
{
screenWidth = GetScreenWidth();
screenHeight = GetScreenHeight();
switch (viewportType)
{
case ViewportType.KeepAspectInteger:
KeepAspectCenteredInteger(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect);
break;
case ViewportType.KeepHeightInteger:
KeepHeightCenteredInteger(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect);
break;
case ViewportType.KeepWidthInteger:
KeepWidthCenteredInteger(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect);
break;
case ViewportType.KeepAspect:
KeepAspectCentered(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect);
break;
case ViewportType.KeepHeight:
KeepHeightCentered(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect);
break;
case ViewportType.KeepWidth:
KeepWidthCentered(screenWidth, screenHeight, gameWidth, gameHeight, ref sourceRect, ref destRect);
break;
default:
break;
}
UnloadRenderTexture(target);
target = LoadRenderTexture((int)sourceRect.Width, -(int)sourceRect.Height);
}
// Example how to calculate position on RenderTexture
private static Vector2 Screen2RenderTexturePosition(Vector2 point, Rectangle textureRect, Rectangle scaledRect)
{
Vector2 relativePosition = new Vector2(point.X - scaledRect.X, point.Y - scaledRect.Y);
Vector2 ratio = new Vector2(textureRect.Width / scaledRect.Width, -textureRect.Height / scaledRect.Height);
return new Vector2(relativePosition.X * ratio.X, relativePosition.Y * ratio.X);
}
public static int Main()
{
// Initialization
//---------------------------------------------------------
SetConfigFlags(ConfigFlags.ResizableWindow);
InitWindow(screenWidth, screenHeight, "raylib [core] example - viewport scaling");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//----------------------------------------------------------
var game = new ViewportScaling();
game.Init();
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
game.Update();
}
game.Unload();
// De-Initialization
//----------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//----------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,65 +1,76 @@
/*******************************************************************************************
*
* raylib [core] example - VR Simulator (Oculus Rift CV1 parameters)
* raylib [core] example - vr simulator
*
* 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: [] 3/4
*
* Copyright (c) 2017 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) 2017-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class VrSimulator
public partial class VrSimulator : IExample
{
public static int Main()
private const int screenWidth = 800;
private const int screenHeight = 450;
#if BROWSER
const int GlslVersion = 100; // WebGL1 needs GLSL ES 100
#else
private const int GlslVersion = 330;
#endif
public string Name => "Core / VR Simulator";
public string Title => "raylib [core] example - vr simulator";
public bool CursorDisabled => true;
private VrStereoConfig config;
private Shader distortion;
private RenderTexture2D target;
private Rectangle sourceRec;
private Rectangle destRec;
private Camera3D camera;
private Vector3 cubePosition;
public unsafe void Init()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 1080;
const int screenHeight = 600;
SetConfigFlags(ConfigFlags.Msaa4xHint);
InitWindow(screenWidth, screenHeight, "raylib [core] example - vr simulator");
// VR device parameters definition
VrDeviceInfo device = new VrDeviceInfo
var device = new VrDeviceInfo
{
// Oculus Rift CV1 parameters for simulator
HResolution = 2160,
VResolution = 1200,
HScreenSize = 0.133793f,
VScreenSize = 0.0669f,
EyeToScreenDistance = 0.041f,
LensSeparationDistance = 0.07f,
InterpupillaryDistance = 0.07f,
HResolution = 2160, // Horizontal resolution in pixels
VResolution = 1200, // Vertical resolution in pixels
HScreenSize = 0.133793f, // Horizontal size in meters
VScreenSize = 0.0669f, // Vertical size in meters
EyeToScreenDistance = 0.041f, // Distance between eye and display in meters
LensSeparationDistance = 0.07f, // Lens separation distance in meters
InterpupillaryDistance = 0.07f, // IPD (distance between pupils) in meters
};
// NOTE: CV1 uses a Fresnel-hybrid-asymmetric lenses with specific distortion compute shaders.
// Following parameters are an approximation to distortion stereo rendering but results differ from actual
// device.
unsafe
{
device.LensDistortionValues[0] = 1.0f;
device.LensDistortionValues[1] = 0.22f;
device.LensDistortionValues[2] = 0.24f;
device.LensDistortionValues[3] = 0.0f;
device.ChromaAbCorrection[0] = 0.996f;
device.ChromaAbCorrection[1] = -0.004f;
device.ChromaAbCorrection[2] = 1.014f;
device.ChromaAbCorrection[3] = 0.0f;
}
// NOTE: CV1 uses fresnel-hybrid-asymmetric lenses with specific compute shaders
// Following parameters are just an approximation to CV1 distortion stereo rendering
device.LensDistortionValues[0] = 1.0f; // Lens distortion constant parameter 0
device.LensDistortionValues[1] = 0.22f; // Lens distortion constant parameter 1
device.LensDistortionValues[2] = 0.24f; // Lens distortion constant parameter 2
device.LensDistortionValues[3] = 0.0f; // Lens distortion constant parameter 3
device.ChromaAbCorrection[0] = 0.996f; // Chromatic aberration correction parameter 0
device.ChromaAbCorrection[1] = -0.004f; // Chromatic aberration correction parameter 1
device.ChromaAbCorrection[2] = 1.014f; // Chromatic aberration correction parameter 2
device.ChromaAbCorrection[3] = 0.0f; // Chromatic aberration correction parameter 3
// Load VR stereo config for VR device parameteres (Oculus Rift CV1 parameters)
VrStereoConfig config = LoadVrStereoConfig(device);
config = LoadVrStereoConfig(device);
// Distortion shader (uses device lens distortion and chroma)
Shader distortion = LoadShader(null, "resources/distortion330.fs");
distortion = LoadShader(null, $"resources/shaders/glsl{GlslVersion}/distortion.fs");
// Update distortion shader with lens and distortion-scale parameters
Raylib.SetShaderValue(
@ -100,88 +111,104 @@ public class VrSimulator
ShaderUniformDataType.Vec2
);
unsafe
{
SetShaderValue(
distortion,
GetShaderLocation(distortion, "deviceWarpParam"),
device.LensDistortionValues,
ShaderUniformDataType.Vec4
);
SetShaderValue(
distortion,
GetShaderLocation(distortion, "chromaAbParam"),
device.ChromaAbCorrection,
ShaderUniformDataType.Vec4
);
}
SetShaderValue(
distortion,
GetShaderLocation(distortion, "deviceWarpParam"),
device.LensDistortionValues,
ShaderUniformDataType.Vec4
);
SetShaderValue(
distortion,
GetShaderLocation(distortion, "chromaAbParam"),
device.ChromaAbCorrection,
ShaderUniformDataType.Vec4
);
// Initialize framebuffer for stereo rendering
// NOTE: Screen size should match HMD aspect ratio
RenderTexture2D target = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
target = LoadRenderTexture(device.HResolution, device.VResolution);
// The target's height is flipped (in the source Rectangle), due to OpenGL reasons
sourceRec = new(0.0f, 0.0f, (float)target.Texture.Width, -(float)target.Texture.Height);
destRec = new(0.0f, 0.0f, (float)GetScreenWidth(), (float)GetScreenHeight());
// Define the camera to look into our 3d world
Camera3D camera;
camera.Position = new Vector3(5.0f, 2.0f, 5.0f);
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.FovY = 60.0f;
camera.Projection = CameraProjection.Perspective;
camera = new();
camera.Position = new Vector3(5.0f, 2.0f, 5.0f); // Camera position
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector
camera.FovY = 60.0f; // Camera field-of-view Y
camera.Projection = CameraProjection.Perspective; // Camera projection type
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
cubePosition = new(0.0f, 0.0f, 0.0f);
}
SetTargetFPS(90); // Set our game to run at 90 frames-per-second
public void Update()
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.FirstPerson);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginTextureMode(target);
ClearBackground(Color.RayWhite);
BeginVrStereoMode(config);
BeginMode3D(camera);
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
DrawGrid(40, 1.0f);
EndMode3D();
EndVrStereoMode();
EndTextureMode();
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginShaderMode(distortion);
DrawTexturePro(target.Texture, sourceRec, destRec, new Vector2(0.0f, 0.0f), 0.0f, Color.White);
EndShaderMode();
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
UnloadVrStereoConfig(config); // Unload stereo config
UnloadRenderTexture(target); // Unload stereo render fbo
UnloadShader(distortion); // Unload distortion shader
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
// NOTE: screenWidth/screenHeight should match VR device aspect ratio
InitWindow(screenWidth, screenHeight, "raylib [core] example - vr simulator");
DisableCursor(); // Limit cursor to relative movement inside the window
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new VrSimulator();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.FirstPerson);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginTextureMode(target);
ClearBackground(Color.RayWhite);
BeginVrStereoMode(config);
BeginMode3D(camera);
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
DrawGrid(40, 1.0f);
EndMode3D();
EndVrStereoMode();
EndTextureMode();
BeginShaderMode(distortion);
DrawTextureRec(
target.Texture,
new Rectangle(0, 0, (float)target.Texture.Width, (float)-target.Texture.Height),
new Vector2(0.0f, 0.0f),
Color.White
);
EndShaderMode();
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadVrStereoConfig(config);
UnloadRenderTexture(target);
UnloadShader(distortion);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

@ -2,28 +2,254 @@
*
* raylib [core] example - window flags
*
* This example has been created using raylib 3.5 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 3/4
*
* Copyright (c) 2020 Ramon Santamaria (@raysan5)
* Example originally created with raylib 3.5, last time updated with raylib 3.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) 2020-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
using static Raylib_cs.ConfigFlags;
namespace Examples.Core;
public class WindowFlags
[ExcludeFromBrowser("runtime window-state flags don't apply to the emscripten canvas")]
public partial class WindowFlags : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Window Flags";
public string Title => "raylib [core] example - window flags";
private Vector2 ballPosition;
private Vector2 ballSpeed;
private float ballRadius;
private int framesCounter = 0;
public void Init()
{
ballPosition = new(GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f);
ballSpeed = new(5.0f, 4.0f);
ballRadius = 20;
framesCounter = 0;
}
public void Update()
{
// Update
//-----------------------------------------------------
if (IsKeyPressed(KeyboardKey.F))
{
// modifies window size when scaling!
ToggleFullscreen();
}
if (IsKeyPressed(KeyboardKey.R))
{
if (IsWindowState(ResizableWindow))
{
ClearWindowState(ResizableWindow);
}
else
{
SetWindowState(ResizableWindow);
}
}
if (IsKeyPressed(KeyboardKey.D))
{
if (IsWindowState(UndecoratedWindow))
{
ClearWindowState(UndecoratedWindow);
}
else
{
SetWindowState(UndecoratedWindow);
}
}
if (IsKeyPressed(KeyboardKey.H))
{
if (!IsWindowState(HiddenWindow))
{
SetWindowState(HiddenWindow);
}
framesCounter = 0;
}
if (IsWindowState(HiddenWindow))
{
framesCounter++;
if (framesCounter >= 240)
{
// Show window after 3 seconds
ClearWindowState(HiddenWindow);
}
}
if (IsKeyPressed(KeyboardKey.N))
{
if (!IsWindowState(MinimizedWindow))
{
MinimizeWindow();
}
framesCounter = 0;
}
if (IsWindowState(MinimizedWindow))
{
framesCounter++;
if (framesCounter >= 240)
{
// Restore window after 3 seconds
RestoreWindow();
}
}
if (IsKeyPressed(KeyboardKey.M))
{
// NOTE: Requires FLAG_WINDOW_RESIZABLE enabled!
if (IsWindowState(MaximizedWindow))
{
RestoreWindow();
}
else
{
MaximizeWindow();
}
}
if (IsKeyPressed(KeyboardKey.U))
{
if (IsWindowState(UnfocusedWindow))
{
ClearWindowState(UnfocusedWindow);
}
else
{
SetWindowState(UnfocusedWindow);
}
}
if (IsKeyPressed(KeyboardKey.T))
{
if (IsWindowState(TopmostWindow))
{
ClearWindowState(TopmostWindow);
}
else
{
SetWindowState(TopmostWindow);
}
}
if (IsKeyPressed(KeyboardKey.A))
{
if (IsWindowState(AlwaysRunWindow))
{
ClearWindowState(AlwaysRunWindow);
}
else
{
SetWindowState(AlwaysRunWindow);
}
}
if (IsKeyPressed(KeyboardKey.V))
{
if (IsWindowState(VSyncHint))
{
ClearWindowState(VSyncHint);
}
else
{
SetWindowState(VSyncHint);
}
}
if (IsKeyPressed(KeyboardKey.B))
{
ToggleBorderlessWindowed();
}
// Bouncing ball logic
ballPosition.X += ballSpeed.X;
ballPosition.Y += ballSpeed.Y;
if ((ballPosition.X >= (GetScreenWidth() - ballRadius)) || (ballPosition.X <= ballRadius))
{
ballSpeed.X *= -1.0f;
}
if ((ballPosition.Y >= (GetScreenHeight() - ballRadius)) || (ballPosition.Y <= ballRadius))
{
ballSpeed.Y *= -1.0f;
}
//-----------------------------------------------------
// Draw
//-----------------------------------------------------
BeginDrawing();
if (IsWindowState(TransparentWindow))
{
ClearBackground(Color.Blank);
}
else
{
ClearBackground(Color.RayWhite);
}
DrawCircleV(ballPosition, ballRadius, Color.Maroon);
DrawRectangleLinesEx(new Rectangle(0, 0, GetScreenWidth(), GetScreenHeight()), 4, Color.RayWhite);
DrawCircleV(GetMousePosition(), 10, Color.DarkBlue);
DrawFPS(10, 10);
DrawText($"Screen Size: [{GetScreenWidth()}, {GetScreenHeight()}]", 10, 40, 10, Color.Green);
// Draw window state info
DrawText("Following flags can be set after window creation:", 10, 60, 10, Color.Gray);
DrawWindowState(FullscreenMode, "[F] FLAG_FULLSCREEN_MODE: ", 10, 80, 10);
DrawWindowState(ResizableWindow, "[R] FLAG_WINDOW_RESIZABLE: ", 10, 100, 10);
DrawWindowState(UndecoratedWindow, "[D] FLAG_WINDOW_UNDECORATED: ", 10, 120, 10);
DrawWindowState(HiddenWindow, "[H] FLAG_WINDOW_HIDDEN: ", 10, 140, 10);
DrawWindowState(MinimizedWindow, "[N] FLAG_WINDOW_MINIMIZED: ", 10, 160, 10);
DrawWindowState(MaximizedWindow, "[M] FLAG_WINDOW_MAXIMIZED: ", 10, 180, 10);
DrawWindowState(UnfocusedWindow, "[G] FLAG_WINDOW_UNFOCUSED: ", 10, 200, 10);
DrawWindowState(TopmostWindow, "[T] FLAG_WINDOW_TOPMOST: ", 10, 220, 10);
DrawWindowState(AlwaysRunWindow, "[A] FLAG_WINDOW_ALWAYS_RUN: ", 10, 240, 10);
DrawWindowState(VSyncHint, "[V] FLAG_VSYNC_HINT: ", 10, 260, 10);
DrawWindowState(BorderlessWindowMode, "[B] FLAG_BORDERLESS_WINDOWED_MODE: ", 10, 280, 10);
DrawText("Following flags can only be set before window creation:", 10, 320, 10, Color.Gray);
DrawWindowState(HighDpiWindow, "FLAG_WINDOW_HIGHDPI: ", 10, 340, 10);
DrawWindowState(TransparentWindow, "FLAG_WINDOW_TRANSPARENT: ", 10, 360, 10);
DrawWindowState(Msaa4xHint, "FLAG_MSAA_4X_HINT: ", 10, 380, 10);
EndDrawing();
//-----------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//---------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
// Possible window flags
/*
FLAG_VSYNC_HINT
@ -42,235 +268,43 @@ public class WindowFlags
*/
// Set configuration flags for window creation
SetConfigFlags(VSyncHint | Msaa4xHint);
//SetConfigFlags(VSyncHint | Msaa4xHint | HighDpiWindow);// | TransparentWindow);
InitWindow(screenWidth, screenHeight, "raylib [core] example - window flags");
Vector2 ballPosition = new(GetScreenWidth() / 2, GetScreenHeight() / 2);
Vector2 ballSpeed = new(5.0f, 4.0f);
int ballRadius = 20;
int framesCounter = 0;
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//----------------------------------------------------------
var game = new WindowFlags();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//-----------------------------------------------------
if (IsKeyPressed(KeyboardKey.F))
{
// modifies window size when scaling!
ToggleFullscreen();
}
if (IsKeyPressed(KeyboardKey.R))
{
if (IsWindowState(ResizableWindow))
{
ClearWindowState(ResizableWindow);
}
else
{
SetWindowState(ResizableWindow);
}
}
if (IsKeyPressed(KeyboardKey.D))
{
if (IsWindowState(UndecoratedWindow))
{
ClearWindowState(UndecoratedWindow);
}
else
{
SetWindowState(UndecoratedWindow);
}
}
if (IsKeyPressed(KeyboardKey.H))
{
if (!IsWindowState(HiddenWindow))
{
SetWindowState(HiddenWindow);
}
framesCounter = 0;
}
if (IsWindowState(HiddenWindow))
{
framesCounter++;
if (framesCounter >= 240)
{
// Show window after 3 seconds
ClearWindowState(HiddenWindow);
}
}
if (IsKeyPressed(KeyboardKey.N))
{
if (!IsWindowState(MinimizedWindow))
{
MinimizeWindow();
}
framesCounter = 0;
}
if (IsWindowState(MinimizedWindow))
{
framesCounter++;
if (framesCounter >= 240)
{
// Restore window after 3 seconds
RestoreWindow();
}
}
if (IsKeyPressed(KeyboardKey.M))
{
// NOTE: Requires FLAG_WINDOW_RESIZABLE enabled!
if (IsWindowState(MaximizedWindow))
{
RestoreWindow();
}
else
{
MaximizeWindow();
}
}
if (IsKeyPressed(KeyboardKey.U))
{
if (IsWindowState(UnfocusedWindow))
{
ClearWindowState(UnfocusedWindow);
}
else
{
SetWindowState(UnfocusedWindow);
}
}
if (IsKeyPressed(KeyboardKey.T))
{
if (IsWindowState(TopmostWindow))
{
ClearWindowState(TopmostWindow);
}
else
{
SetWindowState(TopmostWindow);
}
}
if (IsKeyPressed(KeyboardKey.A))
{
if (IsWindowState(AlwaysRunWindow))
{
ClearWindowState(AlwaysRunWindow);
}
else
{
SetWindowState(AlwaysRunWindow);
}
}
if (IsKeyPressed(KeyboardKey.V))
{
if (IsWindowState(VSyncHint))
{
ClearWindowState(VSyncHint);
}
else
{
SetWindowState(VSyncHint);
}
}
// Bouncing ball logic
ballPosition.X += ballSpeed.X;
ballPosition.Y += ballSpeed.Y;
if ((ballPosition.X >= (GetScreenWidth() - ballRadius)) || (ballPosition.X <= ballRadius))
{
ballSpeed.X *= -1.0f;
}
if ((ballPosition.Y >= (GetScreenHeight() - ballRadius)) || (ballPosition.Y <= ballRadius))
{
ballSpeed.Y *= -1.0f;
}
//-----------------------------------------------------
// Draw
//-----------------------------------------------------
BeginDrawing();
if (IsWindowState(TransparentWindow))
{
ClearBackground(Color.Blank);
}
else
{
ClearBackground(Color.RayWhite);
}
DrawCircleV(ballPosition, ballRadius, Color.Maroon);
DrawRectangleLinesEx(new Rectangle(0, 0, GetScreenWidth(), GetScreenHeight()), 4, Color.RayWhite);
DrawCircleV(GetMousePosition(), 10, Color.DarkBlue);
DrawFPS(10, 10);
DrawText($"Screen Size: [{GetScreenWidth()}, {GetScreenHeight()}]", 10, 40, 10, Color.Green);
// Draw window state info
Color on = Color.Lime;
Color off = Color.Maroon;
DrawText("Following flags can be set after window creation:", 10, 60, 10, Color.Gray);
DrawWindowState(FullscreenMode, "[F] FLAG_FULLSCREEN_MODE: ", 10, 80, 10);
DrawWindowState(ResizableWindow, "[R] FLAG_WINDOW_RESIZABLE: ", 10, 100, 10);
DrawWindowState(UndecoratedWindow, "[D] FLAG_WINDOW_UNDECORATED: ", 10, 120, 10);
DrawWindowState(HiddenWindow, "[H] FLAG_WINDOW_HIDDEN: ", 10, 140, 10);
DrawWindowState(MinimizedWindow, "[N] FLAG_WINDOW_MINIMIZED: ", 10, 160, 10);
DrawWindowState(MaximizedWindow, "[M] FLAG_WINDOW_MAXIMIZED: ", 10, 180, 10);
DrawWindowState(UnfocusedWindow, "[G] FLAG_WINDOW_UNFOCUSED: ", 10, 200, 10);
DrawWindowState(TopmostWindow, "[T] FLAG_WINDOW_TOPMOST: ", 10, 220, 10);
DrawWindowState(AlwaysRunWindow, "[A] FLAG_WINDOW_ALWAYS_RUN: ", 10, 240, 10);
DrawWindowState(VSyncHint, "[V] FLAG_VSYNC_HINT: ", 10, 260, 10);
DrawText("Following flags can only be set before window creation:", 10, 300, 10, Color.Gray);
DrawWindowState(HighDpiWindow, "[F] FLAG_WINDOW_HIGHDPI: ", 10, 320, 10);
DrawWindowState(TransparentWindow, "[F] FLAG_WINDOW_TRANSPARENT: ", 10, 340, 10);
DrawWindowState(Msaa4xHint, "[F] FLAG_MSAA_4X_HINT: ", 10, 360, 10);
EndDrawing();
//-----------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//---------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//----------------------------------------------------------
return 0;
}
static void DrawWindowState(ConfigFlags flag, string text, int posX, int posY, int fontSize)
private static void DrawWindowState(ConfigFlags flag, string text, int posX, int posY, int fontSize)
{
Color onColor = Color.Lime;
Color offColor = Color.Maroon;
var onColor = Color.Lime;
var offColor = Color.Maroon;
if (Raylib.IsWindowState(flag))
{
DrawText($"{text} on", posX, posY, fontSize, onColor);
DrawText($"{text}on", posX, posY, fontSize, onColor);
}
else
{
DrawText($"{text} off", posX, posY, fontSize, offColor);
DrawText($"{text}off", posX, posY, fontSize, offColor);
}
}
}

View file

@ -1,139 +1,169 @@
/*******************************************************************************************
*
* raylib [core] example - window scale letterbox
* raylib [core] example - window letterbox
*
* 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 4.0
*
* Example contributed by Anata (@anatagawa) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2019 Anata (@anatagawa) 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) 2019-2025 Anata (@anatagawa) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class WindowLetterbox
public partial class WindowLetterbox : IExample
{
public static int Main()
private const int windowWidth = 800;
private const int windowHeight = 450;
private const int gamescreenWidth = 640;
private const int gamescreenHeight = 480;
public string Name => "Core / Window Letterbox";
public string Title => "raylib [core] example - window letterbox";
public ConfigFlags ConfigFlags => ConfigFlags.ResizableWindow | ConfigFlags.VSyncHint;
private RenderTexture2D target;
private Color[] colors;
public void Init()
{
const int windowWidth = 800;
const int windowHeight = 450;
// Enable config flags for resizable window and vertical synchro
SetConfigFlags(ConfigFlags.ResizableWindow | ConfigFlags.VSyncHint);
InitWindow(windowWidth, windowHeight, "raylib [core] example - window scale letterbox");
SetWindowMinSize(320, 240);
int gameScreenWidth = 640;
int gameScreenHeight = 480;
// Render texture initialization, used to hold the rendering result so we can easily resize it
RenderTexture2D target = LoadRenderTexture(gameScreenWidth, gameScreenHeight);
SetTextureFilter(target.Texture, TextureFilter.Bilinear);
target = LoadRenderTexture(gamescreenWidth, gamescreenHeight);
SetTextureFilter(target.Texture, TextureFilter.Bilinear); // Texture scale filter to use
Color[] colors = new Color[10];
for (int i = 0; i < 10; i++)
colors = new Color[10];
for (var i = 0; i < 10; i++)
{
colors[i] = new Color(GetRandomValue(100, 250), GetRandomValue(50, 150), GetRandomValue(10, 100), 255);
}
}
SetTargetFPS(60);
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Compute required framebuffer scaling
var scale = MathF.Min(
(float)GetScreenWidth() / gamescreenWidth,
(float)GetScreenHeight() / gamescreenHeight
);
if (IsKeyPressed(KeyboardKey.Space))
{
// Recalculate random colors for the bars
for (var i = 0; i < 10; i++)
{
colors[i] = new Color(
GetRandomValue(100, 250),
GetRandomValue(50, 150),
GetRandomValue(10, 100),
255
);
}
}
// Update virtual mouse (clamped mouse value behind game screen)
var mouse = GetMousePosition();
var virtualMouse = Vector2.Zero;
virtualMouse.X = (mouse.X - (GetScreenWidth() - (gamescreenWidth * scale)) * 0.5f) / scale;
virtualMouse.Y = (mouse.Y - (GetScreenHeight() - (gamescreenHeight * scale)) * 0.5f) / scale;
Vector2 max = new((float)gamescreenWidth, (float)gamescreenHeight);
virtualMouse = Vector2.Clamp(virtualMouse, Vector2.Zero, max);
// Apply the same transformation as the virtual mouse to the real mouse (i.e. to work with raygui)
//SetMouseOffset(-(GetScreenWidth() - (gamescreenWidth*scale))*0.5f, -(GetScreenHeight() - (gamescreenHeight*scale))*0.5f);
//SetMouseScale(1/scale, 1/scale);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
// Draw everything in the render texture, note this will not be rendered on screen, yet
BeginTextureMode(target);
ClearBackground(Color.RayWhite); // Clear render texture background color
for (var i = 0; i < 10; i++)
{
DrawRectangle(0, (gamescreenHeight / 10) * i, gamescreenWidth, gamescreenHeight / 10, colors[i]);
}
DrawText(
"If executed inside a window,\nyou can resize the window,\nand see the screen scaling!",
10,
25,
20,
Color.White
);
DrawText($"Default Mouse: [{(int)mouse.X} , {(int)mouse.Y}]", 350, 25, 20, Color.Green);
DrawText($"Virtual Mouse: [{(int)virtualMouse.X} , {(int)virtualMouse.Y}]", 350, 55, 20, Color.Yellow);
EndTextureMode();
BeginDrawing();
ClearBackground(Color.Black); // Clear screen background
// Draw render texture to screen, properly scaled
Rectangle sourceRec = new(
0.0f,
0.0f,
(float)target.Texture.Width,
(float)-target.Texture.Height
);
Rectangle destRec = new(
(GetScreenWidth() - ((float)gamescreenWidth * scale)) * 0.5f,
(GetScreenHeight() - ((float)gamescreenHeight * scale)) * 0.5f,
(float)gamescreenWidth * scale,
(float)gamescreenHeight * scale
);
DrawTexturePro(target.Texture, sourceRec, destRec, new Vector2(0, 0), 0.0f, Color.White);
EndDrawing();
//--------------------------------------------------------------------------------------
}
public void Unload()
{
UnloadRenderTexture(target); // Unload render texture
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
// Enable config flags for resizable window and vertical synchro
SetConfigFlags(ConfigFlags.ResizableWindow | ConfigFlags.VSyncHint);
InitWindow(windowWidth, windowHeight, "raylib [core] example - window letterbox");
SetWindowMinSize(320, 240);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new WindowLetterbox();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// Compute required framebuffer scaling
float scale = MathF.Min(
(float)GetScreenWidth() / gameScreenWidth,
(float)GetScreenHeight() / gameScreenHeight
);
if (IsKeyPressed(KeyboardKey.Space))
{
// Recalculate random colors for the bars
for (int i = 0; i < 10; i++)
{
colors[i] = new Color(
GetRandomValue(100, 250),
GetRandomValue(50, 150),
GetRandomValue(10, 100),
255
);
}
}
// Update virtual mouse (clamped mouse value behind game screen)
Vector2 mouse = GetMousePosition();
Vector2 virtualMouse = Vector2.Zero;
virtualMouse.X = (mouse.X - (GetScreenWidth() - (gameScreenWidth * scale)) * 0.5f) / scale;
virtualMouse.Y = (mouse.Y - (GetScreenHeight() - (gameScreenHeight * scale)) * 0.5f) / scale;
Vector2 max = new((float)gameScreenWidth, (float)gameScreenHeight);
virtualMouse = Vector2.Clamp(virtualMouse, Vector2.Zero, max);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.Black);
// Draw everything in the render texture, note this will not be rendered on screen, yet
BeginTextureMode(target);
ClearBackground(Color.RayWhite);
for (int i = 0; i < 10; i++)
{
DrawRectangle(0, (gameScreenHeight / 10) * i, gameScreenWidth, gameScreenHeight / 10, colors[i]);
}
DrawText(
"If executed inside a window,\nyou can resize the window,\nand see the screen scaling!",
10,
25,
20,
Color.White
);
DrawText($"Default Mouse: [{(int)mouse.X} {(int)mouse.Y}]", 350, 25, 20, Color.Green);
DrawText($"Virtual Mouse: [{(int)virtualMouse.X}, {(int)virtualMouse.Y}]", 350, 55, 20, Color.Yellow);
EndTextureMode();
// Draw RenderTexture2D to window, properly scaled
Rectangle sourceRec = new(
0.0f,
0.0f,
(float)target.Texture.Width,
(float)-target.Texture.Height
);
Rectangle destRec = new(
(GetScreenWidth() - ((float)gameScreenWidth * scale)) * 0.5f,
(GetScreenHeight() - ((float)gameScreenHeight * scale)) * 0.5f,
(float)gameScreenWidth * scale,
(float)gameScreenHeight * scale
);
DrawTexturePro(target.Texture, sourceRec, destRec, new Vector2(0, 0), 0.0f, Color.White);
EndDrawing();
//--------------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadRenderTexture(target);
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -0,0 +1,126 @@
/*******************************************************************************************
*
* raylib [core] example - window should close
*
* Example complexity rating: [] 1/4
*
* Example originally created with raylib 4.2, 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) 2013-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
namespace Examples.Core;
public partial class WindowShouldClose : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Window Should Close";
public string Title => "raylib [core] example - window should close";
// The runner drives its loop off this instead of WindowShouldClose(), so the exit
// confirmation (polled in Update) can intercept both the X-button and KEY_ESCAPE.
public bool ShouldClose => exitWindow;
private bool exitWindowRequested; // Flag to request window to exit
private bool exitWindow; // Flag to set window to exit
public void Init()
{
SetExitKey(KeyboardKey.Null); // Disable KEY_ESCAPE to close window, X-button still works
exitWindowRequested = false;
exitWindow = false;
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
// Detect if X-button or KEY_ESCAPE have been pressed to close window
bool closeRequested = IsKeyPressed(KeyboardKey.Escape);
#if !BROWSER
// WindowShouldClose() polls the OS window close button, but on the wasm target it calls
// emscripten_sleep (ASYNCIFY is not enabled) and the canvas has no window chrome anyway,
// so on web the confirmation is triggered by KEY_ESCAPE only.
closeRequested |= Raylib.WindowShouldClose();
#endif
if (closeRequested)
{
exitWindowRequested = true;
}
if (exitWindowRequested)
{
// A request for close window has been issued, we can save data before closing
// or just show a message asking for confirmation
if (IsKeyPressed(KeyboardKey.Y))
{
exitWindow = true;
}
else if (IsKeyPressed(KeyboardKey.N))
{
exitWindowRequested = false;
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
if (exitWindowRequested)
{
DrawRectangle(0, 100, screenWidth, 200, Color.Black);
DrawText("Are you sure you want to exit program? [Y/N]", 40, 180, 30, Color.White);
}
else
{
DrawText("Try to close the window to get confirmation message!", 120, 200, 20, Color.LightGray);
}
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
InitWindow(screenWidth, screenHeight, "raylib [core] example - window should close");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new WindowShouldClose();
game.Init();
// Main game loop
while (!game.exitWindow)
{
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}

View file

@ -1,97 +1,127 @@
/*******************************************************************************************
*
* raylib [core] example - World to screen
* raylib [core] example - world screen
*
* This example has been created using raylib 1.3 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [] 2/4
*
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.3, last time updated with raylib 1.4
*
* 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) 2015-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class WorldScreen
public partial class WorldScreen : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / World to Screen";
public string Title => "raylib [core] example - world screen";
public bool CursorDisabled => true;
private Camera3D camera;
private Vector3 cubePosition;
private Vector2 cubeScreenPosition = new(0.0f, 0.0f);
public void Init()
{
// Define the camera to look into our 3d world
camera = new();
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
camera.FovY = 45.0f; // Camera field-of-view Y
camera.Projection = CameraProjection.Perspective; // Camera projection type
cubePosition = new(0.0f, 0.0f, 0.0f);
}
public void Update()
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.ThirdPerson);
// Calculate cube screen space position (with a little offset to be in top)
cubeScreenPosition = GetWorldToScreen(
new Vector3(cubePosition.X, cubePosition.Y + 2.5f, cubePosition.Z),
camera
);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
DrawGrid(10, 1.0f);
EndMode3D();
DrawText(
"Enemy: 100/100",
(int)cubeScreenPosition.X - MeasureText("Enemy: 100/100", 20) / 2,
(int)cubeScreenPosition.Y,
20,
Color.Black
);
DrawText(
$"Cube position in screen space coordinates: [{(int)cubeScreenPosition.X}, {(int)cubeScreenPosition.Y}]",
10,
10,
20,
Color.Lime
);
DrawText("Text 2d should be always on top of the cube", 10, 40, 20, Color.Gray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - world screen");
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free");
DisableCursor(); // Limit cursor to relative movement inside the window
// Define the camera to look into our 3d world
Camera3D camera = new();
camera.Position = new Vector3(10.0f, 10.0f, 10.0f);
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.FovY = 45.0f;
camera.Projection = CameraProjection.Perspective;
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
Vector2 cubeScreenPosition;
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new WorldScreen();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(ref camera, CameraMode.Free);
// Calculate cube screen space position (with a little offset to be in top)
cubeScreenPosition = GetWorldToScreen(
new Vector3(cubePosition.X, cubePosition.Y + 2.5f, cubePosition.Z),
camera
);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
DrawGrid(10, 1.0f);
EndMode3D();
DrawText(
"Enemy: 100 / 100",
(int)cubeScreenPosition.X - MeasureText("Enemy: 100 / 100", 20) / 2,
(int)cubeScreenPosition.Y,
20,
Color.Black
);
DrawText(
"Text is always on top of the cube",
(screenWidth - MeasureText("Text is always on top of the cube", 20)) / 2,
25,
20,
Color.Gray
);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}
}