rigidbody, forces and collision testing
This commit is contained in:
392
PhysicsEngine/Core/Program.cs
Normal file
392
PhysicsEngine/Core/Program.cs
Normal file
@@ -0,0 +1,392 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user