Files
Physics-Engine/PhysicsEngine/Core/Program.cs
2026-09-03 16:50:36 +02:00

392 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Numerics;
using Raylib_cs;
namespace PhysicsEngine
{
class Program
{
private static Font robotoFont;
private static WorldModel world; // Instance of our WorldModel
static void Main(string[] args)
{
Raylib.SetConfigFlags(ConfigFlags.FullscreenMode | ConfigFlags.VSyncHint);
Raylib.InitWindow(0, 0, "Physics Engine");
robotoFont = Raylib.LoadFont("Roboto-Regular.ttf");
Raylib.SetTextureFilter(robotoFont.Texture, TextureFilter.Bilinear);
Camera camera = new Camera();
world = new WorldModel(); // Initialize simulation world
ScenarioLarge();
const float physicsTimeStep = 1.0f / 60.0f;
float accumulator = 0.0f;
// Main loop
while (!Raylib.WindowShouldClose())
{
float frameTime = Raylib.GetFrameTime();
if (frameTime > 0.25f)
{
frameTime = 0.25f;
}
// Update Camera
camera.Update(frameTime);
// Update Physics accumulator
accumulator += frameTime;
while (accumulator >= physicsTimeStep)
{
UpdatePhysics(physicsTimeStep);
accumulator -= physicsTimeStep;
}
// Render loop
Raylib.BeginDrawing();
Raylib.ClearBackground(MuiDarkColor.BackgroundDefault.ToColor());
// Draw background screen-space elements (Grid)
camera.DrawGrid();
// Draw World Bodies inside the Camera's 2D World Transform
Raylib.BeginMode2D(camera.RaylibCamera);
RenderScene();
Raylib.EndMode2D();
// Draw UI / HUD elements
camera.DrawHUD();
DrawText("Physics Engine", 20, 20, 30, MuiDarkColor.TextPrimary.ToColor());
Raylib.EndDrawing();
}
Raylib.UnloadFont(robotoFont);
Raylib.CloseWindow();
}
public static void DrawText(string text, int posX, int posY, float fontSize, Color color)
{
Raylib.DrawTextEx(robotoFont, text, new Vector2(posX, posY), fontSize, 1.0f, color);
}
private static void UpdatePhysics(float dt)
{
world.Step(dt);
}
private static void RenderScene()
{
// Iterate and draw all bodies in the world
foreach (var body in world.Bodies)
{
body.Draw();
}
}
private static void Scenario()
{
float worldWidth = 12.8f;
float worldHeight = 7.2f;
float wallThickness = 1.0f;
// 1. Static world borders
Box floor = new Box(new Vector2(worldWidth * 0.5f, worldHeight + (wallThickness * 0.5f)), new Vector2(worldWidth + wallThickness * 2, wallThickness), 0f);
floor.BaseColor = Color.DarkGray;
world.AddBody(floor);
Box ceiling = new Box(new Vector2(worldWidth * 0.5f, -wallThickness * 0.5f), new Vector2(worldWidth + wallThickness * 2, wallThickness), 0f);
ceiling.BaseColor = Color.DarkGray;
world.AddBody(ceiling);
Box leftWall = new Box(new Vector2(-wallThickness * 0.5f, worldHeight * 0.5f), new Vector2(wallThickness, worldHeight + wallThickness * 2), 0f);
leftWall.BaseColor = Color.DarkGray;
world.AddBody(leftWall);
Box rightWall = new Box(new Vector2(worldWidth + wallThickness * 0.5f, worldHeight * 0.5f), new Vector2(wallThickness, worldHeight + wallThickness * 2), 0f);
rightWall.BaseColor = Color.DarkGray;
world.AddBody(rightWall);
// 2. Static ramps and platforms (rotated boxes)
// Left ramp (slopes up to the right)
Box leftRamp = new Box(new Vector2(2.5f, 5.5f), new Vector2(4.0f, 0.4f), 0f);
leftRamp.Rotation = -0.4f; // tilt upward to the right
leftRamp.BaseColor = Color.Gray;
world.AddBody(leftRamp);
// Right ramp (slopes down to the right)
Box rightRamp = new Box(new Vector2(10.5f, 5.5f), new Vector2(4.0f, 0.4f), 0f);
rightRamp.Rotation = 0.4f; // tilt downward to the right
rightRamp.BaseColor = Color.Gray;
world.AddBody(rightRamp);
// Floating platform in the middle
Box platform = new Box(new Vector2(6.4f, 3.5f), new Vector2(3.0f, 0.4f), 0f);
platform.BaseColor = Color.LightGray;
world.AddBody(platform);
// Small static circle bumper near the bottom center
Circle staticBumper = new Circle(new Vector2(6.4f, 6.0f), 0.3f, 0f);
staticBumper.BaseColor = Color.Orange;
world.AddBody(staticBumper);
// 3. Dynamic bodies a mix of boxes and circles with varied properties
// Tall, thin box (will tip over when hitting the ground)
Box tallBox = new Box(new Vector2(2.0f, 1.0f), new Vector2(0.3f, 1.8f), 30f);
tallBox.BaseColor = Color.SkyBlue;
tallBox.Rotation = 0.3f;
tallBox.AngularVelocity = 0.5f;
tallBox.Friction = 0.8f;
tallBox.Restitution = 0.1f;
world.AddBody(tallBox);
// Heavy square box
Box heavyBox = new Box(new Vector2(4.0f, 1.5f), new Vector2(0.8f, 0.8f), 80f);
heavyBox.BaseColor = Color.DarkGreen;
heavyBox.Friction = 0.9f;
heavyBox.Restitution = 0.0f;
heavyBox.Velocity = new Vector2(1.5f, -1.0f);
world.AddBody(heavyBox);
// Long plank (will slide and possibly balance)
Box plank = new Box(new Vector2(8.0f, 0.5f), new Vector2(2.5f, 0.25f), 25f);
plank.BaseColor = Color.Brown;
plank.Rotation = -0.2f;
plank.AngularVelocity = -0.3f;
plank.Friction = 0.6f;
world.AddBody(plank);
// Bouncy ball (high restitution, low friction)
Circle bouncyBall = new Circle(new Vector2(9.0f, 1.0f), 0.3f, 5f);
bouncyBall.BaseColor = Color.Red;
bouncyBall.Restitution = 0.9f;
bouncyBall.Friction = 0.05f;
bouncyBall.Velocity = new Vector2(-30.0f, -20.0f);
bouncyBall.AngularVelocity = 10f;
world.AddBody(bouncyBall);
// Heavy circle (rolls slowly)
Circle heavyBall = new Circle(new Vector2(5.0f, 0.8f), 0.5f, 40f);
heavyBall.BaseColor = Color.Purple;
heavyBall.Friction = 0.7f;
heavyBall.Restitution = 0.1f;
heavyBall.Velocity = new Vector2(2.0f, -0.5f);
world.AddBody(heavyBall);
// Small fast circle
Circle fastCircle = new Circle(new Vector2(1.0f, 2.0f), 0.2f, 2f);
fastCircle.BaseColor = Color.Yellow;
fastCircle.Restitution = 0.7f;
fastCircle.Friction = 0.2f;
fastCircle.Velocity = new Vector2(6.0f, 2.0f);
world.AddBody(fastCircle);
// Another box with high drag (will slow down quickly)
Box dragBox = new Box(new Vector2(10.0f, 2.0f), new Vector2(0.6f, 0.6f), 15f);
dragBox.BaseColor = Color.Violet;
dragBox.DragCoefficient = 2.0f;
dragBox.Velocity = new Vector2(-2.0f, -1.0f);
dragBox.AngularVelocity = 2.0f;
world.AddBody(dragBox);
// Circle with high drag (like a light ball in air)
Circle dragCircle = new Circle(new Vector2(3.0f, 3.0f), 0.4f, 8f);
dragCircle.BaseColor = Color.Pink;
dragCircle.DragCoefficient = 1.5f;
dragCircle.Velocity = new Vector2(1.0f, 3.0f);
world.AddBody(dragCircle);
// A box launched with an impulse at an offset (will spin)
Box spinningBox = new Box(new Vector2(7.0f, 2.5f), new Vector2(0.5f, 0.5f), 10f);
spinningBox.BaseColor = Color.Beige;
spinningBox.ApplyImpulseAtOffset(new Vector2(3.0f, -5.0f), new Vector2(0.25f, 0.0f));
world.AddBody(spinningBox);
// A circle launched with angular impulse
Circle spinningCircle = new Circle(new Vector2(11.0f, 1.0f), 0.35f, 12f);
spinningCircle.BaseColor = Color.Lime;
spinningCircle.ApplyImpulseAtOffset(new Vector2(0.0f, -8.0f), new Vector2(0.1f, 0.0f));
world.AddBody(spinningCircle);
}
private static void ScenarioLarge()
{
// Larger world dimensions
float worldWidth = 20.0f;
float worldHeight = 12.0f;
float wallThickness = 1.0f;
// 1. Static world borders
Box floor = new Box(new Vector2(worldWidth * 0.5f, worldHeight + (wallThickness * 0.5f)), new Vector2(worldWidth + wallThickness * 2, wallThickness), 0f);
floor.BaseColor = Color.DarkGray;
world.AddBody(floor);
Box ceiling = new Box(new Vector2(worldWidth * 0.5f, -wallThickness * 0.5f), new Vector2(worldWidth + wallThickness * 2, wallThickness), 0f);
ceiling.BaseColor = Color.DarkGray;
world.AddBody(ceiling);
Box leftWall = new Box(new Vector2(-wallThickness * 0.5f, worldHeight * 0.5f), new Vector2(wallThickness, worldHeight + wallThickness * 2), 0f);
leftWall.BaseColor = Color.DarkGray;
world.AddBody(leftWall);
Box rightWall = new Box(new Vector2(worldWidth + wallThickness * 0.5f, worldHeight * 0.5f), new Vector2(wallThickness, worldHeight + wallThickness * 2), 0f);
rightWall.BaseColor = Color.DarkGray;
world.AddBody(rightWall);
// 2. Static ramps (angled platforms)
Box ramp1 = new Box(new Vector2(4.0f, 9.0f), new Vector2(5.0f, 0.4f), 0f);
ramp1.Rotation = -0.35f;
ramp1.BaseColor = Color.Gray;
world.AddBody(ramp1);
Box ramp2 = new Box(new Vector2(16.0f, 9.0f), new Vector2(5.0f, 0.4f), 0f);
ramp2.Rotation = 0.35f;
ramp2.BaseColor = Color.Gray;
world.AddBody(ramp2);
// Static horizontal platforms
Box platform1 = new Box(new Vector2(7.0f, 6.0f), new Vector2(4.0f, 0.4f), 0f);
platform1.BaseColor = Color.LightGray;
world.AddBody(platform1);
Box platform2 = new Box(new Vector2(13.0f, 6.0f), new Vector2(4.0f, 0.4f), 0f);
platform2.BaseColor = Color.LightGray;
world.AddBody(platform2);
// Static vertical pillars to create obstacles
Box pillar1 = new Box(new Vector2(5.0f, 4.0f), new Vector2(0.3f, 3.0f), 0f);
pillar1.BaseColor = Color.DarkBrown;
world.AddBody(pillar1);
Box pillar2 = new Box(new Vector2(15.0f, 4.0f), new Vector2(0.3f, 3.0f), 0f);
pillar2.BaseColor = Color.DarkBrown;
world.AddBody(pillar2);
// Static circular bumpers
Circle bumper1 = new Circle(new Vector2(10.0f, 8.0f), 0.4f, 0f);
bumper1.BaseColor = Color.Orange;
world.AddBody(bumper1);
Circle bumper2 = new Circle(new Vector2(10.0f, 3.0f), 0.4f, 0f);
bumper2.BaseColor = Color.Orange;
world.AddBody(bumper2);
Circle bumper3 = new Circle(new Vector2(2.0f, 7.0f), 0.3f, 0f);
bumper3.BaseColor = Color.Orange;
world.AddBody(bumper3);
Circle bumper4 = new Circle(new Vector2(18.0f, 7.0f), 0.3f, 0f);
bumper4.BaseColor = Color.Orange;
world.AddBody(bumper4);
// 3. Dynamic bodies many with high energy, low damping
// High restitution balls (bouncy)
for (int i = 0; i < 6; i++)
{
Circle bouncyBall = new Circle(new Vector2(2.0f + i * 3.0f, 1.5f), 0.25f, 3.0f);
bouncyBall.BaseColor = Color.Red;
bouncyBall.Restitution = 0.95f;
bouncyBall.Friction = 0.05f;
bouncyBall.Velocity = new Vector2((i % 2 == 0 ? 3.0f : -3.0f), -2.0f);
bouncyBall.AngularVelocity = 5.0f;
world.AddBody(bouncyBall);
}
// Heavy boxes (low restitution, high friction)
Box heavy1 = new Box(new Vector2(6.0f, 2.0f), new Vector2(1.0f, 0.8f), 60f);
heavy1.BaseColor = Color.DarkGreen;
heavy1.Friction = 0.9f;
heavy1.Restitution = 0.0f;
heavy1.Velocity = new Vector2(2.0f, -1.0f);
world.AddBody(heavy1);
Box heavy2 = new Box(new Vector2(14.0f, 2.0f), new Vector2(1.0f, 0.8f), 60f);
heavy2.BaseColor = Color.DarkGreen;
heavy2.Friction = 0.9f;
heavy2.Restitution = 0.0f;
heavy2.Velocity = new Vector2(-2.0f, -1.0f);
world.AddBody(heavy2);
// Long planks (will slide and rotate)
Box plank1 = new Box(new Vector2(8.0f, 10.5f), new Vector2(3.0f, 0.3f), 20f);
plank1.BaseColor = Color.Brown;
plank1.Rotation = 0.1f;
plank1.AngularVelocity = -0.4f;
plank1.Friction = 0.6f;
plank1.Velocity = new Vector2(1.0f, -0.5f);
world.AddBody(plank1);
Box plank2 = new Box(new Vector2(12.0f, 10.5f), new Vector2(3.0f, 0.3f), 20f);
plank2.BaseColor = Color.Brown;
plank2.Rotation = -0.1f;
plank2.AngularVelocity = 0.4f;
plank2.Friction = 0.6f;
plank2.Velocity = new Vector2(-1.0f, -0.5f);
world.AddBody(plank2);
// Spinning boxes (launched with off-center impulses)
Box spinBox1 = new Box(new Vector2(5.0f, 7.0f), new Vector2(0.6f, 0.6f), 10f);
spinBox1.BaseColor = Color.Beige;
spinBox1.ApplyImpulseAtOffset(new Vector2(4.0f, -6.0f), new Vector2(0.3f, 0.0f));
world.AddBody(spinBox1);
Box spinBox2 = new Box(new Vector2(15.0f, 7.0f), new Vector2(0.6f, 0.6f), 10f);
spinBox2.BaseColor = Color.Beige;
spinBox2.ApplyImpulseAtOffset(new Vector2(-4.0f, -6.0f), new Vector2(-0.3f, 0.0f));
world.AddBody(spinBox2);
// Small fast circles
Circle fast1 = new Circle(new Vector2(3.0f, 11.0f), 0.2f, 2f);
fast1.BaseColor = Color.Yellow;
fast1.Restitution = 0.8f;
fast1.Friction = 0.2f;
fast1.Velocity = new Vector2(8.0f, 1.0f);
world.AddBody(fast1);
Circle fast2 = new Circle(new Vector2(17.0f, 11.0f), 0.2f, 2f);
fast2.BaseColor = Color.Yellow;
fast2.Restitution = 0.8f;
fast2.Friction = 0.2f;
fast2.Velocity = new Vector2(-8.0f, 1.0f);
world.AddBody(fast2);
// High-drag objects that still move initially
Box dragBox = new Box(new Vector2(10.0f, 9.0f), new Vector2(0.8f, 0.8f), 15f);
dragBox.BaseColor = Color.Violet;
dragBox.DragCoefficient = 2.0f;
dragBox.Velocity = new Vector2(3.0f, -2.0f);
dragBox.AngularVelocity = 2.0f;
world.AddBody(dragBox);
Circle dragCircle = new Circle(new Vector2(10.0f, 5.0f), 0.4f, 8f);
dragCircle.BaseColor = Color.Pink;
dragCircle.DragCoefficient = 1.5f;
dragCircle.Velocity = new Vector2(-2.0f, 3.0f);
world.AddBody(dragCircle);
// A few more random objects to fill the space
Circle extra1 = new Circle(new Vector2(1.5f, 5.0f), 0.35f, 12f);
extra1.BaseColor = Color.Lime;
extra1.Restitution = 0.7f;
extra1.Velocity = new Vector2(5.0f, -3.0f);
extra1.AngularVelocity = 8.0f;
world.AddBody(extra1);
Circle extra2 = new Circle(new Vector2(18.5f, 5.0f), 0.35f, 12f);
extra2.BaseColor = Color.Lime;
extra2.Restitution = 0.7f;
extra2.Velocity = new Vector2(-5.0f, -3.0f);
extra2.AngularVelocity = -8.0f;
world.AddBody(extra2);
Box extraBox = new Box(new Vector2(10.0f, 1.0f), new Vector2(1.2f, 0.6f), 25f);
extraBox.BaseColor = Color.SkyBlue;
extraBox.Velocity = new Vector2(0.5f, -2.0f);
world.AddBody(extraBox);
}
}
}