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

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

This commit is contained in:
tiger tiger tiger 2026-07-17 08:22:54 +02:00
commit f804ab7773
234 changed files with 38997 additions and 10578 deletions

View file

@ -0,0 +1,379 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
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,21 +1,17 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -23,7 +19,7 @@ using static Raylib_cs.Raylib;
namespace Examples.Core;
enum GameScreen
internal enum GameScreen
{
Logo = 0,
Title,
@ -31,143 +27,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

@ -33,43 +33,56 @@ 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,37 @@
*
********************************************************************************************/
using System;
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 +60,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,184 @@
/*******************************************************************************************
*
* 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 System;
using System.Numerics;
using static Raylib_cs.Raylib;
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,12 +2,16 @@
*
* 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)
*
********************************************************************************************/
@ -18,20 +22,27 @@ 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 +56,7 @@ public class Camera2dPlatformer
}
}
delegate void CameraUpdaterCallback(
private delegate void CameraUpdaterCallback(
ref Camera2D camera,
ref Player player,
EnvItem[] envItems,
@ -54,21 +65,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 +89,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 +105,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 +205,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 +219,7 @@ public class Camera2dPlatformer
hitObstacle = 1;
player.Speed = 0.0f;
player.Position.Y = ei.Rect.Y;
break;
}
}
@ -226,7 +235,7 @@ public class Camera2dPlatformer
}
}
static void UpdateCameraCenter(
private static void UpdateCameraCenter(
ref Camera2D camera,
ref Player player,
EnvItem[] envItems,
@ -235,11 +244,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 +257,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 +306,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 +327,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 +366,7 @@ public class Camera2dPlatformer
}
}
static void UpdateCameraPlayerBoundsPush(
private static void UpdateCameraPlayerBoundsPush(
ref Camera2D camera,
ref Player player,
EnvItem[] envItems,
@ -368,11 +377,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 +408,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,10 +2,14 @@
*
* 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)
*
********************************************************************************************/
@ -14,171 +18,202 @@ 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,348 @@
/*******************************************************************************************
*
* 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 System;
using System.Numerics;
using static Raylib_cs.Raylib;
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,11 +1,15 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -14,74 +18,100 @@ 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,11 +1,15 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -14,63 +18,82 @@ 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,286 @@
/*******************************************************************************************
*
* 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;
using System.Numerics;
using System.Text;
using static Raylib_cs.Raylib;
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,253 @@
/*******************************************************************************************
*
* 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;
using System.Numerics;
using System.Text;
using static Raylib_cs.Raylib;
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,188 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using static Raylib_cs.Raylib;
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,13 +1,17 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -17,11 +21,23 @@ 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 +52,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

@ -21,108 +21,137 @@ 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,205 @@
/*******************************************************************************************
*
* 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.
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
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,125 @@
/*******************************************************************************************
*
* 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 System.Collections.Generic;
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,173 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
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,145 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
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,224 @@
/*******************************************************************************************
*
* 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
using System.Numerics;
using static Raylib_cs.Raylib;
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,34 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
*
* 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;
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 +36,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

@ -18,145 +18,176 @@ 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,454 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
*
* 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;
using System.Numerics;
using static Raylib_cs.Raylib;
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 +457,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 +490,7 @@ public class InputGesturesTestBed
}
// Get color for gesture value
static Color GetGestureColor(int gesture)
private static Color GetGestureColor(int gesture)
{
switch (gesture)
{

View file

@ -18,64 +18,87 @@ 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

@ -19,95 +19,122 @@ 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

@ -17,48 +17,72 @@ 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

@ -20,74 +20,98 @@ 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,27 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
*
* 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;
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
using static Raylib_cs.Raylib;
public enum PadButton
{
BUTTON_NONE = -1,
@ -32,21 +32,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 +72,7 @@ public class InputVirtualControls
) // Down
];
Vector2[][] arrowTris = [
arrowTris = [
// Up
[
new Vector2(
@ -114,107 +124,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,374 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
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,185 @@
/*******************************************************************************************
*
* 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.Diagnostics;
using System.Threading;
using static Raylib_cs.Raylib;
using static Raylib_cs.Color;
using static Raylib_cs.KeyboardKey;
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 +190,3 @@ public class LoadingThread
dataLoaded = true;
}
}

View file

@ -0,0 +1,209 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
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,11 +1,15 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -14,106 +18,148 @@ 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,183 @@
/*******************************************************************************************
*
* 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 System;
using System.Numerics;
using static Raylib_cs.Raylib;
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,11 +1,15 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -13,57 +17,81 @@ 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,139 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
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,13 +1,17 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -15,68 +19,92 @@ 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,382 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System;
using System.Collections.Generic;
using System.Numerics;
using static Raylib_cs.Raylib;
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,14 +1,18 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -18,117 +22,193 @@ 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,13 +1,17 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -16,25 +20,34 @@ 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 +59,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 +68,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 +77,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,204 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
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,11 +1,15 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -13,79 +17,104 @@ 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 +126,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 +144,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 +169,7 @@ public class StorageValues
newDataSize = dataSize;
// Replace value on selected position
int* dataPtr = (int*)newFileData;
var dataPtr = (int*)newFileData;
dataPtr[position] = value;
}
@ -155,7 +184,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 +202,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 +217,7 @@ public class StorageValues
}
else
{
int* dataPtr = (int*)fileData;
var dataPtr = (int*)fileData;
value = dataPtr[position];
}

View file

@ -0,0 +1,209 @@
/*******************************************************************************************
*
* 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 System.Numerics;
using static Raylib_cs.Raylib;
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;
}
}

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

@ -0,0 +1,333 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
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,361 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
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,11 +1,15 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -15,51 +19,62 @@ 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 +115,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,10 +2,14 @@
*
* 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)
*
********************************************************************************************/
@ -15,15 +19,239 @@ 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 +270,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,13 +1,17 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -17,123 +21,153 @@ 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,130 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
using System;
using System.Numerics;
using static Raylib_cs.Raylib;
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,11 +1,15 @@
/*******************************************************************************************
*
* 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)
*
********************************************************************************************/
@ -14,84 +18,113 @@ 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;
}
}