199 lines
7 KiB
C#
199 lines
7 KiB
C#
/*******************************************************************************************
|
|
*
|
|
* raylib [models] example - basic voxel
|
|
*
|
|
* Example complexity rating: [★★☆☆] 2/4
|
|
*
|
|
* Example originally created with raylib 5.5, last time updated with raylib 5.5
|
|
*
|
|
* Example contributed by Tim Little (@timlittle) 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 Tim Little (@timlittle)
|
|
*
|
|
********************************************************************************************/
|
|
|
|
namespace Examples.Models;
|
|
|
|
public partial class BasicVoxel : IExample
|
|
{
|
|
private const int screenWidth = 800;
|
|
private const int screenHeight = 450;
|
|
|
|
private const int WorldSize = 8; // Size of our voxel world (8x8x8 cubes)
|
|
|
|
public string Name => "Models / Basic Voxel";
|
|
|
|
public string Title => "raylib [models] example - basic voxel";
|
|
|
|
public bool CursorDisabled => true;
|
|
|
|
private Camera3D camera;
|
|
private Model cubeModel;
|
|
private bool[,,] voxels;
|
|
|
|
public unsafe void Init()
|
|
{
|
|
// Define the camera to look into our 3d world (first person)
|
|
camera = new();
|
|
camera.Position = new Vector3(-2.0f, 0.0f, -2.0f); // Camera position at ground level
|
|
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
|
|
camera.FovY = 45.0f; // Camera field-of-view Y
|
|
camera.Projection = CameraProjection.Perspective; // Camera projection type
|
|
|
|
// Create a cube model
|
|
var cubeMesh = GenMeshCube(1.0f, 1.0f, 1.0f); // Create a unit cube mesh
|
|
cubeModel = LoadModelFromMesh(cubeMesh); // Convert mesh to a model
|
|
cubeModel.Materials[0].Maps[(int)MaterialMapIndex.Diffuse].Color = Color.Beige;
|
|
|
|
// Initialize voxel world - fill with voxels
|
|
voxels = new bool[WorldSize, WorldSize, WorldSize];
|
|
for (var x = 0; x < WorldSize; x++)
|
|
{
|
|
for (var y = 0; y < WorldSize; y++)
|
|
{
|
|
for (var z = 0; z < WorldSize; z++)
|
|
{
|
|
voxels[x, y, z] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
// Update
|
|
//----------------------------------------------------------------------------------
|
|
UpdateCamera(ref camera, CameraMode.FirstPerson);
|
|
|
|
// Handle voxel removal with mouse click
|
|
// This method is quite inefficient. Ray marching through the voxel grid using DDA would be faster, but more complex.
|
|
if (IsMouseButtonPressed(MouseButton.Left))
|
|
{
|
|
// Cast a ray from the screen center (where crosshair would be)
|
|
Vector2 screenCenter = new(GetScreenWidth() / 2.0f, GetScreenHeight() / 2.0f);
|
|
var ray = GetScreenToWorldRay(screenCenter, camera);
|
|
|
|
// Check ray collision with all voxels
|
|
var closestDistance = 99999.0f;
|
|
Vector3 closestVoxelPosition = new(-1, -1, -1);
|
|
var voxelFound = false;
|
|
for (var x = 0; x < WorldSize; x++)
|
|
{
|
|
for (var y = 0; y < WorldSize; y++)
|
|
{
|
|
for (var z = 0; z < WorldSize; z++)
|
|
{
|
|
if (!voxels[x, y, z])
|
|
{
|
|
continue; // Skip empty voxels
|
|
}
|
|
|
|
// Build a bounding box for this voxel
|
|
Vector3 position = new(x, y, z);
|
|
BoundingBox box = new(
|
|
new Vector3(position.X - 0.5f, position.Y - 0.5f, position.Z - 0.5f),
|
|
new Vector3(position.X + 0.5f, position.Y + 0.5f, position.Z + 0.5f)
|
|
);
|
|
|
|
// Check ray-box collision
|
|
var collision = GetRayCollisionBox(ray, box);
|
|
if (collision.Hit && (collision.Distance < closestDistance))
|
|
{
|
|
closestDistance = collision.Distance;
|
|
closestVoxelPosition = new Vector3(x, y, z);
|
|
voxelFound = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove the closest voxel if one was hit
|
|
if (voxelFound)
|
|
{
|
|
voxels[(int)closestVoxelPosition.X,
|
|
(int)closestVoxelPosition.Y,
|
|
(int)closestVoxelPosition.Z] = false;
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------------
|
|
|
|
// Draw
|
|
//----------------------------------------------------------------------------------
|
|
BeginDrawing();
|
|
|
|
ClearBackground(Color.RayWhite);
|
|
|
|
BeginMode3D(camera);
|
|
|
|
DrawGrid(10, 1.0f);
|
|
|
|
// Draw all voxels
|
|
for (var x = 0; x < WorldSize; x++)
|
|
{
|
|
for (var y = 0; y < WorldSize; y++)
|
|
{
|
|
for (var z = 0; z < WorldSize; z++)
|
|
{
|
|
if (!voxels[x, y, z])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Vector3 position = new(x, y, z);
|
|
DrawModel(cubeModel, position, 1.0f, Color.Beige);
|
|
DrawCubeWires(position, 1.0f, 1.0f, 1.0f, Color.Black);
|
|
}
|
|
}
|
|
}
|
|
|
|
EndMode3D();
|
|
|
|
// Draw reference point for raycasting to delete blocks
|
|
DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, 4, Color.Red);
|
|
|
|
DrawText("Left-click a voxel to remove it!", 10, 10, 20, Color.DarkGray);
|
|
DrawText("WASD to move, mouse to look around", 10, 35, 10, Color.Gray);
|
|
|
|
EndDrawing();
|
|
//----------------------------------------------------------------------------------
|
|
}
|
|
|
|
public void Unload()
|
|
{
|
|
UnloadModel(cubeModel);
|
|
}
|
|
|
|
public static int Main()
|
|
{
|
|
// Initialization
|
|
//--------------------------------------------------------------------------------------
|
|
InitWindow(screenWidth, screenHeight, "raylib [models] example - basic voxel");
|
|
|
|
DisableCursor(); // Lock mouse to window center
|
|
|
|
SetTargetFPS(60);
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
var game = new BasicVoxel();
|
|
game.Init();
|
|
|
|
// Main game loop
|
|
while (!WindowShouldClose()) // Detect window close button or ESC key
|
|
{
|
|
game.Update();
|
|
}
|
|
|
|
game.Unload();
|
|
|
|
// De-Initialization
|
|
//--------------------------------------------------------------------------------------
|
|
CloseWindow();
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
return 0;
|
|
}
|
|
}
|