feat: backporting existing raylib-cs examples and new official raylib examples to WASM, adopting raylib's original code style
This commit is contained in:
parent
6aa91e3097
commit
f804ab7773
234 changed files with 38997 additions and 10578 deletions
263
Examples/Audio/AmpEnvelope.cs
Normal file
263
Examples/Audio/AmpEnvelope.cs
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - amp envelope
|
||||
*
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example contributed by Arbinda Rizki Muhammad (@arbipink) 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) 2026 Arbinda Rizki Muhammad (@arbipink)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public unsafe partial class AmpEnvelope : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int BUFFER_SIZE = 4096;
|
||||
private const int SAMPLE_RATE = 44100;
|
||||
|
||||
// Wave state
|
||||
private enum ADSRState
|
||||
{
|
||||
Idle,
|
||||
Attack,
|
||||
Decay,
|
||||
Sustain,
|
||||
Release
|
||||
}
|
||||
|
||||
// Grouping all ADSR parameters and state into a struct
|
||||
private struct Envelope
|
||||
{
|
||||
public float AttackTime;
|
||||
public float DecayTime;
|
||||
public float SustainLevel;
|
||||
public float ReleaseTime;
|
||||
public float CurrentValue;
|
||||
public ADSRState State;
|
||||
}
|
||||
|
||||
public string Name => "Audio / Amp Envelope";
|
||||
|
||||
public string Title => "raylib [audio] example - amp envelope";
|
||||
|
||||
private float[] buffer;
|
||||
private AudioStream stream;
|
||||
private float audioTime;
|
||||
private Envelope env;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice();
|
||||
|
||||
// Set the number of samples the stream will keep in memory at a time to BUFFER_SIZE
|
||||
SetAudioStreamBufferSizeDefault(BUFFER_SIZE);
|
||||
buffer = new float[BUFFER_SIZE];
|
||||
|
||||
// Init raw audio stream (sample rate: 44100, sample size: 32bit-float, channels: 1-mono)
|
||||
stream = LoadAudioStream(SAMPLE_RATE, 32, 1);
|
||||
|
||||
// Init Phase
|
||||
audioTime = 0.0f;
|
||||
|
||||
// Initialize the struct
|
||||
env = new Envelope
|
||||
{
|
||||
AttackTime = 1.0f,
|
||||
DecayTime = 1.0f,
|
||||
SustainLevel = 0.5f,
|
||||
ReleaseTime = 1.0f,
|
||||
CurrentValue = 0.0f,
|
||||
State = ADSRState.Idle
|
||||
};
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space)) env.State = ADSRState.Attack;
|
||||
|
||||
if (IsKeyReleased(KeyboardKey.Space) && (env.State != ADSRState.Idle)) env.State = ADSRState.Release;
|
||||
|
||||
if (IsAudioStreamProcessed(stream))
|
||||
{
|
||||
if ((env.State != ADSRState.Idle) || (env.CurrentValue > 0.0f))
|
||||
{
|
||||
for (int i = 0; i < BUFFER_SIZE; i++)
|
||||
{
|
||||
UpdateEnvelope(ref env);
|
||||
FillAudioBuffer(i, buffer, env.CurrentValue, ref audioTime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear buffer if silent to avoid looping noise
|
||||
for (int i = 0; i < BUFFER_SIZE; i++) buffer[i] = 0;
|
||||
audioTime = 0.0f;
|
||||
}
|
||||
|
||||
fixed (float* bufferPtr = buffer)
|
||||
{
|
||||
UpdateAudioStream(stream, bufferPtr, BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsAudioStreamPlaying(stream)) PlayAudioStream(stream);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
// NOTE: raygui is not bound in raylib-cs, so the sliders below are left as reference.
|
||||
// The envelope keeps its default parameters (Attack/Decay/Release = 1.0s, Sustain = 0.5).
|
||||
//GuiSliderBar(new Rectangle( 100, 60, 400, 30 ), "Attack (s)", TextFormat("%2.2fs", env.AttackTime), ref env.AttackTime, 0.1f, 3.0f);
|
||||
//GuiSliderBar(new Rectangle( 100, 100, 400, 30 ), "Decay (s)", TextFormat("%2.2fs", env.DecayTime), ref env.DecayTime, 0.1f, 3.0f);
|
||||
//GuiSliderBar(new Rectangle( 100, 140, 400, 30 ), "Sustain", TextFormat("%2.2f", env.SustainLevel), ref env.SustainLevel, 0.0f, 1.0f);
|
||||
//GuiSliderBar(new Rectangle( 100, 180, 400, 30 ), "Release (s)", TextFormat("%2.2fs", env.ReleaseTime), ref env.ReleaseTime, 0.1f, 3.0f);
|
||||
|
||||
DrawADSRGraph(ref env, new Rectangle(100, 250, 400, 100));
|
||||
|
||||
DrawCircleV(new Vector2(520, 350 - (env.CurrentValue * 100)), 5, Color.Maroon);
|
||||
DrawText($"Current Gain: {env.CurrentValue:F2}", 535, (int)(345 - (env.CurrentValue * 100)), 10, Color.Maroon);
|
||||
|
||||
DrawText("Press SPACE to PLAY the sound!", 200, 400, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadAudioStream(stream);
|
||||
CloseAudioDevice();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//------------------------------------------------------------------------------------
|
||||
private static void FillAudioBuffer(int i, float[] buffer, float envelopeValue, ref float audioTime)
|
||||
{
|
||||
int frequency = 440;
|
||||
buffer[i] = envelopeValue * MathF.Sin(2.0f * MathF.PI * frequency * audioTime);
|
||||
audioTime += (1.0f / SAMPLE_RATE);
|
||||
}
|
||||
|
||||
private static void UpdateEnvelope(ref Envelope env)
|
||||
{
|
||||
// Calculate the time delta for ONE sample (1/44100)
|
||||
float sampleTime = 1.0f / SAMPLE_RATE;
|
||||
|
||||
switch (env.State)
|
||||
{
|
||||
case ADSRState.Attack:
|
||||
{
|
||||
env.CurrentValue += (1.0f / env.AttackTime) * sampleTime;
|
||||
if (env.CurrentValue >= 1.0f)
|
||||
{
|
||||
env.CurrentValue = 1.0f;
|
||||
env.State = ADSRState.Decay;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADSRState.Decay:
|
||||
{
|
||||
env.CurrentValue -= ((1.0f - env.SustainLevel) / env.DecayTime) * sampleTime;
|
||||
if (env.CurrentValue <= env.SustainLevel)
|
||||
{
|
||||
env.CurrentValue = env.SustainLevel;
|
||||
env.State = ADSRState.Sustain;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADSRState.Sustain:
|
||||
{
|
||||
env.CurrentValue = env.SustainLevel;
|
||||
}
|
||||
break;
|
||||
case ADSRState.Release:
|
||||
{
|
||||
env.CurrentValue -= (env.SustainLevel / env.ReleaseTime) * sampleTime;
|
||||
if (env.CurrentValue <= 0.001f) // Use a small threshold to avoid infinite tail
|
||||
{
|
||||
env.CurrentValue = 0.0f;
|
||||
env.State = ADSRState.Idle;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawADSRGraph(ref Envelope env, Rectangle bounds)
|
||||
{
|
||||
DrawRectangleRec(bounds, Fade(Color.LightGray, 0.3f));
|
||||
DrawRectangleLinesEx(bounds, 1, Color.Gray);
|
||||
|
||||
// Fixed visual width for sustain stage since it's an amplitude not a time value
|
||||
float sustainWidth = 1.0f;
|
||||
|
||||
// Total time to visualize (sum of A, D, R + a padding for Sustain)
|
||||
float totalTime = env.AttackTime + env.DecayTime + sustainWidth + env.ReleaseTime;
|
||||
|
||||
float scaleX = bounds.Width / totalTime;
|
||||
float scaleY = bounds.Height;
|
||||
|
||||
Vector2 start = new Vector2(bounds.X, bounds.Y + bounds.Height);
|
||||
Vector2 peak = new Vector2(start.X + (env.AttackTime * scaleX), bounds.Y);
|
||||
Vector2 sustain = new Vector2(peak.X + (env.DecayTime * scaleX), bounds.Y + (1.0f - env.SustainLevel) * scaleY);
|
||||
Vector2 rel = new Vector2(sustain.X + (sustainWidth * scaleX), sustain.Y);
|
||||
Vector2 end = new Vector2(rel.X + (env.ReleaseTime * scaleX), bounds.Y + bounds.Height);
|
||||
|
||||
DrawLineV(start, peak, Color.SkyBlue);
|
||||
DrawLineV(peak, sustain, Color.Blue);
|
||||
DrawLineV(sustain, rel, Color.DarkBlue);
|
||||
DrawLineV(rel, end, Color.Orange);
|
||||
|
||||
DrawText("ADSR Visualizer", (int)bounds.X, (int)bounds.Y - 20, 10, Color.DarkGray);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - amp envelope");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new AmpEnvelope();
|
||||
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;
|
||||
}
|
||||
}
|
||||
159
Examples/Audio/MixedProcessor.cs
Normal file
159
Examples/Audio/MixedProcessor.cs
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - mixed processor
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 4.2, last time updated with raylib 4.2
|
||||
*
|
||||
* Example contributed by hkc (@hatkidchan) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2023-2025 hkc (@hatkidchan)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
[ExcludeFromBrowser("AttachAudioMixedProcessor callback is unreliable on the wasm audio backend")]
|
||||
public unsafe partial class MixedProcessor : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Mixed Processor";
|
||||
|
||||
public string Title => "raylib [audio] example - mixed processor";
|
||||
|
||||
private static float exponent = 1.0f; // Audio exponentiation value
|
||||
private static readonly float[] averageVolume = new float[400]; // Average volume history
|
||||
|
||||
private Music music;
|
||||
private Sound sound;
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Audio processing function
|
||||
//------------------------------------------------------------------------------------
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void ProcessAudio(void* buffer, uint frames)
|
||||
{
|
||||
float* samples = (float*)buffer; // Samples internally stored as <float>s
|
||||
float average = 0.0f; // Temporary average volume
|
||||
|
||||
for (uint frame = 0; frame < frames; frame++)
|
||||
{
|
||||
float* left = &samples[frame * 2 + 0];
|
||||
float* right = &samples[frame * 2 + 1];
|
||||
|
||||
*left = MathF.Pow(MathF.Abs(*left), exponent) * ((*left < 0.0f) ? -1.0f : 1.0f);
|
||||
*right = MathF.Pow(MathF.Abs(*right), exponent) * ((*right < 0.0f) ? -1.0f : 1.0f);
|
||||
|
||||
average += MathF.Abs(*left) / frames; // accumulating average volume
|
||||
average += MathF.Abs(*right) / frames;
|
||||
}
|
||||
|
||||
// Moving history to the left
|
||||
for (int i = 0; i < 399; i++) averageVolume[i] = averageVolume[i + 1];
|
||||
|
||||
averageVolume[399] = average; // Adding last average value
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
exponent = 1.0f;
|
||||
Array.Clear(averageVolume, 0, averageVolume.Length);
|
||||
|
||||
AttachAudioMixedProcessor(&ProcessAudio);
|
||||
|
||||
music = LoadMusicStream("resources/audio/country.mp3");
|
||||
sound = LoadSound("resources/audio/coin.wav");
|
||||
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Modify processing variables
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Left)) exponent -= 0.05f;
|
||||
if (IsKeyPressed(KeyboardKey.Right)) exponent += 0.05f;
|
||||
|
||||
if (exponent <= 0.5f) exponent = 0.5f;
|
||||
if (exponent >= 3.0f) exponent = 3.0f;
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Space)) PlaySound(sound);
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, Color.LightGray);
|
||||
|
||||
DrawText($"EXPONENT = {exponent:F2}", 215, 180, 20, Color.LightGray);
|
||||
|
||||
DrawRectangle(199, 199, 402, 34, Color.LightGray);
|
||||
for (int i = 0; i < 400; i++)
|
||||
{
|
||||
DrawLine(201 + i, 232 - (int)(averageVolume[i] * 32), 201 + i, 232, Color.Maroon);
|
||||
}
|
||||
DrawRectangleLines(199, 199, 402, 34, Color.Gray);
|
||||
|
||||
DrawText("PRESS SPACE TO PLAY OTHER SOUND", 200, 250, 20, Color.LightGray);
|
||||
DrawText("USE LEFT AND RIGHT ARROWS TO ALTER DISTORTION", 140, 280, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||
|
||||
DetachAudioMixedProcessor(&ProcessAudio); // Disconnect audio processor
|
||||
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - mixed processor");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MixedProcessor();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - Module playing (streaming)
|
||||
* raylib [audio] example - module playing
|
||||
*
|
||||
* NOTE: This example requires OpenAL Soft library installed
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* This example has been created using raylib 1.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example originally created with raylib 1.5, last time updated with raylib 3.5
|
||||
*
|
||||
* Copyright (c) 2016 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) 2016-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -16,11 +18,20 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public class ModulePlaying
|
||||
public partial class ModulePlaying : IExample
|
||||
{
|
||||
const int MaxCircles = 64;
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
struct CircleWave
|
||||
private const int MaxCircles = 64;
|
||||
|
||||
public string Name => "Audio / Module Playing";
|
||||
|
||||
public string Title => "raylib [audio] example - module playing";
|
||||
|
||||
public ConfigFlags ConfigFlags => ConfigFlags.Msaa4xHint;
|
||||
|
||||
private struct CircleWave
|
||||
{
|
||||
public Vector2 Position;
|
||||
public float Radius;
|
||||
|
|
@ -29,20 +40,18 @@ public class ModulePlaying
|
|||
public Color Color;
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
private Color[] colors;
|
||||
private CircleWave[] circles;
|
||||
private Music music;
|
||||
private float pitch;
|
||||
private float timePlayed;
|
||||
private bool pause;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // NOTE: Try to enable MSAA 4X
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - module playing (streaming)");
|
||||
|
||||
InitAudioDevice();
|
||||
|
||||
Color[] colors = new Color[14] {
|
||||
colors = new Color[14] {
|
||||
Color.Orange,
|
||||
Color.Red,
|
||||
Color.Gold,
|
||||
|
|
@ -59,133 +68,163 @@ public class ModulePlaying
|
|||
Color.Beige
|
||||
};
|
||||
|
||||
// Creates ome circles for visual effect
|
||||
CircleWave[] circles = new CircleWave[MaxCircles];
|
||||
// Creates some circles for visual effect
|
||||
circles = new CircleWave[MaxCircles];
|
||||
|
||||
for (int i = MaxCircles - 1; i >= 0; i--)
|
||||
for (var i = MaxCircles - 1; i >= 0; i--)
|
||||
{
|
||||
circles[i].Alpha = 0.0f;
|
||||
circles[i].Radius = GetRandomValue(10, 40);
|
||||
circles[i].Position.X = GetRandomValue((int)circles[i].Radius, screenWidth - (int)circles[i].Radius);
|
||||
circles[i].Position.Y = GetRandomValue((int)circles[i].Radius, screenHeight - (int)circles[i].Radius);
|
||||
circles[i].Speed = (float)GetRandomValue(1, 100) / 20000.0f;
|
||||
circles[i].Speed = (float)GetRandomValue(1, 100) / 2000.0f;
|
||||
circles[i].Color = colors[GetRandomValue(0, 13)];
|
||||
}
|
||||
|
||||
Music music = LoadMusicStream("resources/audio/mini1111.xm");
|
||||
music = LoadMusicStream("resources/audio/mini1111.xm");
|
||||
music.Looping = false;
|
||||
float pitch = 1.0f;
|
||||
pitch = 1.0f;
|
||||
|
||||
PlayMusicStream(music);
|
||||
|
||||
float timePlayed = 0.0f;
|
||||
bool pause = false;
|
||||
timePlayed = 0.0f;
|
||||
pause = false;
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause)
|
||||
{
|
||||
PauseMusicStream(music);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResumeMusicStream(music);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
pitch -= 0.01f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
pitch += 0.01f;
|
||||
}
|
||||
|
||||
SetMusicPitch(music, pitch);
|
||||
|
||||
// Get timePlayed scaled to bar dimensions
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music) * (screenWidth - 40);
|
||||
|
||||
// Color circles animation
|
||||
for (var i = MaxCircles - 1; (i >= 0) && !pause; i--)
|
||||
{
|
||||
circles[i].Alpha += circles[i].Speed;
|
||||
circles[i].Radius += circles[i].Speed * 10.0f;
|
||||
|
||||
if (circles[i].Alpha > 1.0f)
|
||||
{
|
||||
circles[i].Speed *= -1;
|
||||
}
|
||||
|
||||
if (circles[i].Alpha <= 0.0f)
|
||||
{
|
||||
circles[i].Alpha = 0.0f;
|
||||
circles[i].Radius = GetRandomValue(10, 40);
|
||||
circles[i].Position.X = GetRandomValue(
|
||||
(int)circles[i].Radius,
|
||||
screenWidth - (int)circles[i].Radius
|
||||
);
|
||||
circles[i].Position.Y = GetRandomValue(
|
||||
(int)circles[i].Radius,
|
||||
screenHeight - (int)circles[i].Radius
|
||||
);
|
||||
circles[i].Color = colors[GetRandomValue(0, 13)];
|
||||
circles[i].Speed = (float)GetRandomValue(1, 100) / 2000.0f;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
for (var i = MaxCircles - 1; i >= 0; i--)
|
||||
{
|
||||
DrawCircleV(
|
||||
circles[i].Position,
|
||||
circles[i].Radius,
|
||||
Fade(circles[i].Color, circles[i].Alpha)
|
||||
);
|
||||
}
|
||||
|
||||
// Draw time bar
|
||||
DrawRectangle(20, screenHeight - 20 - 12, screenWidth - 40, 12, Color.LightGray);
|
||||
DrawRectangle(20, screenHeight - 20 - 12, (int)timePlayed, 12, Color.Maroon);
|
||||
DrawRectangleLines(20, screenHeight - 20 - 12, screenWidth - 40, 12, Color.Gray);
|
||||
|
||||
// Draw help instructions
|
||||
DrawRectangle(20, 20, 425, 145, Color.White);
|
||||
DrawRectangleLines(20, 20, 425, 145, Color.Gray);
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 40, 40, 20, Color.Black);
|
||||
DrawText("PRESS P TO PAUSE/RESUME", 40, 70, 20, Color.Black);
|
||||
DrawText("PRESS UP/DOWN TO CHANGE SPEED", 40, 100, 20, Color.Black);
|
||||
DrawText($"SPEED: {pitch:F6}", 40, 130, 20, Color.Maroon);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetConfigFlags(ConfigFlags.Msaa4xHint); // NOTE: Try to enable MSAA 4X
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - module playing");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new ModulePlaying();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause)
|
||||
{
|
||||
PauseMusicStream(music);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResumeMusicStream(music);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
pitch -= 0.01f;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
pitch += 0.01f;
|
||||
}
|
||||
|
||||
SetMusicPitch(music, pitch);
|
||||
|
||||
// Get timePlayed scaled to bar dimensions
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music) * (screenWidth - 40);
|
||||
|
||||
// Color circles animation
|
||||
for (int i = MaxCircles - 1; (i >= 0) && !pause; i--)
|
||||
{
|
||||
circles[i].Alpha += circles[i].Speed;
|
||||
circles[i].Radius += circles[i].Speed * 10.0f;
|
||||
|
||||
if (circles[i].Alpha > 1.0f)
|
||||
{
|
||||
circles[i].Speed *= -1;
|
||||
}
|
||||
|
||||
if (circles[i].Alpha <= 0.0f)
|
||||
{
|
||||
circles[i].Alpha = 0.0f;
|
||||
circles[i].Radius = GetRandomValue(10, 40);
|
||||
circles[i].Position.X = GetRandomValue(
|
||||
(int)circles[i].Radius,
|
||||
screenWidth - (int)circles[i].Radius
|
||||
);
|
||||
circles[i].Position.Y = GetRandomValue(
|
||||
(int)circles[i].Radius,
|
||||
screenHeight - (int)circles[i].Radius
|
||||
);
|
||||
circles[i].Color = colors[GetRandomValue(0, 13)];
|
||||
circles[i].Speed = (float)GetRandomValue(1, 100) / 2000.0f;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
for (int i = MaxCircles - 1; i >= 0; i--)
|
||||
{
|
||||
DrawCircleV(
|
||||
circles[i].Position,
|
||||
circles[i].Radius,
|
||||
ColorAlpha(circles[i].Color, circles[i].Alpha)
|
||||
);
|
||||
}
|
||||
|
||||
// Draw time bar
|
||||
DrawRectangle(20, screenHeight - 20 - 12, screenWidth - 40, 12, Color.LightGray);
|
||||
DrawRectangle(20, screenHeight - 20 - 12, (int)timePlayed, 12, Color.Maroon);
|
||||
DrawRectangleLines(20, screenHeight - 20 - 12, screenWidth - 40, 12, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadMusicStream(music);
|
||||
|
||||
CloseAudioDevice();
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - IntPtr playing (streaming)
|
||||
* raylib [audio] example - music stream
|
||||
*
|
||||
* NOTE: This example requires OpenAL Soft library installed
|
||||
* Example complexity rating: [★☆☆☆] 1/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)
|
||||
* Example originally created with raylib 1.3, last time updated with raylib 4.2
|
||||
*
|
||||
* Copyright (c) 2015 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) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -15,90 +17,176 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public class MusicStreamDemo
|
||||
public partial class MusicStreamDemo : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Music Stream Demo";
|
||||
|
||||
public string Title => "raylib [audio] example - music stream";
|
||||
|
||||
public int TargetFps => 30;
|
||||
|
||||
private Music music;
|
||||
private float timePlayed;
|
||||
private bool pause;
|
||||
private float pan;
|
||||
private float volume;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
music = LoadMusicStream("resources/audio/country.mp3");
|
||||
|
||||
PlayMusicStream(music);
|
||||
|
||||
timePlayed = 0.0f; // Time played normalized [0.0f..1.0f]
|
||||
pause = false; // Music playing paused
|
||||
|
||||
pan = 0.0f; // Default audio pan center [-1.0f..1.0f]
|
||||
SetMusicPan(music, pan);
|
||||
|
||||
volume = 0.8f; // Default audio volume [0.0f..1.0f]
|
||||
SetMusicVolume(music, volume);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause)
|
||||
{
|
||||
PauseMusicStream(music);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResumeMusicStream(music);
|
||||
}
|
||||
}
|
||||
|
||||
// Set audio pan
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
pan -= 0.05f;
|
||||
if (pan < -1.0f)
|
||||
{
|
||||
pan = -1.0f;
|
||||
}
|
||||
SetMusicPan(music, pan);
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
pan += 0.05f;
|
||||
if (pan > 1.0f)
|
||||
{
|
||||
pan = 1.0f;
|
||||
}
|
||||
SetMusicPan(music, pan);
|
||||
}
|
||||
|
||||
// Set audio volume
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
volume -= 0.05f;
|
||||
if (volume < 0.0f)
|
||||
{
|
||||
volume = 0.0f;
|
||||
}
|
||||
SetMusicVolume(music, volume);
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
volume += 0.05f;
|
||||
if (volume > 1.0f)
|
||||
{
|
||||
volume = 1.0f;
|
||||
}
|
||||
SetMusicVolume(music, volume);
|
||||
}
|
||||
|
||||
// Get normalized time played for current music stream
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music);
|
||||
|
||||
if (timePlayed > 1.0f)
|
||||
{
|
||||
timePlayed = 1.0f; // Make sure time played is no longer than music
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, Color.LightGray);
|
||||
|
||||
DrawText("LEFT-RIGHT for PAN CONTROL", 320, 74, 10, Color.DarkBlue);
|
||||
DrawRectangle(300, 100, 200, 12, Color.LightGray);
|
||||
DrawRectangleLines(300, 100, 200, 12, Color.Gray);
|
||||
DrawRectangle((int)(300 + (pan + 1.0f) / 2.0f * 200 - 5), 92, 10, 28, Color.DarkGray);
|
||||
|
||||
DrawRectangle(200, 200, 400, 12, Color.LightGray);
|
||||
DrawRectangle(200, 200, (int)(timePlayed * 400.0f), 12, Color.Maroon);
|
||||
DrawRectangleLines(200, 200, 400, 12, Color.Gray);
|
||||
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, Color.LightGray);
|
||||
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, Color.LightGray);
|
||||
|
||||
DrawText("UP-DOWN for VOLUME CONTROL", 320, 334, 10, Color.DarkGreen);
|
||||
DrawRectangle(300, 360, 200, 12, Color.LightGray);
|
||||
DrawRectangleLines(300, 360, 200, 12, Color.Gray);
|
||||
DrawRectangle((int)(300 + volume * 200 - 5), 352, 10, 28, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - music stream");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - music playing (streaming)");
|
||||
InitAudioDevice();
|
||||
|
||||
Music music = LoadMusicStream("resources/audio/country.mp3");
|
||||
PlayMusicStream(music);
|
||||
|
||||
float timePlayed = 0.0f;
|
||||
bool pause = false;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(30); // Set our game to run at 30 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new MusicStreamDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause)
|
||||
{
|
||||
PauseMusicStream(music);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResumeMusicStream(music);
|
||||
}
|
||||
}
|
||||
|
||||
// Get timePlayed scaled to bar dimensions (400 pixels)
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music) * 400;
|
||||
|
||||
if (timePlayed > 400)
|
||||
{
|
||||
StopMusicStream(music);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, Color.LightGray);
|
||||
|
||||
DrawRectangle(200, 200, 400, 12, Color.LightGray);
|
||||
DrawRectangle(200, 200, (int)timePlayed, 12, Color.Maroon);
|
||||
DrawRectangleLines(200, 200, 400, 12, Color.Gray);
|
||||
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, Color.LightGray);
|
||||
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadMusicStream(music);
|
||||
|
||||
CloseAudioDevice();
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
182
Examples/Audio/RawStream.cs
Normal file
182
Examples/Audio/RawStream.cs
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - raw stream
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 1.6, last time updated with raylib 6.0
|
||||
*
|
||||
* Example created by Ramon Santamaria (@raysan5) and reviewed by James Hofmann (@triplefox)
|
||||
*
|
||||
* 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-2026 Ramon Santamaria (@raysan5) and James Hofmann (@triplefox)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public unsafe partial class RawStream : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int BUFFER_SIZE = 4096;
|
||||
private const int SAMPLE_RATE = 44100;
|
||||
|
||||
public string Name => "Audio / Raw Stream";
|
||||
|
||||
public string Title => "raylib [audio] example - raw stream";
|
||||
|
||||
public int TargetFps => 30;
|
||||
|
||||
private float[] buffer;
|
||||
private AudioStream stream;
|
||||
private float pan;
|
||||
private int sineFrequency;
|
||||
private int newSineFrequency;
|
||||
private int sineIndex;
|
||||
private double sineStartTime;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice();
|
||||
|
||||
// Set the number of samples the stream will keep in memory at a time to BUFFER_SIZE
|
||||
SetAudioStreamBufferSizeDefault(BUFFER_SIZE);
|
||||
buffer = new float[BUFFER_SIZE];
|
||||
|
||||
// Init raw audio stream (sample rate: 44100, sample size: 32bit-float, channels: 1-mono)
|
||||
stream = LoadAudioStream(SAMPLE_RATE, 32, 1);
|
||||
pan = 0.0f;
|
||||
SetAudioStreamPan(stream, pan);
|
||||
PlayAudioStream(stream);
|
||||
|
||||
sineFrequency = 440;
|
||||
newSineFrequency = 440;
|
||||
sineIndex = 0;
|
||||
sineStartTime = 0.0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
newSineFrequency += 10;
|
||||
if (newSineFrequency > 12500) newSineFrequency = 12500;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
newSineFrequency -= 10;
|
||||
if (newSineFrequency < 20) newSineFrequency = 20;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
pan -= 0.01f;
|
||||
if (pan < -1.0f) pan = -1.0f;
|
||||
SetAudioStreamPan(stream, pan);
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
pan += 0.01f;
|
||||
if (pan > 1.0f) pan = 1.0f;
|
||||
SetAudioStreamPan(stream, pan);
|
||||
}
|
||||
|
||||
if (IsAudioStreamProcessed(stream))
|
||||
{
|
||||
for (int i = 0; i < BUFFER_SIZE; i++)
|
||||
{
|
||||
int wl = SAMPLE_RATE / sineFrequency;
|
||||
buffer[i] = MathF.Sin(2 * MathF.PI * sineIndex / wl);
|
||||
sineIndex++;
|
||||
|
||||
if (sineIndex >= wl)
|
||||
{
|
||||
sineFrequency = newSineFrequency;
|
||||
sineIndex = 0;
|
||||
sineStartTime = GetTime();
|
||||
}
|
||||
}
|
||||
|
||||
fixed (float* bufferPtr = buffer)
|
||||
{
|
||||
UpdateAudioStream(stream, bufferPtr, BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText($"sine frequency: {sineFrequency}", screenWidth - 220, 10, 20, Color.Red);
|
||||
DrawText($"pan: {pan:F2}", screenWidth - 220, 30, 20, Color.Red);
|
||||
DrawText("Up/down to change frequency", 10, 10, 20, Color.DarkGray);
|
||||
DrawText("Left/right to pan", 10, 30, 20, Color.DarkGray);
|
||||
|
||||
int windowStart = (int)((GetTime() - sineStartTime) * SAMPLE_RATE);
|
||||
int windowSize = (int)(0.1f * SAMPLE_RATE);
|
||||
int wavelength = SAMPLE_RATE / sineFrequency;
|
||||
|
||||
// Draw a sine wave with the same frequency as the one being sent to the audio stream
|
||||
for (int i = 0; i < screenWidth; i++)
|
||||
{
|
||||
int t0 = windowStart + i * windowSize / screenWidth;
|
||||
int t1 = windowStart + (i + 1) * windowSize / screenWidth;
|
||||
Vector2 startPos = new Vector2(i, 250 + 50 * MathF.Sin(2 * MathF.PI * t0 / wavelength));
|
||||
Vector2 endPos = new Vector2(i + 1, 250 + 50 * MathF.Sin(2 * MathF.PI * t1 / wavelength));
|
||||
DrawLineV(startPos, endPos, Color.Red);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadAudioStream(stream); // Close raw audio stream and delete buffers from RAM
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw stream");
|
||||
|
||||
SetTargetFPS(30);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new RawStream();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - Sound loading and playing
|
||||
* raylib [audio] example - sound loading
|
||||
*
|
||||
* NOTE: This example requires OpenAL Soft library installed
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* 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 originally created with raylib 1.1, last time updated with raylib 3.5
|
||||
*
|
||||
* Copyright (c) 2014 Ramon Santamaria (@raysan5)
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -15,60 +17,84 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public class SoundLoading
|
||||
public partial class SoundLoading : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Sound Loading";
|
||||
|
||||
public string Title => "raylib [audio] example - sound loading";
|
||||
|
||||
private Sound fxWav;
|
||||
private Sound fxOgg;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
fxWav = LoadSound("resources/audio/sound.wav"); // Load WAV audio file
|
||||
fxOgg = LoadSound("resources/audio/target.ogg"); // Load OGG audio file
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
PlaySound(fxWav); // Play WAV sound
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Enter))
|
||||
{
|
||||
PlaySound(fxOgg); // Play OGG sound
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Press SPACE to PLAY the WAV sound!", 200, 180, 20, Color.LightGray);
|
||||
DrawText("Press ENTER to PLAY the OGG sound!", 200, 220, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadSound(fxWav); // Unload sound data
|
||||
UnloadSound(fxOgg); // Unload sound data
|
||||
|
||||
CloseAudioDevice(); // Close audio device
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - sound loading");
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - sound loading and playing");
|
||||
InitAudioDevice();
|
||||
|
||||
Sound fxWav = LoadSound("resources/audio/sound.wav");
|
||||
Sound fxOgg = LoadSound("resources/audio/target.ogg");
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SoundLoading();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
PlaySound(fxWav);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Enter))
|
||||
{
|
||||
PlaySound(fxOgg);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Press SPACE to PLAY the WAV sound!", 200, 180, 20, Color.LightGray);
|
||||
DrawText("Press ENTER to PLAY the OGG sound!", 200, 220, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
UnloadSound(fxWav);
|
||||
UnloadSound(fxOgg);
|
||||
|
||||
CloseAudioDevice();
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
114
Examples/Audio/SoundMulti.cs
Normal file
114
Examples/Audio/SoundMulti.cs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - sound multi
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.0
|
||||
*
|
||||
* 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) 2023-2025 Jeffery Myers (@JeffM2501)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public partial class SoundMulti : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int MAX_SOUNDS = 10;
|
||||
|
||||
public string Name => "Audio / Sound Multi";
|
||||
|
||||
public string Title => "raylib [audio] example - sound multi";
|
||||
|
||||
private Sound[] soundArray = new Sound[MAX_SOUNDS];
|
||||
private int currentSound;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
// Load audio file into the first slot as the 'source' sound,
|
||||
// this sound owns the sample data
|
||||
soundArray[0] = LoadSound("resources/audio/sound.wav");
|
||||
|
||||
// Load an alias of the sound into slots 1-9. These do not own the sound data, but can be played
|
||||
for (int i = 1; i < MAX_SOUNDS; i++) soundArray[i] = LoadSoundAlias(soundArray[0]);
|
||||
|
||||
currentSound = 0; // Set the sound list to the start
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
PlaySound(soundArray[currentSound]); // Play the next open sound slot
|
||||
currentSound++; // Increment the sound slot
|
||||
|
||||
// If the sound slot is out of bounds, go back to 0
|
||||
if (currentSound >= MAX_SOUNDS) currentSound = 0;
|
||||
|
||||
// NOTE: Another approach would be to look at the list for the first sound
|
||||
// that is not playing and use that slot
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Press SPACE to PLAY a WAV sound!", 200, 180, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
for (int i = 1; i < MAX_SOUNDS; i++) UnloadSoundAlias(soundArray[i]); // Unload sound aliases
|
||||
UnloadSound(soundArray[0]); // Unload source sound data
|
||||
|
||||
CloseAudioDevice(); // Close audio device
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - sound multi");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SoundMulti();
|
||||
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;
|
||||
}
|
||||
}
|
||||
154
Examples/Audio/SoundPositioning.cs
Normal file
154
Examples/Audio/SoundPositioning.cs
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - sound positioning
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.5
|
||||
*
|
||||
* Example contributed by Le Juez Victor (@Bigfoot71) 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 Le Juez Victor (@Bigfoot71)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
public partial class SoundPositioning : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Sound Positioning";
|
||||
|
||||
public string Title => "raylib [audio] example - sound positioning";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Sound sound;
|
||||
private Camera3D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice();
|
||||
|
||||
sound = LoadSound("resources/audio/coin.wav");
|
||||
|
||||
camera = new Camera3D
|
||||
{
|
||||
Position = new Vector3(0, 5, 5),
|
||||
Target = new Vector3(0, 0, 0),
|
||||
Up = new Vector3(0, 1, 0),
|
||||
FovY = 60,
|
||||
Projection = CameraProjection.Perspective
|
||||
};
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
|
||||
float th = (float)GetTime();
|
||||
|
||||
Vector3 spherePos = new Vector3(
|
||||
5.0f * MathF.Cos(th),
|
||||
0.0f,
|
||||
5.0f * MathF.Sin(th)
|
||||
);
|
||||
|
||||
SetSoundPosition(camera, sound, spherePos, 1.0f);
|
||||
|
||||
if (!IsSoundPlaying(sound)) PlaySound(sound);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawGrid(10, 2);
|
||||
DrawSphere(spherePos, 0.5f, Color.Red);
|
||||
EndMode3D();
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadSound(sound);
|
||||
CloseAudioDevice(); // Close audio device
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//------------------------------------------------------------------------------------
|
||||
// Set sound 3d position
|
||||
private static void SetSoundPosition(Camera3D listener, Sound sound, Vector3 position, float maxDist)
|
||||
{
|
||||
// Calculate direction vector and distance between listener and sound source
|
||||
Vector3 direction = Vector3.Subtract(position, listener.Position);
|
||||
float distance = direction.Length();
|
||||
|
||||
// Apply logarithmic distance attenuation and clamp between 0-1
|
||||
float attenuation = 1.0f / (1.0f + (distance / maxDist));
|
||||
attenuation = Math.Clamp(attenuation, 0.0f, 1.0f);
|
||||
|
||||
// Calculate normalized vectors for spatial positioning
|
||||
Vector3 normalizedDirection = Vector3.Normalize(direction);
|
||||
Vector3 forward = Vector3.Normalize(Vector3.Subtract(listener.Target, listener.Position));
|
||||
Vector3 right = Vector3.Normalize(Vector3.Cross(listener.Up, forward));
|
||||
|
||||
// Reduce volume for sounds behind the listener
|
||||
float dotProduct = Vector3.Dot(forward, normalizedDirection);
|
||||
if (dotProduct < 0.0f) attenuation *= (1.0f + dotProduct * 0.5f);
|
||||
|
||||
// Set stereo panning based on sound position relative to listener
|
||||
float pan = 0.5f + 0.5f * Vector3.Dot(normalizedDirection, right);
|
||||
|
||||
// Apply final sound properties
|
||||
SetSoundVolume(sound, attenuation);
|
||||
SetSoundPan(sound, pan);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - sound positioning");
|
||||
|
||||
DisableCursor();
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new SoundPositioning();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
306
Examples/Audio/StreamCallback.cs
Normal file
306
Examples/Audio/StreamCallback.cs
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - stream callback
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 6.0, last time updated with raylib 6.0
|
||||
*
|
||||
* Example created by Dan Hoang (@dan-hoang) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* NOTE: Example sends a wave to the audio device,
|
||||
* user gets the choice of four waves: sine, square, triangle, and sawtooth
|
||||
* A stream is set up to play to the audio device; stream is hooked to a callback that
|
||||
* generates a wave, that is determined by user choice
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2026 Dan Hoang (@dan-hoang)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
[ExcludeFromBrowser("SetAudioStreamCallback is unreliable on the wasm audio backend")]
|
||||
public unsafe partial class StreamCallback : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private const int BUFFER_SIZE = 4096;
|
||||
private const int SAMPLE_RATE = 44100;
|
||||
|
||||
// Wave type
|
||||
private enum WaveType
|
||||
{
|
||||
Sine,
|
||||
Square,
|
||||
Triangle,
|
||||
Sawtooth
|
||||
}
|
||||
|
||||
public string Name => "Audio / Stream Callback";
|
||||
|
||||
public string Title => "raylib [audio] example - stream callback";
|
||||
|
||||
public int TargetFps => 30;
|
||||
|
||||
private static int waveFrequency = 440;
|
||||
private static int newWaveFrequency = 440;
|
||||
private static int waveIndex = 0;
|
||||
|
||||
// Buffer to keep the last second of uploaded audio,
|
||||
// part of which will be drawn on the screen
|
||||
private static readonly float[] buffer = new float[SAMPLE_RATE];
|
||||
|
||||
private static readonly string[] waveTypesAsString = { "sine", "square", "triangle", "sawtooth" };
|
||||
|
||||
private AudioStream stream;
|
||||
private WaveType waveType;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice();
|
||||
|
||||
waveFrequency = 440;
|
||||
newWaveFrequency = 440;
|
||||
waveIndex = 0;
|
||||
Array.Clear(buffer, 0, buffer.Length);
|
||||
|
||||
// Set the number of samples the stream will keep in memory at a time to BUFFER_SIZE
|
||||
SetAudioStreamBufferSizeDefault(BUFFER_SIZE);
|
||||
|
||||
// Init raw audio stream (sample rate: 44100, sample size: 32bit-float, channels: 1-mono)
|
||||
stream = LoadAudioStream(SAMPLE_RATE, 32, 1);
|
||||
PlayAudioStream(stream);
|
||||
|
||||
// Configure it so that the callback for waveType is called whenever stream is out of samples
|
||||
waveType = WaveType.Sine;
|
||||
SetWaveCallback();
|
||||
}
|
||||
|
||||
// Attach the callback matching the current waveType to the stream
|
||||
private void SetWaveCallback()
|
||||
{
|
||||
switch (waveType)
|
||||
{
|
||||
case WaveType.Sine: SetAudioStreamCallback(stream, &SineCallback); break;
|
||||
case WaveType.Square: SetAudioStreamCallback(stream, &SquareCallback); break;
|
||||
case WaveType.Triangle: SetAudioStreamCallback(stream, &TriangleCallback); break;
|
||||
case WaveType.Sawtooth: SetAudioStreamCallback(stream, &SawtoothCallback); break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyDown(KeyboardKey.Up))
|
||||
{
|
||||
newWaveFrequency += 10;
|
||||
if (newWaveFrequency > 12500) newWaveFrequency = 12500;
|
||||
}
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Down))
|
||||
{
|
||||
newWaveFrequency -= 10;
|
||||
if (newWaveFrequency < 20) newWaveFrequency = 20;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Left))
|
||||
{
|
||||
if (waveType == WaveType.Sine) waveType = WaveType.Sawtooth;
|
||||
else if (waveType == WaveType.Square) waveType = WaveType.Sine;
|
||||
else if (waveType == WaveType.Triangle) waveType = WaveType.Square;
|
||||
else waveType = WaveType.Triangle;
|
||||
|
||||
SetWaveCallback();
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Right))
|
||||
{
|
||||
if (waveType == WaveType.Sine) waveType = WaveType.Square;
|
||||
else if (waveType == WaveType.Square) waveType = WaveType.Triangle;
|
||||
else if (waveType == WaveType.Triangle) waveType = WaveType.Sawtooth;
|
||||
else waveType = WaveType.Sine;
|
||||
|
||||
SetWaveCallback();
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
DrawText($"frequency: {newWaveFrequency}", screenWidth - 220, 10, 20, Color.Red);
|
||||
DrawText($"wave type: {waveTypesAsString[(int)waveType]}", screenWidth - 220, 30, 20, Color.Red);
|
||||
DrawText("Up/down to change frequency", 10, 10, 20, Color.DarkGray);
|
||||
DrawText("Left/right to change wave type", 10, 30, 20, Color.DarkGray);
|
||||
|
||||
// Draw the last 10 ms of uploaded audio
|
||||
for (int i = 0; i < screenWidth; i++)
|
||||
{
|
||||
Vector2 startPos = new Vector2(i, 250 - 50 * buffer[WaveSampleIndex(i)]);
|
||||
Vector2 endPos = new Vector2(i + 1, 250 - 50 * buffer[WaveSampleIndex(i + 1)]);
|
||||
DrawLineV(startPos, endPos, Color.Red);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadAudioStream(stream); // Close raw audio stream and delete buffers from RAM
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
}
|
||||
|
||||
// Maps a screen column to a sample index in the last 10 ms of the buffer. The final column
|
||||
// maps one sample past the end of the buffer; upstream C reads out of bounds there, so we
|
||||
// clamp to the last valid sample (visually identical, but safe under C# bounds checking).
|
||||
private static int WaveSampleIndex(int column)
|
||||
{
|
||||
int index = SAMPLE_RATE - SAMPLE_RATE / 100 + column * SAMPLE_RATE / 100 / screenWidth;
|
||||
return index < SAMPLE_RATE ? index : SAMPLE_RATE - 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//------------------------------------------------------------------------------------
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void SineCallback(void* framesOut, uint frameCount)
|
||||
{
|
||||
int fc = (int)frameCount;
|
||||
int wavelength = SAMPLE_RATE / waveFrequency;
|
||||
float* frames = (float*)framesOut;
|
||||
|
||||
// Synthesize the sine wave
|
||||
for (int i = 0; i < fc; i++)
|
||||
{
|
||||
frames[i] = MathF.Sin(2 * MathF.PI * waveIndex / wavelength);
|
||||
|
||||
waveIndex++;
|
||||
|
||||
if (waveIndex >= wavelength)
|
||||
{
|
||||
waveFrequency = newWaveFrequency;
|
||||
waveIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the synthesized samples for later drawing
|
||||
for (int i = 0; i < SAMPLE_RATE - fc; i++) buffer[i] = buffer[i + fc];
|
||||
for (int i = 0; i < fc; i++) buffer[SAMPLE_RATE - fc + i] = frames[i];
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void SquareCallback(void* framesOut, uint frameCount)
|
||||
{
|
||||
int fc = (int)frameCount;
|
||||
int wavelength = SAMPLE_RATE / waveFrequency;
|
||||
float* frames = (float*)framesOut;
|
||||
|
||||
// Synthesize the square wave
|
||||
for (int i = 0; i < fc; i++)
|
||||
{
|
||||
frames[i] = (waveIndex < wavelength / 2) ? 1 : -1;
|
||||
waveIndex++;
|
||||
|
||||
if (waveIndex >= wavelength)
|
||||
{
|
||||
waveFrequency = newWaveFrequency;
|
||||
waveIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the synthesized samples for later drawing
|
||||
for (int i = 0; i < SAMPLE_RATE - fc; i++) buffer[i] = buffer[i + fc];
|
||||
for (int i = 0; i < fc; i++) buffer[SAMPLE_RATE - fc + i] = frames[i];
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void TriangleCallback(void* framesOut, uint frameCount)
|
||||
{
|
||||
int fc = (int)frameCount;
|
||||
int wavelength = SAMPLE_RATE / waveFrequency;
|
||||
float* frames = (float*)framesOut;
|
||||
|
||||
// Synthesize the triangle wave
|
||||
for (int i = 0; i < fc; i++)
|
||||
{
|
||||
frames[i] = (waveIndex < wavelength / 2) ? (-1 + 2.0f * waveIndex / (wavelength / 2)) : (1 - 2.0f * (waveIndex - wavelength / 2) / (wavelength / 2));
|
||||
waveIndex++;
|
||||
|
||||
if (waveIndex >= wavelength)
|
||||
{
|
||||
waveFrequency = newWaveFrequency;
|
||||
waveIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the synthesized samples for later drawing
|
||||
for (int i = 0; i < SAMPLE_RATE - fc; i++) buffer[i] = buffer[i + fc];
|
||||
for (int i = 0; i < fc; i++) buffer[SAMPLE_RATE - fc + i] = frames[i];
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void SawtoothCallback(void* framesOut, uint frameCount)
|
||||
{
|
||||
int fc = (int)frameCount;
|
||||
int wavelength = SAMPLE_RATE / waveFrequency;
|
||||
float* frames = (float*)framesOut;
|
||||
|
||||
// Synthesize the sawtooth wave
|
||||
for (int i = 0; i < fc; i++)
|
||||
{
|
||||
frames[i] = -1 + 2.0f * waveIndex / wavelength;
|
||||
waveIndex++;
|
||||
|
||||
if (waveIndex >= wavelength)
|
||||
{
|
||||
waveFrequency = newWaveFrequency;
|
||||
waveIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the synthesized samples for later drawing
|
||||
for (int i = 0; i < SAMPLE_RATE - fc; i++) buffer[i] = buffer[i + fc];
|
||||
for (int i = 0; i < fc; i++) buffer[SAMPLE_RATE - fc + i] = frames[i];
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - stream callback");
|
||||
|
||||
SetTargetFPS(30);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new StreamCallback();
|
||||
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;
|
||||
}
|
||||
}
|
||||
222
Examples/Audio/StreamEffects.cs
Normal file
222
Examples/Audio/StreamEffects.cs
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [audio] example - stream effects
|
||||
*
|
||||
* Example complexity rating: [★★★★] 4/4
|
||||
*
|
||||
* Example originally created with raylib 4.2, last time updated with raylib 5.0
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2022-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Audio;
|
||||
|
||||
[ExcludeFromBrowser("AttachAudioStreamProcessor is unreliable on the wasm audio backend")]
|
||||
public unsafe partial class StreamEffects : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Audio / Stream Effects";
|
||||
|
||||
public string Title => "raylib [audio] example - stream effects";
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
private static float[] delayBuffer = null;
|
||||
private static uint delayBufferSize = 0;
|
||||
private static uint delayReadIndex = 2;
|
||||
private static uint delayWriteIndex = 0;
|
||||
|
||||
// Low-pass filter state (was a function-local static in the C example)
|
||||
private static readonly float[] low = { 0.0f, 0.0f };
|
||||
|
||||
private Music music;
|
||||
private float timePlayed;
|
||||
private bool pause;
|
||||
private bool enableEffectLPF;
|
||||
private bool enableEffectDelay;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
InitAudioDevice(); // Initialize audio device
|
||||
|
||||
music = LoadMusicStream("resources/audio/country.mp3");
|
||||
|
||||
// Allocate buffer for the delay effect
|
||||
delayBufferSize = 48000 * 2; // 1 second delay (device sampleRate*channels)
|
||||
delayBuffer = new float[delayBufferSize];
|
||||
delayReadIndex = 2;
|
||||
delayWriteIndex = 0;
|
||||
low[0] = 0.0f;
|
||||
low[1] = 0.0f;
|
||||
|
||||
PlayMusicStream(music);
|
||||
|
||||
timePlayed = 0.0f; // Time played normalized [0.0f..1.0f]
|
||||
pause = false; // Music playing paused
|
||||
|
||||
enableEffectLPF = false; // Enable effect low-pass-filter
|
||||
enableEffectDelay = false; // Enable effect delay (1 second)
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateMusicStream(music); // Update music buffer with new stream data
|
||||
|
||||
// Restart music playing (stop and play)
|
||||
if (IsKeyPressed(KeyboardKey.Space))
|
||||
{
|
||||
StopMusicStream(music);
|
||||
PlayMusicStream(music);
|
||||
}
|
||||
|
||||
// Pause/Resume music playing
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
pause = !pause;
|
||||
|
||||
if (pause) PauseMusicStream(music);
|
||||
else ResumeMusicStream(music);
|
||||
}
|
||||
|
||||
// Add/Remove effect: lowpass filter
|
||||
if (IsKeyPressed(KeyboardKey.F))
|
||||
{
|
||||
enableEffectLPF = !enableEffectLPF;
|
||||
if (enableEffectLPF) AttachAudioStreamProcessor(music.Stream, &AudioProcessEffectLPF);
|
||||
else DetachAudioStreamProcessor(music.Stream, &AudioProcessEffectLPF);
|
||||
}
|
||||
|
||||
// Add/Remove effect: delay
|
||||
if (IsKeyPressed(KeyboardKey.D))
|
||||
{
|
||||
enableEffectDelay = !enableEffectDelay;
|
||||
if (enableEffectDelay) AttachAudioStreamProcessor(music.Stream, &AudioProcessEffectDelay);
|
||||
else DetachAudioStreamProcessor(music.Stream, &AudioProcessEffectDelay);
|
||||
}
|
||||
|
||||
// Get normalized time played for current music stream
|
||||
timePlayed = GetMusicTimePlayed(music) / GetMusicTimeLength(music);
|
||||
|
||||
if (timePlayed > 1.0f) timePlayed = 1.0f; // Make sure time played is no longer than music
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("MUSIC SHOULD BE PLAYING!", 245, 150, 20, Color.LightGray);
|
||||
|
||||
DrawRectangle(200, 180, 400, 12, Color.LightGray);
|
||||
DrawRectangle(200, 180, (int)(timePlayed * 400.0f), 12, Color.Maroon);
|
||||
DrawRectangleLines(200, 180, 400, 12, Color.Gray);
|
||||
|
||||
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 230, 20, Color.LightGray);
|
||||
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 260, 20, Color.LightGray);
|
||||
|
||||
DrawText($"PRESS F TO TOGGLE LPF EFFECT: {(enableEffectLPF ? "ON" : "OFF")}", 200, 320, 20, Color.Gray);
|
||||
DrawText($"PRESS D TO TOGGLE DELAY EFFECT: {(enableEffectDelay ? "ON" : "OFF")}", 180, 350, 20, Color.Gray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadMusicStream(music); // Unload music stream buffers from RAM
|
||||
|
||||
CloseAudioDevice(); // Close audio device (music streaming is automatically stopped)
|
||||
|
||||
delayBuffer = null; // Free delay buffer
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//------------------------------------------------------------------------------------
|
||||
// Audio effect: lowpass filter
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void AudioProcessEffectLPF(void* buffer, uint frames)
|
||||
{
|
||||
const float cutoff = 70.0f / 44100.0f; // 70 Hz lowpass filter
|
||||
const float k = cutoff / (cutoff + 0.1591549431f); // RC filter formula
|
||||
|
||||
// Converts the buffer data before using it
|
||||
float* bufferData = (float*)buffer;
|
||||
for (uint i = 0; i < frames * 2; i += 2)
|
||||
{
|
||||
float l = bufferData[i];
|
||||
float r = bufferData[i + 1];
|
||||
|
||||
low[0] += k * (l - low[0]);
|
||||
low[1] += k * (r - low[1]);
|
||||
bufferData[i] = low[0];
|
||||
bufferData[i + 1] = low[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Audio effect: delay
|
||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||
private static void AudioProcessEffectDelay(void* buffer, uint frames)
|
||||
{
|
||||
float* bufferData = (float*)buffer;
|
||||
fixed (float* delay = delayBuffer)
|
||||
{
|
||||
for (uint i = 0; i < frames * 2; i += 2)
|
||||
{
|
||||
float leftDelay = delay[delayReadIndex++]; // ERROR: Reading buffer -> WHY??? Maybe thread related???
|
||||
float rightDelay = delay[delayReadIndex++];
|
||||
|
||||
if (delayReadIndex == delayBufferSize) delayReadIndex = 0;
|
||||
|
||||
bufferData[i] = 0.5f * bufferData[i] + 0.5f * leftDelay;
|
||||
bufferData[i + 1] = 0.5f * bufferData[i + 1] + 0.5f * rightDelay;
|
||||
|
||||
delay[delayWriteIndex++] = bufferData[i];
|
||||
delay[delayWriteIndex++] = bufferData[i + 1];
|
||||
if (delayWriteIndex == delayBufferSize) delayWriteIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [audio] example - stream effects");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new StreamEffects();
|
||||
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;
|
||||
}
|
||||
}
|
||||
379
Examples/Core/AutomationEvents.cs
Normal file
379
Examples/Core/AutomationEvents.cs
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - automation events
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 5.0, last time updated with raylib 5.0
|
||||
*
|
||||
* Example based on 2d_camera_platformer example by arvyy (@arvyy)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2023-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class AutomationEvents : IExample
|
||||
{
|
||||
private const int GRAVITY = 400;
|
||||
private const float PLAYER_JUMP_SPD = 350.0f;
|
||||
private const float PLAYER_HOR_SPD = 200.0f;
|
||||
|
||||
private const int MAX_ENVIRONMENT_ELEMENTS = 5;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Automation Events";
|
||||
|
||||
public string Title => "raylib [core] example - automation events";
|
||||
|
||||
private struct Player
|
||||
{
|
||||
public Vector2 Position;
|
||||
public float Speed;
|
||||
public bool CanJump;
|
||||
}
|
||||
|
||||
private struct EnvElement
|
||||
{
|
||||
public Rectangle Rect;
|
||||
public int Blocking;
|
||||
public Color Color;
|
||||
}
|
||||
|
||||
private Player player;
|
||||
private EnvElement[] envElements;
|
||||
private Camera2D camera;
|
||||
|
||||
private AutomationEventList aelist;
|
||||
private bool eventRecording;
|
||||
private bool eventPlaying;
|
||||
|
||||
private uint frameCounter;
|
||||
private uint playFrameCounter;
|
||||
private uint currentPlayFrame;
|
||||
|
||||
public unsafe void Init()
|
||||
{
|
||||
// Define player
|
||||
player = new Player();
|
||||
player.Position = new Vector2(400, 280);
|
||||
player.Speed = 0;
|
||||
player.CanJump = false;
|
||||
|
||||
// Define environment elements (platforms)
|
||||
envElements = new EnvElement[MAX_ENVIRONMENT_ELEMENTS]
|
||||
{
|
||||
new EnvElement { Rect = new Rectangle(0, 0, 1000, 400), Blocking = 0, Color = Color.LightGray },
|
||||
new EnvElement { Rect = new Rectangle(0, 400, 1000, 200), Blocking = 1, Color = Color.Gray },
|
||||
new EnvElement { Rect = new Rectangle(300, 200, 400, 10), Blocking = 1, Color = Color.Gray },
|
||||
new EnvElement { Rect = new Rectangle(250, 300, 100, 10), Blocking = 1, Color = Color.Gray },
|
||||
new EnvElement { Rect = new Rectangle(650, 300, 100, 10), Blocking = 1, Color = Color.Gray }
|
||||
};
|
||||
|
||||
// Define camera
|
||||
camera = new Camera2D();
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
|
||||
// Automation events
|
||||
aelist = LoadAutomationEventList((sbyte*)null); // Initialize list of automation events to record new events
|
||||
SetAutomationEventList(ref aelist);
|
||||
eventRecording = false;
|
||||
eventPlaying = false;
|
||||
|
||||
frameCounter = 0;
|
||||
playFrameCounter = 0;
|
||||
currentPlayFrame = 0;
|
||||
}
|
||||
|
||||
public unsafe void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
float deltaTime = 0.015f;//GetFrameTime();
|
||||
|
||||
// Dropped files logic
|
||||
//----------------------------------------------------------------------------------
|
||||
#if BROWSER
|
||||
// NOTE: drag-and-drop event-list loading (.txt/.rae) is not supported in the browser host.
|
||||
#else
|
||||
if (IsFileDropped())
|
||||
{
|
||||
FilePathList droppedFiles = LoadDroppedFiles();
|
||||
|
||||
// Supports loading .rgs style files (text or binary) and .png style palette images
|
||||
if (IsFileExtension(droppedFiles[0], ".txt;.rae"))
|
||||
{
|
||||
UnloadAutomationEventList(aelist);
|
||||
aelist = LoadAutomationEventList(droppedFiles[0]);
|
||||
|
||||
eventRecording = false;
|
||||
|
||||
// Reset scene state to play
|
||||
eventPlaying = true;
|
||||
playFrameCounter = 0;
|
||||
currentPlayFrame = 0;
|
||||
|
||||
player.Position = new Vector2(400, 280);
|
||||
player.Speed = 0;
|
||||
player.CanJump = false;
|
||||
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
}
|
||||
|
||||
UnloadDroppedFiles(droppedFiles); // Unload filepaths from memory
|
||||
}
|
||||
#endif
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Update player
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyDown(KeyboardKey.Left)) player.Position.X -= PLAYER_HOR_SPD * deltaTime;
|
||||
if (IsKeyDown(KeyboardKey.Right)) player.Position.X += PLAYER_HOR_SPD * deltaTime;
|
||||
if (IsKeyDown(KeyboardKey.Space) && player.CanJump)
|
||||
{
|
||||
player.Speed = -PLAYER_JUMP_SPD;
|
||||
player.CanJump = false;
|
||||
}
|
||||
|
||||
int hitObstacle = 0;
|
||||
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
|
||||
{
|
||||
EnvElement element = envElements[i];
|
||||
if (element.Blocking != 0 &&
|
||||
element.Rect.X <= player.Position.X &&
|
||||
element.Rect.X + element.Rect.Width >= player.Position.X &&
|
||||
element.Rect.Y >= player.Position.Y &&
|
||||
element.Rect.Y <= player.Position.Y + player.Speed * deltaTime)
|
||||
{
|
||||
hitObstacle = 1;
|
||||
player.Speed = 0.0f;
|
||||
player.Position.Y = element.Rect.Y;
|
||||
}
|
||||
}
|
||||
|
||||
if (hitObstacle == 0)
|
||||
{
|
||||
player.Position.Y += player.Speed * deltaTime;
|
||||
player.Speed += GRAVITY * deltaTime;
|
||||
player.CanJump = false;
|
||||
}
|
||||
else player.CanJump = true;
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
// Reset game state
|
||||
player.Position = new Vector2(400, 280);
|
||||
player.Speed = 0;
|
||||
player.CanJump = false;
|
||||
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Events playing
|
||||
// NOTE: Logic must be before Camera update because it depends on mouse-wheel value,
|
||||
// that can be set by the played event... but some other inputs could be affected
|
||||
//----------------------------------------------------------------------------------
|
||||
if (eventPlaying)
|
||||
{
|
||||
// NOTE: Multiple events could be executed in a single frame
|
||||
while (playFrameCounter == aelist.Events[currentPlayFrame].Frame)
|
||||
{
|
||||
PlayAutomationEvent(aelist.Events[currentPlayFrame]);
|
||||
currentPlayFrame++;
|
||||
|
||||
if (currentPlayFrame == aelist.Count)
|
||||
{
|
||||
eventPlaying = false;
|
||||
currentPlayFrame = 0;
|
||||
playFrameCounter = 0;
|
||||
|
||||
TraceLog(TraceLogLevel.Info, "FINISH PLAYING!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
playFrameCounter++;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Update camera
|
||||
//----------------------------------------------------------------------------------
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000;
|
||||
|
||||
// WARNING: On event replay, mouse-wheel internal value is set
|
||||
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
|
||||
if (camera.Zoom > 3.0f) camera.Zoom = 3.0f;
|
||||
else if (camera.Zoom < 0.25f) camera.Zoom = 0.25f;
|
||||
|
||||
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
|
||||
{
|
||||
EnvElement element = envElements[i];
|
||||
minX = MathF.Min(element.Rect.X, minX);
|
||||
maxX = MathF.Max(element.Rect.X + element.Rect.Width, maxX);
|
||||
minY = MathF.Min(element.Rect.Y, minY);
|
||||
maxY = MathF.Max(element.Rect.Y + element.Rect.Height, maxY);
|
||||
}
|
||||
|
||||
Vector2 max = GetWorldToScreen2D(new Vector2(maxX, maxY), camera);
|
||||
Vector2 min = GetWorldToScreen2D(new Vector2(minX, minY), camera);
|
||||
|
||||
if (max.X < screenWidth) camera.Offset.X = screenWidth - (max.X - (float)screenWidth / 2);
|
||||
if (max.Y < screenHeight) camera.Offset.Y = screenHeight - (max.Y - (float)screenHeight / 2);
|
||||
if (min.X > 0) camera.Offset.X = (float)screenWidth / 2 - min.X;
|
||||
if (min.Y > 0) camera.Offset.Y = (float)screenHeight / 2 - min.Y;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Events management
|
||||
if (IsKeyPressed(KeyboardKey.S)) // Toggle events recording
|
||||
{
|
||||
if (!eventPlaying)
|
||||
{
|
||||
if (eventRecording)
|
||||
{
|
||||
StopAutomationEventRecording();
|
||||
eventRecording = false;
|
||||
|
||||
ExportAutomationEventList(aelist, "automation.rae");
|
||||
|
||||
TraceLog(TraceLogLevel.Info, $"RECORDED FRAMES: {aelist.Count}");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetAutomationEventBaseFrame(180);
|
||||
StartAutomationEventRecording();
|
||||
eventRecording = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.A)) // Toggle events playing (WARNING: Starts next frame)
|
||||
{
|
||||
if (!eventRecording && (aelist.Count > 0))
|
||||
{
|
||||
// Reset scene state to play
|
||||
eventPlaying = true;
|
||||
playFrameCounter = 0;
|
||||
currentPlayFrame = 0;
|
||||
|
||||
player.Position = new Vector2(400, 280);
|
||||
player.Speed = 0;
|
||||
player.CanJump = false;
|
||||
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventRecording || eventPlaying) frameCounter++;
|
||||
else frameCounter = 0;
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.LightGray);
|
||||
|
||||
BeginMode2D(camera);
|
||||
|
||||
// Draw environment elements
|
||||
for (int i = 0; i < MAX_ENVIRONMENT_ELEMENTS; i++)
|
||||
{
|
||||
DrawRectangleRec(envElements[i].Rect, envElements[i].Color);
|
||||
}
|
||||
|
||||
// Draw player rectangle
|
||||
DrawRectangleRec(new Rectangle(player.Position.X - 20, player.Position.Y - 40, 40, 40), Color.Red);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
// Draw game controls
|
||||
DrawRectangle(10, 10, 290, 145, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 290, 145, Fade(Color.Blue, 0.8f));
|
||||
|
||||
DrawText("Controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- RIGHT | LEFT: Player movement", 30, 40, 10, Color.DarkGray);
|
||||
DrawText("- SPACE: Player jump", 30, 60, 10, Color.DarkGray);
|
||||
DrawText("- R: Reset game state", 30, 80, 10, Color.DarkGray);
|
||||
|
||||
DrawText("- S: START/STOP RECORDING INPUT EVENTS", 30, 110, 10, Color.Black);
|
||||
DrawText("- A: REPLAY LAST RECORDED INPUT EVENTS", 30, 130, 10, Color.Black);
|
||||
|
||||
// Draw automation events recording indicator
|
||||
if (eventRecording)
|
||||
{
|
||||
DrawRectangle(10, 160, 290, 30, Fade(Color.Red, 0.3f));
|
||||
DrawRectangleLines(10, 160, 290, 30, Fade(Color.Maroon, 0.8f));
|
||||
DrawCircle(30, 175, 10, Color.Maroon);
|
||||
|
||||
if (((frameCounter / 15) % 2) == 1) DrawText($"RECORDING EVENTS... [{aelist.Count}]", 50, 170, 10, Color.Maroon);
|
||||
}
|
||||
else if (eventPlaying)
|
||||
{
|
||||
DrawRectangle(10, 160, 290, 30, Fade(Color.Lime, 0.3f));
|
||||
DrawRectangleLines(10, 160, 290, 30, Fade(Color.DarkGreen, 0.8f));
|
||||
DrawTriangle(new Vector2(20, 155 + 10), new Vector2(20, 155 + 30), new Vector2(40, 155 + 20), Color.DarkGreen);
|
||||
|
||||
if (((frameCounter / 15) % 2) == 1) DrawText($"PLAYING RECORDED EVENTS... [{currentPlayFrame}]", 50, 170, 10, Color.DarkGreen);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
UnloadAutomationEventList(aelist);
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - automation events");
|
||||
|
||||
var game = new AutomationEvents();
|
||||
game.Init();
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,17 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Basic window
|
||||
* raylib [core] example - basic screen manager
|
||||
*
|
||||
* Welcome to raylib!
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* To test examples, just press F6 and execute raylib_compile_execute script
|
||||
* Note that compiled executable is placed in the same folder as .c file
|
||||
* NOTE: This example illustrates a very simple screen manager based on a states machines
|
||||
*
|
||||
* You can find all basic examples on C:\raylib\raylib\examples folder or
|
||||
* raylib official webpage: www.raylib.com
|
||||
* Example originally created with raylib 4.0, last time updated with raylib 4.0
|
||||
*
|
||||
* Enjoy using raylib. :)
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* This example has been created using raylib 1.0 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
*
|
||||
* Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2021-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -23,7 +19,7 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
enum GameScreen
|
||||
internal enum GameScreen
|
||||
{
|
||||
Logo = 0,
|
||||
Title,
|
||||
|
|
@ -31,143 +27,160 @@ enum GameScreen
|
|||
Ending
|
||||
}
|
||||
|
||||
public class BasicScreenManager
|
||||
public partial class BasicScreenManager : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Basic Screen Manager";
|
||||
|
||||
public string Title => "raylib [core] example - basic screen manager";
|
||||
|
||||
private GameScreen currentScreen;
|
||||
private int framesCounter;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
currentScreen = GameScreen.Logo;
|
||||
|
||||
// TODO: Initialize all required variables and load all required data here!
|
||||
|
||||
framesCounter = 0; // Useful to count frames
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
switch (currentScreen)
|
||||
{
|
||||
case GameScreen.Logo:
|
||||
{
|
||||
// TODO: Update LOGO screen variables here!
|
||||
|
||||
framesCounter++; // Count frames
|
||||
|
||||
// Wait for 2 seconds (120 frames) before jumping to TITLE screen
|
||||
if (framesCounter > 120)
|
||||
{
|
||||
currentScreen = GameScreen.Title;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Title:
|
||||
{
|
||||
// TODO: Update TITLE screen variables here!
|
||||
|
||||
// Press enter to change to GAMEPLAY screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Gameplay;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Gameplay:
|
||||
{
|
||||
// TODO: Update GAMEPLAY screen variables here!
|
||||
|
||||
// Press enter to change to ENDING screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Ending;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Ending:
|
||||
{
|
||||
// TODO: Update ENDING screen variables here!
|
||||
|
||||
// Press enter to return to TITLE screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Title;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
switch (currentScreen)
|
||||
{
|
||||
case GameScreen.Logo:
|
||||
{
|
||||
// TODO: Draw LOGO screen here!
|
||||
DrawText("LOGO SCREEN", 20, 20, 40, Color.LightGray);
|
||||
DrawText("WAIT for 2 SECONDS...", 290, 220, 20, Color.Gray);
|
||||
}
|
||||
break;
|
||||
case GameScreen.Title:
|
||||
{
|
||||
// TODO: Draw TITLE screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Green);
|
||||
DrawText("TITLE SCREEN", 20, 20, 40, Color.DarkGreen);
|
||||
DrawText("PRESS ENTER or TAP to JUMP to GAMEPLAY SCREEN", 120, 220, 20, Color.DarkGreen);
|
||||
}
|
||||
break;
|
||||
case GameScreen.Gameplay:
|
||||
{
|
||||
// TODO: Draw GAMEPLAY screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Purple);
|
||||
DrawText("GAMEPLAY SCREEN", 20, 20, 40, Color.Maroon);
|
||||
DrawText("PRESS ENTER or TAP to JUMP to ENDING SCREEN", 130, 220, 20, Color.Maroon);
|
||||
|
||||
}
|
||||
break;
|
||||
case GameScreen.Ending:
|
||||
{
|
||||
// TODO: Draw ENDING screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Blue);
|
||||
DrawText("ENDING SCREEN", 20, 20, 40, Color.DarkBlue);
|
||||
DrawText("PRESS ENTER or TAP to RETURN to TITLE SCREEN", 120, 220, 20, Color.DarkBlue);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
// TODO: Unload all loaded data (textures, fonts, audio) here!
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic screen manager");
|
||||
|
||||
GameScreen currentScreen = GameScreen.Logo;
|
||||
|
||||
// TODO: Initialize all required variables and load all required data here!
|
||||
|
||||
// Useful to count frames
|
||||
int framesCounter = 0;
|
||||
|
||||
SetTargetFPS(60); // Set desired framerate (frames-per-second)
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new BasicScreenManager();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
switch (currentScreen)
|
||||
{
|
||||
case GameScreen.Logo:
|
||||
{
|
||||
// TODO: Update LOGO screen variables here!
|
||||
|
||||
// Count frames
|
||||
framesCounter++;
|
||||
|
||||
// Wait for 2 seconds (120 frames) before jumping to TITLE screen
|
||||
if (framesCounter > 120)
|
||||
{
|
||||
currentScreen = GameScreen.Title;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Title:
|
||||
{
|
||||
// TODO: Update TITLE screen variables here!
|
||||
|
||||
// Press enter to change to GAMEPLAY screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Gameplay;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Gameplay:
|
||||
{
|
||||
// TODO: Update GAMEPLAY screen variables here!
|
||||
|
||||
// Press enter to change to ENDING screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Ending;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GameScreen.Ending:
|
||||
{
|
||||
// TODO: Update ENDING screen variables here!
|
||||
|
||||
// Press enter to return to TITLE screen
|
||||
if (IsKeyPressed(KeyboardKey.Enter) || IsGestureDetected(Gesture.Tap))
|
||||
{
|
||||
currentScreen = GameScreen.Title;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
switch (currentScreen)
|
||||
{
|
||||
case GameScreen.Logo:
|
||||
{
|
||||
// TODO: Draw LOGO screen here!
|
||||
DrawText("LOGO SCREEN", 20, 20, 40, Color.LightGray);
|
||||
DrawText("WAIT for 2 SECONDS...", 290, 220, 20, Color.Gray);
|
||||
|
||||
}
|
||||
break;
|
||||
case GameScreen.Title:
|
||||
{
|
||||
// TODO: Draw TITLE screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Green);
|
||||
DrawText("TITLE SCREEN", 20, 20, 40, Color.DarkGreen);
|
||||
DrawText("PRESS ENTER or TAP to JUMP to GAMEPLAY SCREEN", 120, 220, 20, Color.DarkGreen);
|
||||
|
||||
}
|
||||
break;
|
||||
case GameScreen.Gameplay:
|
||||
{
|
||||
// TODO: Draw GAMEPLAY screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Purple);
|
||||
DrawText("GAMEPLAY SCREEN", 20, 20, 40, Color.Maroon);
|
||||
DrawText("PRESS ENTER or TAP to JUMP to ENDING SCREEN", 130, 220, 20, Color.Maroon);
|
||||
|
||||
}
|
||||
break;
|
||||
case GameScreen.Ending:
|
||||
{
|
||||
// TODO: Draw ENDING screen here!
|
||||
DrawRectangle(0, 0, screenWidth, screenHeight, Color.Blue);
|
||||
DrawText("ENDING SCREEN", 20, 20, 40, Color.DarkBlue);
|
||||
DrawText("PRESS ENTER or TAP to RETURN to TITLE SCREEN", 120, 220, 20, Color.DarkBlue);
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// TODO: Unload all loaded data (textures, fonts, audio) here!
|
||||
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -33,43 +33,56 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class BasicWindow
|
||||
public partial class BasicWindow : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Basic Window";
|
||||
|
||||
public string Title => "raylib [core] example - basic window";
|
||||
|
||||
public void Init()
|
||||
{
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Congrats! You created your first window!", 190, 200, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
|
||||
var game = new BasicWindow();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// TODO: Update your variables here
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
DrawText("Congrats! You created your first window!", 190, 200, 20, Color.LightGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,31 +13,37 @@
|
|||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Camera2dDemo
|
||||
public partial class Camera2dDemo : IExample
|
||||
{
|
||||
public const int MaxBuildings = 100;
|
||||
|
||||
public static int Main()
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Camera 2D Demo";
|
||||
|
||||
public string Title => "raylib [core] example - 2d camera";
|
||||
|
||||
private Rectangle player;
|
||||
private Rectangle[] buildings;
|
||||
private Color[] buildColors;
|
||||
private Camera2D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
player = new(400, 280, 40, 40);
|
||||
buildings = new Rectangle[MaxBuildings];
|
||||
buildColors = new Color[MaxBuildings];
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
|
||||
var spacing = 0;
|
||||
|
||||
Rectangle player = new(400, 280, 40, 40);
|
||||
Rectangle[] buildings = new Rectangle[MaxBuildings];
|
||||
Color[] buildColors = new Color[MaxBuildings];
|
||||
|
||||
int spacing = 0;
|
||||
|
||||
for (int i = 0; i < MaxBuildings; i++)
|
||||
for (var i = 0; i < MaxBuildings; i++)
|
||||
{
|
||||
buildings[i].Width = GetRandomValue(50, 200);
|
||||
buildings[i].Height = GetRandomValue(100, 800);
|
||||
|
|
@ -54,124 +60,139 @@ public class Camera2dDemo
|
|||
);
|
||||
}
|
||||
|
||||
Camera2D camera = new();
|
||||
camera = new();
|
||||
camera.Target = new Vector2(player.X + 20, player.Y + 20);
|
||||
camera.Offset = new Vector2(screenWidth / 2, screenHeight / 2);
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
}
|
||||
|
||||
SetTargetFPS(60);
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Player movement
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
player.X += 2;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
player.X -= 2;
|
||||
}
|
||||
|
||||
// Camera target follows player
|
||||
camera.Target = new Vector2(player.X + 20, player.Y + 20);
|
||||
|
||||
// Camera rotation controls
|
||||
if (IsKeyDown(KeyboardKey.A))
|
||||
{
|
||||
camera.Rotation--;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
camera.Rotation++;
|
||||
}
|
||||
|
||||
// Limit camera rotation to 80 degrees (-40 to 40)
|
||||
if (camera.Rotation > 40)
|
||||
{
|
||||
camera.Rotation = 40;
|
||||
}
|
||||
else if (camera.Rotation < -40)
|
||||
{
|
||||
camera.Rotation = -40;
|
||||
}
|
||||
|
||||
// Camera zoom controls
|
||||
// Uses log scaling to provide consistent zoom speed
|
||||
camera.Zoom = MathF.Exp(MathF.Log(camera.Zoom) + ((float)GetMouseWheelMove() * 0.1f));
|
||||
|
||||
if (camera.Zoom > 3.0f)
|
||||
{
|
||||
camera.Zoom = 3.0f;
|
||||
}
|
||||
else if (camera.Zoom < 0.1f)
|
||||
{
|
||||
camera.Zoom = 0.1f;
|
||||
}
|
||||
|
||||
// Camera reset (zoom and rotation)
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
camera.Zoom = 1.0f;
|
||||
camera.Rotation = 0.0f;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(camera);
|
||||
|
||||
DrawRectangle(-6000, 320, 13000, 8000, Color.DarkGray);
|
||||
|
||||
for (var i = 0; i < MaxBuildings; i++)
|
||||
{
|
||||
DrawRectangleRec(buildings[i], buildColors[i]);
|
||||
}
|
||||
|
||||
DrawRectangleRec(player, Color.Red);
|
||||
|
||||
DrawLine((int)camera.Target.X, -screenHeight * 10, (int)camera.Target.X, screenHeight * 10, Color.Green);
|
||||
DrawLine(-screenWidth * 10, (int)camera.Target.Y, screenWidth * 10, (int)camera.Target.Y, Color.Green);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
DrawText("SCREEN AREA", 640, 10, 20, Color.Red);
|
||||
|
||||
DrawRectangle(0, 0, screenWidth, 5, Color.Red);
|
||||
DrawRectangle(0, 5, 5, screenHeight - 10, Color.Red);
|
||||
DrawRectangle(screenWidth - 5, 5, 5, screenHeight - 10, Color.Red);
|
||||
DrawRectangle(0, screenHeight - 5, screenWidth, 5, Color.Red);
|
||||
|
||||
DrawRectangle(10, 10, 250, 113, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 250, 113, Color.Blue);
|
||||
|
||||
DrawText("Free 2D camera controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Right/Left to move player", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- A / S to Rotate", 40, 80, 10, Color.DarkGray);
|
||||
DrawText("- R to reset Zoom and Rotation", 40, 100, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera2dDemo();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Player movement
|
||||
if (IsKeyDown(KeyboardKey.Right))
|
||||
{
|
||||
player.X += 2;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
player.X -= 2;
|
||||
}
|
||||
|
||||
// Camera3D target follows player
|
||||
camera.Target = new Vector2(player.X + 20, player.Y + 20);
|
||||
|
||||
// Camera3D rotation controls
|
||||
if (IsKeyDown(KeyboardKey.A))
|
||||
{
|
||||
camera.Rotation--;
|
||||
}
|
||||
else if (IsKeyDown(KeyboardKey.S))
|
||||
{
|
||||
camera.Rotation++;
|
||||
}
|
||||
|
||||
// Limit camera rotation to 80 degrees (-40 to 40)
|
||||
if (camera.Rotation > 40)
|
||||
{
|
||||
camera.Rotation = 40;
|
||||
}
|
||||
else if (camera.Rotation < -40)
|
||||
{
|
||||
camera.Rotation = -40;
|
||||
}
|
||||
|
||||
// Camera3D zoom controls
|
||||
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
|
||||
|
||||
if (camera.Zoom > 3.0f)
|
||||
{
|
||||
camera.Zoom = 3.0f;
|
||||
}
|
||||
else if (camera.Zoom < 0.1f)
|
||||
{
|
||||
camera.Zoom = 0.1f;
|
||||
}
|
||||
|
||||
// Camera3D reset (zoom and rotation)
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
camera.Zoom = 1.0f;
|
||||
camera.Rotation = 0.0f;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(camera);
|
||||
|
||||
DrawRectangle(-6000, 320, 13000, 8000, Color.DarkGray);
|
||||
|
||||
for (int i = 0; i < MaxBuildings; i++)
|
||||
{
|
||||
DrawRectangleRec(buildings[i], buildColors[i]);
|
||||
}
|
||||
|
||||
DrawRectangleRec(player, Color.Red);
|
||||
|
||||
DrawRectangle((int)camera.Target.X, -500, 1, (int)(screenHeight * 4), Color.Green);
|
||||
DrawLine(
|
||||
(int)(-screenWidth * 10),
|
||||
(int)camera.Target.Y,
|
||||
(int)(screenWidth * 10),
|
||||
(int)camera.Target.Y,
|
||||
Color.Green
|
||||
);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
DrawText("SCREEN AREA", 640, 10, 20, Color.Red);
|
||||
|
||||
DrawRectangle(0, 0, (int)screenWidth, 5, Color.Red);
|
||||
DrawRectangle(0, 5, 5, (int)screenHeight - 10, Color.Red);
|
||||
DrawRectangle((int)screenWidth - 5, 5, 5, (int)screenHeight - 10, Color.Red);
|
||||
DrawRectangle(0, (int)screenHeight - 5, (int)screenWidth, 5, Color.Red);
|
||||
|
||||
DrawRectangle(10, 10, 250, 113, ColorAlpha(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 250, 113, Color.Blue);
|
||||
|
||||
DrawText("Free 2d camera controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Right/Left to move Offset", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- A / S to Rotate", 40, 80, 10, Color.DarkGray);
|
||||
DrawText("- R to reset Zoom and Rotation", 40, 100, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
184
Examples/Core/Camera2dMouseZoom.cs
Normal file
184
Examples/Core/Camera2dMouseZoom.cs
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - 2d camera mouse zoom
|
||||
*
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Example originally created with raylib 4.2, last time updated with raylib 4.2
|
||||
*
|
||||
* Example contributed by Jeffery Myers (@JeffM2501) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2022-2025 Jeffery Myers (@JeffM2501)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class Camera2dMouseZoom : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Camera 2D Mouse Zoom";
|
||||
|
||||
public string Title => "raylib [core] example - 2d camera mouse zoom";
|
||||
|
||||
private Camera2D camera;
|
||||
private int zoomMode; // 0-Mouse Wheel, 1-Mouse Move
|
||||
|
||||
public void Init()
|
||||
{
|
||||
camera = new Camera2D();
|
||||
camera.Zoom = 1.0f;
|
||||
|
||||
zoomMode = 0;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
zoomMode = 0;
|
||||
}
|
||||
else if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
zoomMode = 1;
|
||||
}
|
||||
|
||||
// Translate based on mouse right click
|
||||
if (IsMouseButtonDown(MouseButton.Left))
|
||||
{
|
||||
Vector2 delta = GetMouseDelta();
|
||||
delta = Vector2Scale(delta, -1.0f / camera.Zoom);
|
||||
camera.Target = Vector2Add(camera.Target, delta);
|
||||
}
|
||||
|
||||
if (zoomMode == 0)
|
||||
{
|
||||
// Zoom based on mouse wheel
|
||||
float wheel = GetMouseWheelMove();
|
||||
if (wheel != 0)
|
||||
{
|
||||
// Get the world point that is under the mouse
|
||||
Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera);
|
||||
|
||||
// Set the offset to where the mouse is
|
||||
camera.Offset = GetMousePosition();
|
||||
|
||||
// Set the target to match, so that the camera maps the world space point
|
||||
// under the cursor to the screen space point under the cursor at any zoom
|
||||
camera.Target = mouseWorldPos;
|
||||
|
||||
// Zoom increment
|
||||
// Uses log scaling to provide consistent zoom speed
|
||||
float scale = 0.2f * wheel;
|
||||
camera.Zoom = Clamp(MathF.Exp(MathF.Log(camera.Zoom) + scale), 0.125f, 64.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Zoom based on mouse right click
|
||||
if (IsMouseButtonPressed(MouseButton.Right))
|
||||
{
|
||||
// Get the world point that is under the mouse
|
||||
Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera);
|
||||
|
||||
// Set the offset to where the mouse is
|
||||
camera.Offset = GetMousePosition();
|
||||
|
||||
// Set the target to match, so that the camera maps the world space point
|
||||
// under the cursor to the screen space point under the cursor at any zoom
|
||||
camera.Target = mouseWorldPos;
|
||||
}
|
||||
|
||||
if (IsMouseButtonDown(MouseButton.Right))
|
||||
{
|
||||
// Zoom increment
|
||||
// Uses log scaling to provide consistent zoom speed
|
||||
float deltaX = GetMouseDelta().X;
|
||||
float scale = 0.005f * deltaX;
|
||||
camera.Zoom = Clamp(MathF.Exp(MathF.Log(camera.Zoom) + scale), 0.125f, 64.0f);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode2D(camera);
|
||||
// Draw the 3d grid, rotated 90 degrees and centered around 0,0
|
||||
// just so we have something in the XY plane
|
||||
Rlgl.PushMatrix();
|
||||
Rlgl.Translatef(0, 25 * 50, 0);
|
||||
Rlgl.Rotatef(90, 1, 0, 0);
|
||||
DrawGrid(100, 50);
|
||||
Rlgl.PopMatrix();
|
||||
|
||||
// Draw a reference circle
|
||||
DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, 50, Color.Maroon);
|
||||
EndMode2D();
|
||||
|
||||
// Draw mouse reference
|
||||
//Vector2 mousePos = GetWorldToScreen2D(GetMousePosition(), camera)
|
||||
DrawCircleV(GetMousePosition(), 4, Color.DarkGray);
|
||||
DrawTextEx(GetFontDefault(), $"[{GetMouseX()}, {GetMouseY()}]",
|
||||
Vector2Add(GetMousePosition(), new Vector2(-44, -24)), 20, 2, Color.Black);
|
||||
|
||||
DrawText("[1][2] Select mouse zoom mode (Wheel or Move)", 20, 20, 20, Color.DarkGray);
|
||||
if (zoomMode == 0)
|
||||
{
|
||||
DrawText("Mouse left button drag to move, mouse wheel to zoom", 20, 50, 20, Color.DarkGray);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawText("Mouse left button drag to move, mouse press and move to zoom", 20, 50, 20, Color.DarkGray);
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera mouse zoom");
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera2dMouseZoom();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,16 @@
|
|||
*
|
||||
* raylib [core] example - 2d camera platformer
|
||||
*
|
||||
* This example has been created using raylib 2.5 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 2.5, last time updated with raylib 3.0
|
||||
*
|
||||
* Example contributed by arvyy (@arvyy) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Copyright (c) 2019 arvyy (@arvyy)
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2019-2025 arvyy (@arvyy)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -18,20 +22,27 @@ using static Raylib_cs.Raymath;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Camera2dPlatformer
|
||||
public partial class Camera2dPlatformer : IExample
|
||||
{
|
||||
const int G = 400;
|
||||
const float PlayerJumpSpeed = 350.0f;
|
||||
const float PlayerHorSpeed = 200.0f;
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
struct Player
|
||||
private const int G = 400;
|
||||
private const float PlayerJumpSpeed = 350.0f;
|
||||
private const float PlayerHorSpeed = 200.0f;
|
||||
|
||||
public string Name => "Core / 2D Camera Platformer";
|
||||
|
||||
public string Title => "raylib [core] example - 2d camera platformer";
|
||||
|
||||
private struct Player
|
||||
{
|
||||
public Vector2 Position;
|
||||
public float Speed;
|
||||
public bool CanJump;
|
||||
}
|
||||
|
||||
struct EnvItem
|
||||
private struct EnvItem
|
||||
{
|
||||
public Rectangle Rect;
|
||||
public int Blocking;
|
||||
|
|
@ -45,7 +56,7 @@ public class Camera2dPlatformer
|
|||
}
|
||||
}
|
||||
|
||||
delegate void CameraUpdaterCallback(
|
||||
private delegate void CameraUpdaterCallback(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -54,21 +65,22 @@ public class Camera2dPlatformer
|
|||
int height
|
||||
);
|
||||
|
||||
public static int Main()
|
||||
private Player player;
|
||||
private EnvItem[] envItems;
|
||||
private Camera2D camera;
|
||||
private CameraUpdaterCallback[] cameraUpdaters;
|
||||
private int cameraOption;
|
||||
private int cameraUpdatersLength;
|
||||
private string[] cameraDescriptions;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
|
||||
|
||||
Player player = new();
|
||||
player = new();
|
||||
player.Position = new Vector2(400, 280);
|
||||
player.Speed = 0;
|
||||
player.CanJump = false;
|
||||
|
||||
EnvItem[] envItems = new EnvItem[]
|
||||
envItems = new EnvItem[]
|
||||
{
|
||||
new EnvItem(new Rectangle(0, 0, 1000, 400), 0, Color.LightGray),
|
||||
new EnvItem(new Rectangle(0, 400, 1000, 200), 1, Color.Gray),
|
||||
|
|
@ -77,14 +89,14 @@ public class Camera2dPlatformer
|
|||
new EnvItem(new Rectangle(650, 300, 100, 10), 1, Color.Gray)
|
||||
};
|
||||
|
||||
Camera2D camera = new();
|
||||
camera = new();
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(screenWidth / 2, screenHeight / 2);
|
||||
camera.Offset = new Vector2(screenWidth / 2.0f, screenHeight / 2.0f);
|
||||
camera.Rotation = 0.0f;
|
||||
camera.Zoom = 1.0f;
|
||||
|
||||
// Store callbacks to the multiple update camera functions
|
||||
CameraUpdaterCallback[] cameraUpdaters = new CameraUpdaterCallback[]
|
||||
// Store pointers to the multiple update camera functions
|
||||
cameraUpdaters = new CameraUpdaterCallback[]
|
||||
{
|
||||
UpdateCameraCenter,
|
||||
UpdateCameraCenterInsideMap,
|
||||
|
|
@ -93,93 +105,89 @@ public class Camera2dPlatformer
|
|||
UpdateCameraPlayerBoundsPush
|
||||
};
|
||||
|
||||
int cameraOption = 0;
|
||||
int cameraUpdatersLength = cameraUpdaters.Length;
|
||||
cameraOption = 0;
|
||||
cameraUpdatersLength = cameraUpdaters.Length;
|
||||
|
||||
string[] cameraDescriptions = new string[]{
|
||||
cameraDescriptions = new string[]{
|
||||
"Follow player center",
|
||||
"Follow player center, but clamp to map edges",
|
||||
"Follow player center; smoothed",
|
||||
"Follow player center horizontally; update player center vertically after landing",
|
||||
"Player push camera on getting too close to screen edge"
|
||||
};
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
float deltaTime = GetFrameTime();
|
||||
|
||||
UpdatePlayer(ref player, envItems, deltaTime);
|
||||
|
||||
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
|
||||
|
||||
if (camera.Zoom > 3.0f)
|
||||
{
|
||||
camera.Zoom = 3.0f;
|
||||
}
|
||||
else if (camera.Zoom < 0.25f)
|
||||
{
|
||||
camera.Zoom = 0.25f;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
camera.Zoom = 1.0f;
|
||||
player.Position = new Vector2(400, 280);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.C))
|
||||
{
|
||||
cameraOption = (cameraOption + 1) % cameraUpdatersLength;
|
||||
}
|
||||
|
||||
// Call update camera function by its pointer
|
||||
cameraUpdaters[cameraOption](ref camera, ref player, envItems, deltaTime, screenWidth, screenHeight);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.LightGray);
|
||||
|
||||
BeginMode2D(camera);
|
||||
|
||||
for (int i = 0; i < envItems.Length; i++)
|
||||
{
|
||||
DrawRectangleRec(envItems[i].Rect, envItems[i].Color);
|
||||
}
|
||||
|
||||
Rectangle playerRect = new(player.Position.X - 20, player.Position.Y - 40, 40, 40);
|
||||
DrawRectangleRec(playerRect, Color.Red);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
DrawText("Controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Right/Left to move", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Space to jump", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel to Zoom in-out, R to reset zoom", 40, 80, 10, Color.DarkGray);
|
||||
DrawText("- C to change camera mode", 40, 100, 10, Color.DarkGray);
|
||||
DrawText("Current camera mode:", 20, 120, 10, Color.Black);
|
||||
DrawText(cameraDescriptions[cameraOption], 40, 140, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void UpdatePlayer(ref Player player, EnvItem[] envItems, float delta)
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
var deltaTime = GetFrameTime();
|
||||
|
||||
UpdatePlayer(ref player, envItems, deltaTime);
|
||||
|
||||
camera.Zoom += ((float)GetMouseWheelMove() * 0.05f);
|
||||
|
||||
if (camera.Zoom > 3.0f)
|
||||
{
|
||||
camera.Zoom = 3.0f;
|
||||
}
|
||||
else if (camera.Zoom < 0.25f)
|
||||
{
|
||||
camera.Zoom = 0.25f;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.R))
|
||||
{
|
||||
camera.Zoom = 1.0f;
|
||||
player.Position = new Vector2(400, 280);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.C))
|
||||
{
|
||||
cameraOption = (cameraOption + 1) % cameraUpdatersLength;
|
||||
}
|
||||
|
||||
// Call update camera function by its pointer
|
||||
cameraUpdaters[cameraOption](ref camera, ref player, envItems, deltaTime, screenWidth, screenHeight);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.LightGray);
|
||||
|
||||
BeginMode2D(camera);
|
||||
|
||||
for (var i = 0; i < envItems.Length; i++)
|
||||
{
|
||||
DrawRectangleRec(envItems[i].Rect, envItems[i].Color);
|
||||
}
|
||||
|
||||
Rectangle playerRect = new(player.Position.X - 20, player.Position.Y - 40, 40.0f, 40.0f);
|
||||
DrawRectangleRec(playerRect, Color.Red);
|
||||
|
||||
DrawCircleV(player.Position, 5.0f, Color.Gold);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
DrawText("Controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Right/Left to move", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Space to jump", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel to Zoom in-out", 40, 80, 10, Color.DarkGray);
|
||||
DrawText("- R to reset position + zoom", 40, 100, 10, Color.DarkGray);
|
||||
DrawText("- C to change camera mode", 40, 120, 10, Color.DarkGray);
|
||||
DrawText("Current camera mode:", 20, 140, 10, Color.Black);
|
||||
DrawText(cameraDescriptions[cameraOption], 40, 160, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
private static void UpdatePlayer(ref Player player, EnvItem[] envItems, float delta)
|
||||
{
|
||||
if (IsKeyDown(KeyboardKey.Left))
|
||||
{
|
||||
|
|
@ -197,11 +205,11 @@ public class Camera2dPlatformer
|
|||
player.CanJump = false;
|
||||
}
|
||||
|
||||
int hitObstacle = 0;
|
||||
for (int i = 0; i < envItems.Length; i++)
|
||||
var hitObstacle = 0;
|
||||
for (var i = 0; i < envItems.Length; i++)
|
||||
{
|
||||
EnvItem ei = envItems[i];
|
||||
Vector2 p = player.Position;
|
||||
var ei = envItems[i];
|
||||
var p = player.Position;
|
||||
if (ei.Blocking != 0 &&
|
||||
ei.Rect.X <= p.X &&
|
||||
ei.Rect.X + ei.Rect.Width >= p.X &&
|
||||
|
|
@ -211,6 +219,7 @@ public class Camera2dPlatformer
|
|||
hitObstacle = 1;
|
||||
player.Speed = 0.0f;
|
||||
player.Position.Y = ei.Rect.Y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -226,7 +235,7 @@ public class Camera2dPlatformer
|
|||
}
|
||||
}
|
||||
|
||||
static void UpdateCameraCenter(
|
||||
private static void UpdateCameraCenter(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -235,11 +244,11 @@ public class Camera2dPlatformer
|
|||
int height
|
||||
)
|
||||
{
|
||||
camera.Offset = new Vector2(width / 2, height / 2);
|
||||
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
|
||||
camera.Target = player.Position;
|
||||
}
|
||||
|
||||
static void UpdateCameraCenterInsideMap(
|
||||
private static void UpdateCameraCenterInsideMap(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -248,43 +257,43 @@ public class Camera2dPlatformer
|
|||
int height)
|
||||
{
|
||||
camera.Target = player.Position;
|
||||
camera.Offset = new Vector2(width / 2, height / 2);
|
||||
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
|
||||
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000;
|
||||
|
||||
for (int i = 0; i < envItems.Length; i++)
|
||||
for (var i = 0; i < envItems.Length; i++)
|
||||
{
|
||||
EnvItem ei = envItems[i];
|
||||
var ei = envItems[i];
|
||||
minX = Math.Min(ei.Rect.X, minX);
|
||||
maxX = Math.Max(ei.Rect.X + ei.Rect.Width, maxX);
|
||||
minY = Math.Min(ei.Rect.Y, minY);
|
||||
maxY = Math.Max(ei.Rect.Y + ei.Rect.Height, maxY);
|
||||
}
|
||||
|
||||
Vector2 max = GetWorldToScreen2D(new Vector2(maxX, maxY), camera);
|
||||
Vector2 min = GetWorldToScreen2D(new Vector2(minX, minY), camera);
|
||||
var max = GetWorldToScreen2D(new Vector2(maxX, maxY), camera);
|
||||
var min = GetWorldToScreen2D(new Vector2(minX, minY), camera);
|
||||
|
||||
if (max.X < width)
|
||||
{
|
||||
camera.Offset.X = width - (max.X - width / 2);
|
||||
camera.Offset.X = width - (max.X - width / 2.0f);
|
||||
}
|
||||
|
||||
if (max.Y < height)
|
||||
{
|
||||
camera.Offset.Y = height - (max.Y - height / 2);
|
||||
camera.Offset.Y = height - (max.Y - height / 2.0f);
|
||||
}
|
||||
|
||||
if (min.X > 0)
|
||||
{
|
||||
camera.Offset.X = width / 2 - min.X;
|
||||
camera.Offset.X = width / 2.0f - min.X;
|
||||
}
|
||||
|
||||
if (min.Y > 0)
|
||||
{
|
||||
camera.Offset.Y = height / 2 - min.Y;
|
||||
camera.Offset.Y = height / 2.0f - min.Y;
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateCameraCenterSmoothFollow(
|
||||
private static void UpdateCameraCenterSmoothFollow(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -297,18 +306,18 @@ public class Camera2dPlatformer
|
|||
const float minEffectLength = 10;
|
||||
const float fractionSpeed = 0.8f;
|
||||
|
||||
camera.Offset = new Vector2(width / 2, height / 2);
|
||||
Vector2 diff = Vector2Subtract(player.Position, camera.Target);
|
||||
float length = Vector2Length(diff);
|
||||
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
|
||||
var diff = Vector2Subtract(player.Position, camera.Target);
|
||||
var length = Vector2Length(diff);
|
||||
|
||||
if (length > minEffectLength)
|
||||
{
|
||||
float speed = Math.Max(fractionSpeed * length, minSpeed);
|
||||
var speed = Math.Max(fractionSpeed * length, minSpeed);
|
||||
camera.Target = Vector2Add(camera.Target, Vector2Scale(diff, speed * delta / length));
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateCameraEvenOutOnLanding(
|
||||
private static void UpdateCameraEvenOutOnLanding(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -318,10 +327,10 @@ public class Camera2dPlatformer
|
|||
)
|
||||
{
|
||||
float evenOutSpeed = 700;
|
||||
int eveningOut = 0;
|
||||
float evenOutTarget = 0.0f;
|
||||
var eveningOut = 0;
|
||||
var evenOutTarget = 0.0f;
|
||||
|
||||
camera.Offset = new Vector2(width / 2, height / 2);
|
||||
camera.Offset = new Vector2(width / 2.0f, height / 2.0f);
|
||||
camera.Target.X = player.Position.X;
|
||||
|
||||
if (eveningOut != 0)
|
||||
|
|
@ -357,7 +366,7 @@ public class Camera2dPlatformer
|
|||
}
|
||||
}
|
||||
|
||||
static void UpdateCameraPlayerBoundsPush(
|
||||
private static void UpdateCameraPlayerBoundsPush(
|
||||
ref Camera2D camera,
|
||||
ref Player player,
|
||||
EnvItem[] envItems,
|
||||
|
|
@ -368,11 +377,11 @@ public class Camera2dPlatformer
|
|||
{
|
||||
Vector2 bbox = new(0.2f, 0.2f);
|
||||
|
||||
Vector2 bboxWorldMin = GetScreenToWorld2D(
|
||||
var bboxWorldMin = GetScreenToWorld2D(
|
||||
new Vector2((1 - bbox.X) * 0.5f * width, (1 - bbox.Y) * 0.5f * height),
|
||||
camera
|
||||
);
|
||||
Vector2 bboxWorldMax = GetScreenToWorld2D(
|
||||
var bboxWorldMax = GetScreenToWorld2D(
|
||||
new Vector2((1 + bbox.X) * 0.5f * width,
|
||||
(1 + bbox.Y) * 0.5f * height),
|
||||
camera
|
||||
|
|
@ -399,4 +408,32 @@ public class Camera2dPlatformer
|
|||
camera.Target.Y = bboxWorldMin.Y + (player.Position.Y - bboxWorldMax.Y);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera platformer");
|
||||
|
||||
SetTargetFPS(60);
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera2dPlatformer();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@
|
|||
*
|
||||
* raylib [core] example - 3d camera first person
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★★☆☆] 2/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, last time updated with raylib 1.3
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,171 +18,202 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Camera3dFirstPerson
|
||||
public partial class Camera3dFirstPerson : IExample
|
||||
{
|
||||
public const int MaxColumns = 20;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Camera 3D First Person";
|
||||
|
||||
public string Title => "raylib [core] example - 3d camera first person";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private CameraMode cameraMode;
|
||||
private float[] heights;
|
||||
private Vector3[] positions;
|
||||
private Color[] colors;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world (position, target, up vector)
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 2.0f, 4.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 60.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
cameraMode = CameraMode.FirstPerson;
|
||||
|
||||
// Generates some random columns
|
||||
heights = new float[MaxColumns];
|
||||
positions = new Vector3[MaxColumns];
|
||||
colors = new Color[MaxColumns];
|
||||
|
||||
for (var i = 0; i < MaxColumns; i++)
|
||||
{
|
||||
heights[i] = (float)GetRandomValue(1, 12);
|
||||
positions[i] = new Vector3(GetRandomValue(-15, 15), heights[i] / 2.0f, GetRandomValue(-15, 15));
|
||||
colors[i] = new Color(GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Switch camera mode
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
cameraMode = CameraMode.Free;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
cameraMode = CameraMode.FirstPerson;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Four))
|
||||
{
|
||||
cameraMode = CameraMode.Orbital;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
// Switch camera projection
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
// Create isometric view
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
// Note: The target distance is related to the render distance in the orthographic projection
|
||||
camera.Position = new Vector3(0.0f, 2.0f, -100.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Projection = CameraProjection.Orthographic;
|
||||
camera.FovY = 20.0f; // near plane width in CAMERA_ORTHOGRAPHIC
|
||||
// CameraYaw(&camera, -135 * DEG2RAD, true);
|
||||
// CameraPitch(&camera, -45 * DEG2RAD, true, true, false);
|
||||
}
|
||||
else if (camera.Projection == CameraProjection.Orthographic)
|
||||
{
|
||||
// Reset to default view
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
camera.Position = new Vector3(0.0f, 2.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera.FovY = 60.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Update camera computes movement internally depending on the camera mode
|
||||
// Some default standard keyboard/mouse inputs are hardcoded to simplify use
|
||||
// For advanced camera controls, it's recommended to compute camera movement manually
|
||||
UpdateCamera(ref camera, cameraMode); // Update camera
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw ground
|
||||
DrawPlane(new Vector3(0.0f, 0.0f, 0.0f), new Vector2(32.0f, 32.0f), Color.LightGray);
|
||||
|
||||
// Draw a blue wall
|
||||
DrawCube(new Vector3(-16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Blue);
|
||||
|
||||
// Draw a green wall
|
||||
DrawCube(new Vector3(16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Lime);
|
||||
|
||||
// Draw a yellow wall
|
||||
DrawCube(new Vector3(0.0f, 2.5f, 16.0f), 32.0f, 5.0f, 1.0f, Color.Gold);
|
||||
|
||||
// Draw some cubes around
|
||||
for (var i = 0; i < MaxColumns; i++)
|
||||
{
|
||||
DrawCube(positions[i], 2.0f, heights[i], 2.0f, colors[i]);
|
||||
DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, Color.Maroon);
|
||||
}
|
||||
|
||||
// Draw player cube
|
||||
if (cameraMode == CameraMode.ThirdPerson)
|
||||
{
|
||||
DrawCube(camera.Target, 0.5f, 0.5f, 0.5f, Color.Purple);
|
||||
DrawCubeWires(camera.Target, 0.5f, 0.5f, 0.5f, Color.DarkPurple);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw info boxes
|
||||
DrawRectangle(5, 5, 330, 100, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(5, 5, 330, 100, Color.Blue);
|
||||
|
||||
DrawText("Camera controls:", 15, 15, 10, Color.Black);
|
||||
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, Color.Black);
|
||||
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, Color.Black);
|
||||
DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, Color.Black);
|
||||
DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, Color.Black);
|
||||
DrawText("- Camera projection key: P", 15, 90, 10, Color.Black);
|
||||
|
||||
DrawRectangle(600, 5, 195, 100, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(600, 5, 195, 100, Color.Blue);
|
||||
|
||||
DrawText("Camera status:", 610, 15, 10, Color.Black);
|
||||
DrawText($"- Mode: {cameraMode}", 610, 30, 10, Color.Black);
|
||||
DrawText($"- Projection: {camera.Projection}", 610, 45, 10, Color.Black);
|
||||
DrawText($"- Position: {camera.Position}", 610, 60, 10, Color.Black);
|
||||
DrawText($"- Target: {camera.Target}", 610, 75, 10, Color.Black);
|
||||
DrawText($"- Up: {camera.Up}", 610, 90, 10, Color.Black);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person");
|
||||
|
||||
// Define the camera to look into our 3d world (position, target, up vector)
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(4.0f, 2.0f, 4.0f);
|
||||
camera.Target = new Vector3(0.0f, 1.8f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 60.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
// Generates some random columns
|
||||
float[] heights = new float[MaxColumns];
|
||||
Vector3[] positions = new Vector3[MaxColumns];
|
||||
Color[] colors = new Color[MaxColumns];
|
||||
|
||||
for (int i = 0; i < MaxColumns; i++)
|
||||
{
|
||||
heights[i] = (float)GetRandomValue(1, 12);
|
||||
positions[i] = new Vector3(GetRandomValue(-15, 15), heights[i] / 2, GetRandomValue(-15, 15));
|
||||
colors[i] = new Color(GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255);
|
||||
}
|
||||
|
||||
CameraMode cameraMode = CameraMode.FirstPerson;
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera3dFirstPerson();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Switch camera mode
|
||||
if (IsKeyPressed(KeyboardKey.One))
|
||||
{
|
||||
cameraMode = CameraMode.Free;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Two))
|
||||
{
|
||||
cameraMode = CameraMode.FirstPerson;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Three))
|
||||
{
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Four))
|
||||
{
|
||||
cameraMode = CameraMode.Orbital;
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
// Switch camera projection
|
||||
if (IsKeyPressed(KeyboardKey.P))
|
||||
{
|
||||
if (camera.Projection == CameraProjection.Perspective)
|
||||
{
|
||||
// Create isometric view
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
// Note: The target distance is related to the render distance in the orthographic projection
|
||||
camera.Position = new Vector3(0.0f, 2.0f, -100.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Projection = CameraProjection.Orthographic;
|
||||
camera.FovY = 20.0f; // near plane width in CAMERA_ORTHOGRAPHIC
|
||||
// CameraYaw(&camera, -135 * DEG2RAD, true);
|
||||
// CameraPitch(&camera, -45 * DEG2RAD, true, true, false);
|
||||
}
|
||||
else if (camera.Projection == CameraProjection.Orthographic)
|
||||
{
|
||||
// Reset to default view
|
||||
cameraMode = CameraMode.ThirdPerson;
|
||||
camera.Position = new Vector3(0.0f, 2.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 2.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera.FovY = 60.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Update camera computes movement internally depending on the camera mode
|
||||
// Some default standard keyboard/mouse inputs are hardcoded to simplify use
|
||||
// For advance camera controls, it's reecommended to compute camera movement manually
|
||||
UpdateCamera(ref camera, cameraMode);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
// Draw ground
|
||||
DrawPlane(new Vector3(0.0f, 0.0f, 0.0f), new Vector2(32.0f, 32.0f), Color.LightGray);
|
||||
|
||||
// Draw a blue wall
|
||||
DrawCube(new Vector3(-16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Blue);
|
||||
|
||||
// Draw a green wall
|
||||
DrawCube(new Vector3(16.0f, 2.5f, 0.0f), 1.0f, 5.0f, 32.0f, Color.Lime);
|
||||
|
||||
// Draw a yellow wall
|
||||
DrawCube(new Vector3(0.0f, 2.5f, 16.0f), 32.0f, 5.0f, 1.0f, Color.Gold);
|
||||
|
||||
// Draw some cubes around
|
||||
for (int i = 0; i < MaxColumns; i++)
|
||||
{
|
||||
DrawCube(positions[i], 2.0f, heights[i], 2.0f, colors[i]);
|
||||
DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, Color.Maroon);
|
||||
}
|
||||
|
||||
// Draw player cube
|
||||
if (cameraMode == CameraMode.ThirdPerson)
|
||||
{
|
||||
DrawCube(camera.Target, 0.5f, 0.5f, 0.5f, Color.Purple);
|
||||
DrawCubeWires(camera.Target, 0.5f, 0.5f, 0.5f, Color.DarkPurple);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
// Draw info boxes
|
||||
DrawRectangle(5, 5, 330, 100, ColorAlpha(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 330, 100, Color.Blue);
|
||||
|
||||
DrawText("Camera controls:", 15, 15, 10, Color.Black);
|
||||
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, Color.Black);
|
||||
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, Color.Black);
|
||||
DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, Color.Black);
|
||||
DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, Color.Black);
|
||||
DrawText("- Camera projection key: P", 15, 90, 10, Color.Black);
|
||||
|
||||
DrawRectangle(600, 5, 195, 100, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(600, 5, 195, 100, Color.Blue);
|
||||
|
||||
DrawText("Camera status:", 610, 15, 10, Color.Black);
|
||||
DrawText($"- Mode: {cameraMode}", 610, 30, 10, Color.Black);
|
||||
DrawText($"- Projection: {camera.Projection}", 610, 45, 10, Color.Black);
|
||||
DrawText($"- Position: {camera.Position}", 610, 60, 10, Color.Black);
|
||||
DrawText($"- Target: {camera.Target}", 610, 75, 10, Color.Black);
|
||||
DrawText($"- Up: {camera.Up}", 610, 90, 10, Color.Black);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
348
Examples/Core/Camera3dFps.cs
Normal file
348
Examples/Core/Camera3dFps.cs
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - 3d camera fps
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 5.5, last time updated with raylib 5.5
|
||||
*
|
||||
* Example contributed by Agnis Aldiņš (@nezvers) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2025 Agnis Aldiņš (@nezvers)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using static Raylib_cs.Raylib;
|
||||
using static Raylib_cs.Raymath;
|
||||
|
||||
namespace Examples.Core;
|
||||
|
||||
public partial class Camera3dFps : IExample
|
||||
{
|
||||
// Movement constants
|
||||
private const float GRAVITY = 32.0f;
|
||||
private const float MAX_SPEED = 20.0f;
|
||||
private const float CROUCH_SPEED = 5.0f;
|
||||
private const float JUMP_FORCE = 12.0f;
|
||||
private const float MAX_ACCEL = 150.0f;
|
||||
// Grounded drag
|
||||
private const float FRICTION = 0.86f;
|
||||
// Increasing air drag, increases strafing speed
|
||||
private const float AIR_DRAG = 0.98f;
|
||||
// Responsiveness for turning movement direction to looked direction
|
||||
private const float CONTROL = 15.0f;
|
||||
private const float CROUCH_HEIGHT = 0.0f;
|
||||
private const float STAND_HEIGHT = 1.0f;
|
||||
private const float BOTTOM_HEIGHT = 0.5f;
|
||||
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / 3D Camera FPS";
|
||||
|
||||
public string Title => "raylib [core] example - 3d camera fps";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
// Body structure
|
||||
private struct Body
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Vector3 Velocity;
|
||||
public Vector3 Dir;
|
||||
public bool IsGrounded;
|
||||
}
|
||||
|
||||
// State that was global in the C example
|
||||
private readonly Vector2 sensitivity = new Vector2(0.001f, 0.001f);
|
||||
|
||||
private Body player;
|
||||
private Vector2 lookRotation;
|
||||
private float headTimer;
|
||||
private float walkLerp;
|
||||
private float headLerp;
|
||||
private Vector2 lean;
|
||||
|
||||
private Camera3D camera;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
player = new Body();
|
||||
lookRotation = new Vector2(0, 0);
|
||||
headTimer = 0.0f;
|
||||
walkLerp = 0.0f;
|
||||
headLerp = STAND_HEIGHT;
|
||||
lean = new Vector2(0, 0);
|
||||
|
||||
// Initialize camera variables
|
||||
// NOTE: UpdateCameraFPS() takes care of the rest
|
||||
camera = new Camera3D();
|
||||
camera.FovY = 60.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
camera.Position = new Vector3(
|
||||
player.Position.X,
|
||||
player.Position.Y + (BOTTOM_HEIGHT + headLerp),
|
||||
player.Position.Z);
|
||||
|
||||
UpdateCameraFPS(ref camera); // Update camera parameters
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
Vector2 mouseDelta = GetMouseDelta();
|
||||
lookRotation.X -= mouseDelta.X * sensitivity.X;
|
||||
lookRotation.Y += mouseDelta.Y * sensitivity.Y;
|
||||
|
||||
int sideway = (IsKeyDown(KeyboardKey.D) ? 1 : 0) - (IsKeyDown(KeyboardKey.A) ? 1 : 0);
|
||||
int forward = (IsKeyDown(KeyboardKey.W) ? 1 : 0) - (IsKeyDown(KeyboardKey.S) ? 1 : 0);
|
||||
bool crouching = IsKeyDown(KeyboardKey.LeftControl);
|
||||
UpdateBody(ref player, lookRotation.X, sideway, forward, IsKeyPressed(KeyboardKey.Space), crouching);
|
||||
|
||||
float delta = GetFrameTime();
|
||||
headLerp = Lerp(headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0f * delta);
|
||||
camera.Position = new Vector3(
|
||||
player.Position.X,
|
||||
player.Position.Y + (BOTTOM_HEIGHT + headLerp),
|
||||
player.Position.Z);
|
||||
|
||||
if (player.IsGrounded && ((forward != 0) || (sideway != 0)))
|
||||
{
|
||||
headTimer += delta * 3.0f;
|
||||
walkLerp = Lerp(walkLerp, 1.0f, 10.0f * delta);
|
||||
camera.FovY = Lerp(camera.FovY, 55.0f, 5.0f * delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
walkLerp = Lerp(walkLerp, 0.0f, 10.0f * delta);
|
||||
camera.FovY = Lerp(camera.FovY, 60.0f, 5.0f * delta);
|
||||
}
|
||||
|
||||
lean.X = Lerp(lean.X, sideway * 0.02f, 10.0f * delta);
|
||||
lean.Y = Lerp(lean.Y, forward * 0.015f, 10.0f * delta);
|
||||
|
||||
UpdateCameraFPS(ref camera);
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
DrawLevel();
|
||||
EndMode3D();
|
||||
|
||||
// Draw info box
|
||||
DrawRectangle(5, 5, 330, 75, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(5, 5, 330, 75, Color.Blue);
|
||||
|
||||
DrawText("Camera controls:", 15, 15, 10, Color.Black);
|
||||
DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, Color.Black);
|
||||
DrawText("- Look around: arrow keys or mouse", 15, 45, 10, Color.Black);
|
||||
float velLen = Vector2Length(new Vector2(player.Velocity.X, player.Velocity.Z));
|
||||
DrawText($"- Velocity Len: ({velLen:00.000})", 15, 60, 10, Color.Black);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
// Update body considering current world state
|
||||
private void UpdateBody(ref Body body, float rot, int side, int forward, bool jumpPressed, bool crouchHold)
|
||||
{
|
||||
Vector2 input = new Vector2((float)side, (float)-forward);
|
||||
|
||||
// Upstream guards this with `#if defined(NORMALIZE_INPUT)`, which is always true given the
|
||||
// `#define NORMALIZE_INPUT 0` above it (defined() tests definedness, not the value), so the
|
||||
// diagonal-movement normalization is active.
|
||||
// Slow down diagonal movement
|
||||
if ((side != 0) && (forward != 0)) input = Vector2Normalize(input);
|
||||
|
||||
float delta = GetFrameTime();
|
||||
|
||||
if (!body.IsGrounded) body.Velocity.Y -= GRAVITY * delta;
|
||||
|
||||
if (body.IsGrounded && jumpPressed)
|
||||
{
|
||||
body.Velocity.Y = JUMP_FORCE;
|
||||
body.IsGrounded = false;
|
||||
|
||||
// Sound can be played at this moment
|
||||
//SetSoundPitch(fxJump, 1.0f + (GetRandomValue(-100, 100)*0.001));
|
||||
//PlaySound(fxJump);
|
||||
}
|
||||
|
||||
Vector3 front = new Vector3(MathF.Sin(rot), 0.0f, MathF.Cos(rot));
|
||||
Vector3 right = new Vector3(MathF.Cos(-rot), 0.0f, MathF.Sin(-rot));
|
||||
|
||||
Vector3 desiredDir = new Vector3(
|
||||
input.X * right.X + input.Y * front.X,
|
||||
0.0f,
|
||||
input.X * right.Z + input.Y * front.Z);
|
||||
body.Dir = Vector3Lerp(body.Dir, desiredDir, CONTROL * delta);
|
||||
|
||||
float decel = (body.IsGrounded ? FRICTION : AIR_DRAG);
|
||||
Vector3 hvel = new Vector3(body.Velocity.X * decel, 0.0f, body.Velocity.Z * decel);
|
||||
|
||||
float hvelLength = Vector3Length(hvel); // Magnitude
|
||||
if (hvelLength < (MAX_SPEED * 0.01f)) hvel = new Vector3(0, 0, 0);
|
||||
|
||||
// This is what creates strafing
|
||||
float speed = Vector3DotProduct(hvel, body.Dir);
|
||||
|
||||
// Whenever the amount of acceleration to add is clamped by the maximum acceleration constant,
|
||||
// a Player can make the speed faster by bringing the direction closer to horizontal velocity angle
|
||||
// More info here: https://youtu.be/v3zT3Z5apaM?t=165
|
||||
float maxSpeed = (crouchHold ? CROUCH_SPEED : MAX_SPEED);
|
||||
float accel = Clamp(maxSpeed - speed, 0.0f, MAX_ACCEL * delta);
|
||||
hvel.X += body.Dir.X * accel;
|
||||
hvel.Z += body.Dir.Z * accel;
|
||||
|
||||
body.Velocity.X = hvel.X;
|
||||
body.Velocity.Z = hvel.Z;
|
||||
|
||||
body.Position.X += body.Velocity.X * delta;
|
||||
body.Position.Y += body.Velocity.Y * delta;
|
||||
body.Position.Z += body.Velocity.Z * delta;
|
||||
|
||||
// Fancy collision system against the floor
|
||||
if (body.Position.Y <= 0.0f)
|
||||
{
|
||||
body.Position.Y = 0.0f;
|
||||
body.Velocity.Y = 0.0f;
|
||||
body.IsGrounded = true; // Enable jumping
|
||||
}
|
||||
}
|
||||
|
||||
// Update camera for FPS behaviour
|
||||
private void UpdateCameraFPS(ref Camera3D camera)
|
||||
{
|
||||
Vector3 up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
Vector3 targetOffset = new Vector3(0.0f, 0.0f, -1.0f);
|
||||
|
||||
// Left and right
|
||||
Vector3 yaw = Vector3RotateByAxisAngle(targetOffset, up, lookRotation.X);
|
||||
|
||||
// Clamp view up
|
||||
float maxAngleUp = Vector3Angle(up, yaw);
|
||||
maxAngleUp -= 0.001f; // Avoid numerical errors
|
||||
if (-(lookRotation.Y) > maxAngleUp) { lookRotation.Y = -maxAngleUp; }
|
||||
|
||||
// Clamp view down
|
||||
float maxAngleDown = Vector3Angle(Vector3Negate(up), yaw);
|
||||
maxAngleDown *= -1.0f; // Downwards angle is negative
|
||||
maxAngleDown += 0.001f; // Avoid numerical errors
|
||||
if (-(lookRotation.Y) < maxAngleDown) { lookRotation.Y = -maxAngleDown; }
|
||||
|
||||
// Up and down
|
||||
Vector3 right = Vector3Normalize(Vector3CrossProduct(yaw, up));
|
||||
|
||||
// Rotate view vector around right axis
|
||||
float pitchAngle = -lookRotation.Y - lean.Y;
|
||||
pitchAngle = Clamp(pitchAngle, -MathF.PI / 2 + 0.0001f, MathF.PI / 2 - 0.0001f); // Clamp angle so it doesn't go past straight up or straight down
|
||||
Vector3 pitch = Vector3RotateByAxisAngle(yaw, right, pitchAngle);
|
||||
|
||||
// Head animation
|
||||
// Rotate up direction around forward axis
|
||||
float headSin = MathF.Sin(headTimer * MathF.PI);
|
||||
float headCos = MathF.Cos(headTimer * MathF.PI);
|
||||
const float stepRotation = 0.01f;
|
||||
camera.Up = Vector3RotateByAxisAngle(up, pitch, headSin * stepRotation + lean.X);
|
||||
|
||||
// Camera BOB
|
||||
const float bobSide = 0.1f;
|
||||
const float bobUp = 0.15f;
|
||||
Vector3 bobbing = Vector3Scale(right, headSin * bobSide);
|
||||
bobbing.Y = MathF.Abs(headCos * bobUp);
|
||||
|
||||
camera.Position = Vector3Add(camera.Position, Vector3Scale(bobbing, walkLerp));
|
||||
camera.Target = Vector3Add(camera.Position, pitch);
|
||||
}
|
||||
|
||||
// Draw game level
|
||||
private void DrawLevel()
|
||||
{
|
||||
const int floorExtent = 25;
|
||||
const float tileSize = 5.0f;
|
||||
Color tileColor1 = new Color(150, 200, 200, 255);
|
||||
|
||||
// Floor tiles
|
||||
for (int y = -floorExtent; y < floorExtent; y++)
|
||||
{
|
||||
for (int x = -floorExtent; x < floorExtent; x++)
|
||||
{
|
||||
if ((y & 1) != 0 && (x & 1) != 0)
|
||||
{
|
||||
DrawPlane(new Vector3(x * tileSize, 0.0f, y * tileSize), new Vector2(tileSize, tileSize), tileColor1);
|
||||
}
|
||||
else if ((y & 1) == 0 && (x & 1) == 0)
|
||||
{
|
||||
DrawPlane(new Vector3(x * tileSize, 0.0f, y * tileSize), new Vector2(tileSize, tileSize), Color.LightGray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 towerSize = new Vector3(16.0f, 32.0f, 16.0f);
|
||||
Color towerColor = new Color(150, 200, 200, 255);
|
||||
|
||||
Vector3 towerPos = new Vector3(16.0f, 16.0f, 16.0f);
|
||||
DrawCubeV(towerPos, towerSize, towerColor);
|
||||
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
|
||||
|
||||
towerPos.X *= -1;
|
||||
DrawCubeV(towerPos, towerSize, towerColor);
|
||||
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
|
||||
|
||||
towerPos.Z *= -1;
|
||||
DrawCubeV(towerPos, towerSize, towerColor);
|
||||
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
|
||||
|
||||
towerPos.X *= -1;
|
||||
DrawCubeV(towerPos, towerSize, towerColor);
|
||||
DrawCubeWiresV(towerPos, towerSize, Color.DarkBlue);
|
||||
|
||||
// Red sun
|
||||
DrawSphere(new Vector3(300.0f, 300.0f, 0.0f), 100.0f, new Color(255, 0, 0, 255));
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera fps");
|
||||
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera3dFps();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Initialize 3d camera free
|
||||
* raylib [core] example - 3d camera free
|
||||
*
|
||||
* This example has been created using raylib 1.3 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.3, last time updated with raylib 1.3
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2015-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,74 +18,100 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Camera3dFree
|
||||
public partial class Camera3dFree : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
public string Name => "Core / Camera 3D Free";
|
||||
|
||||
public string Title => "raylib [core] example - 3d camera free";
|
||||
|
||||
public bool CursorDisabled => true;
|
||||
|
||||
private Camera3D camera;
|
||||
private Vector3 cubePosition;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
||||
|
||||
cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
|
||||
if (IsKeyPressed(KeyboardKey.Z))
|
||||
{
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangle(10, 10, 320, 93, Fade(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 320, 93, Color.Blue);
|
||||
|
||||
DrawText("Free camera default controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- Z to zoom to (0, 0, 0)", 40, 80, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera;
|
||||
camera.Position = new Vector3(10.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
DisableCursor(); // Limit cursor to relative movement inside the window
|
||||
|
||||
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera3dFree();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
UpdateCamera(ref camera, CameraMode.Free);
|
||||
|
||||
if (IsKeyDown(KeyboardKey.Z))
|
||||
{
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawRectangle(10, 10, 320, 133, ColorAlpha(Color.SkyBlue, 0.5f));
|
||||
DrawRectangleLines(10, 10, 320, 133, Color.Blue);
|
||||
|
||||
DrawText("Free camera default controls:", 20, 20, 10, Color.Black);
|
||||
DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, Color.DarkGray);
|
||||
DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, Color.DarkGray);
|
||||
DrawText("- Alt + Mouse Wheel Pressed to Rotate", 40, 80, 10, Color.DarkGray);
|
||||
DrawText("- Alt + Ctrl + Mouse Wheel Pressed for Smooth Zoom", 40, 100, 10, Color.DarkGray);
|
||||
DrawText("- Z to zoom to (0, 0, 0)", 40, 120, 10, Color.DarkGray);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [core] example - Initialize 3d camera mode
|
||||
* raylib [core] example - 3d camera mode
|
||||
*
|
||||
* This example has been created using raylib 1.0 (www.raylib.com)
|
||||
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
|
||||
* Example complexity rating: [★☆☆☆] 1/4
|
||||
*
|
||||
* Copyright (c) 2014 Ramon Santamaria (@raysan5)
|
||||
* Example originally created with raylib 1.0, last time updated with raylib 1.0
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
|
@ -14,63 +18,82 @@ using static Raylib_cs.Raylib;
|
|||
|
||||
namespace Examples.Core;
|
||||
|
||||
public class Camera3dMode
|
||||
public partial class Camera3dMode : IExample
|
||||
{
|
||||
private const int screenWidth = 800;
|
||||
private const int screenHeight = 450;
|
||||
|
||||
private Camera3D camera;
|
||||
private Vector3 cubePosition;
|
||||
|
||||
public string Name => "Core / Camera 3D Mode";
|
||||
|
||||
public string Title => "raylib [core] example - 3d camera mode";
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// Define the camera to look into our 3d world
|
||||
camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f); // Camera position
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f); // Camera looking at point
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f); // Camera up vector (rotation towards target)
|
||||
camera.FovY = 45.0f; // Camera field-of-view Y
|
||||
camera.Projection = CameraProjection.Perspective; // Camera mode type
|
||||
|
||||
cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Welcome to the third dimension!", 10, 40, 20, Color.DarkGray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Main()
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera mode");
|
||||
|
||||
// Define the camera to look into our 3d world
|
||||
Camera3D camera = new();
|
||||
camera.Position = new Vector3(0.0f, 10.0f, 10.0f);
|
||||
camera.Target = new Vector3(0.0f, 0.0f, 0.0f);
|
||||
camera.Up = new Vector3(0.0f, 1.0f, 0.0f);
|
||||
camera.FovY = 45.0f;
|
||||
camera.Projection = CameraProjection.Perspective;
|
||||
|
||||
Vector3 cubePosition = new(0.0f, 0.0f, 0.0f);
|
||||
|
||||
SetTargetFPS(60);
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
var game = new Camera3dMode();
|
||||
game.Init();
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose())
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// TODO: Update your variables here
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
ClearBackground(Color.RayWhite);
|
||||
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, Color.Red);
|
||||
DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, Color.Maroon);
|
||||
|
||||
DrawGrid(10, 1.0f);
|
||||
|
||||
EndMode3D();
|
||||
|
||||
DrawText("Welcome to the third dimension!", 10, 40, 20, Color.DarkGray);
|
||||
|
||||
DrawFPS(10, 10);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
game.Update();
|
||||
}
|
||||
|
||||
game.Unload();
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow();
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue