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

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

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

* chg: Modernize CI workflow, enable SourceLink

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

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

* chore: updated readme

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

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

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

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

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

* chore: readme updated

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

* fix: Wrong signature of FrameBufferComplete

* chore: readme update

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

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

* chore: readme, gitignore, and targets backport.

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

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

* chore: readme, gitignore, and targets backport.

* chore: clean up linter warnings

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

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,76 +1,96 @@
/*******************************************************************************************
*
* raylib [core] example - Initialize 3d camera mode
* raylib [core] example - 3d camera mode
*
* This example has been created using raylib 1.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [★☆☆☆] 1/4
*
* Copyright (c) 2014 Ramon Santamaria (@raysan5)
* Example originally created with raylib 1.0, last time updated with raylib 1.0
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System.Numerics;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public class Camera3dMode
public partial class Camera3dMode : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
private Camera3D camera;
private Vector3 cubePosition;
public string Name => "Core / Camera 3D Mode";
public string Title => "raylib [core] example - 3d camera mode";
public void Init()
{
// Define the camera to look into our 3d world
camera = new();
camera.Position = new Vector3(0.0f, 10.0f, 10.0f); // Camera position
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
camera.FovY = 45.0f; // Camera field-of-view Y
camera.Projection = CameraProjection.Perspective; // Camera mode type
cubePosition = new(0.0f, 0.0f, 0.0f);
}
public void Update()
{
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
DrawGrid(10, 1.0f);
EndMode3D();
DrawText("Welcome to the third dimension!", 10, 40, 20, Color.DarkGray);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera mode");
// Define the camera to look into our 3d world
Camera3D camera = new();
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
camera.FovY = 45.0f;
camera.Projection = CameraProjection.Perspective;
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new Camera3dMode();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update your variables here
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
BeginMode3D(camera);
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
DrawGrid(10, 1.0f);
EndMode3D();
DrawText("Welcome to the third dimension!", 10, 40, 20, Color.DarkGray);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

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

View file

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

View file

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

View file

@ -1,27 +1,41 @@
/*******************************************************************************************
*
* raylib [core] example - Custom logging
* raylib [core] example - custom logging
*
* This example has been created using raylib 2.1 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
* Example complexity rating: [★★★☆] 3/4
*
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example contributed by Pablo Marcos Oltra (@pamarcos) and reviewed by Ramon Santamaria (@raysan5)
*
* Copyright (c) 2018 Pablo Marcos Oltra (@pamarcos) and Ramon Santamaria (@raysan5)
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2018-2025 Pablo Marcos Oltra (@pamarcos) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
using System;
using System.Runtime.InteropServices;
using static Raylib_cs.Raylib;
namespace Examples.Core;
public unsafe class CustomLogging
public unsafe partial class CustomLogging : IExample
{
private const int screenWidth = 800;
private const int screenHeight = 450;
public string Name => "Core / Custom Logging";
public string Title => "raylib [core] example - custom logging";
[UnmanagedCallersOnly(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })]
private static void LogCustom(int logLevel, sbyte* text, sbyte* args)
{
#if BROWSER
// WebAssembly can't invoke the C varargs vsprintf/vsnprintf that Logging.GetLogMessage relies on
// (the wasm runtime traps with "function signature mismatch"), so log the raw, unformatted text.
string message = Marshal.PtrToStringUTF8(new IntPtr(text)) ?? string.Empty;
#else
var message = Logging.GetLogMessage(new IntPtr(text), new IntPtr(args));
/*Console.ForegroundColor = (TraceLogLevel)logLevel switch
@ -36,50 +50,64 @@ public unsafe class CustomLogging
TraceLogLevel.LOG_NONE => ConsoleColor.White,
_ => throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null)
};*/
#endif
Console.WriteLine($"Custom " + message);
// Console.ResetColor();
}
public void Init()
{
// First thing we do is setting our custom logger to ensure everything raylib logs
// will use our own logger instead of its internal one
SetTraceLogCallback(&LogCustom);
}
public void Update()
{
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("Check out the console output to see the custom logger in action!", 60, 200, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
}
public void Unload()
{
#if !BROWSER
// Restore the default formatting logger on desktop. On WebAssembly we leave the (wasm-safe)
// custom logger in place — Logging.LogConsole formats via vsprintf, which traps on wasm.
SetTraceLogCallback(&Logging.LogConsole);
#endif
}
public static int Main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
// First thing we do is setting our custom logger to ensure everything raylib logs
// will use our own logger instead of its internal one
SetTraceLogCallback(&LogCustom);
InitWindow(screenWidth, screenHeight, "raylib [core] example - custom logging");
SetTargetFPS(60);
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
var game = new CustomLogging();
game.Init();
// Main game loop
while (!WindowShouldClose())
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// TODO: Update your variables here
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(Color.RayWhite);
DrawText("Check out the console output to see the custom logger in action!", 60, 200, 20, Color.LightGray);
EndDrawing();
//----------------------------------------------------------------------------------
game.Update();
}
game.Unload();
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow();
SetTraceLogCallback(&Logging.LogConsole);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

Some files were not shown because too many files have changed in this diff Show more