183 lines
6.7 KiB
C#
183 lines
6.7 KiB
C#
using System.Numerics;
|
|
using Raylib_cs;
|
|
|
|
namespace PhysicsEngine
|
|
{
|
|
class Program
|
|
{
|
|
private static Font robotoFont;
|
|
private static WorldModel world;
|
|
|
|
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();
|
|
|
|
Scenario();
|
|
|
|
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());
|
|
|
|
camera.DrawGrid();
|
|
|
|
// draw bodies
|
|
Raylib.BeginMode2D(camera.RaylibCamera);
|
|
RenderScene();
|
|
Raylib.EndMode2D();
|
|
|
|
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()
|
|
{
|
|
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;
|
|
floor.Friction = 0.9f;
|
|
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
|
|
Box platform = new Box(new Vector2(9.0f, 4.5f), new Vector2(3.5f, 0.3f), 0f);
|
|
platform.BaseColor = Color.Gray;
|
|
platform.Friction = 0.8f;
|
|
world.AddBody(platform);
|
|
|
|
Box ramp = new Box(new Vector2(2.0f, 3.5f), new Vector2(3.5f, 0.3f), 0f);
|
|
ramp.Rotation = 0.35f; // Slopes down toward center stack
|
|
ramp.BaseColor = Color.Gray;
|
|
ramp.Friction = 0.6f;
|
|
world.AddBody(ramp);
|
|
|
|
// 3. Main Ground Box Tower (5 boxes high)
|
|
float stackX = 5.0f;
|
|
float boxHeight = 0.6f;
|
|
float boxWidth = 0.6f;
|
|
float startY = worldHeight - (boxHeight * 0.5f); // Sits cleanly on the floor surface (Y = 7.2)
|
|
|
|
Color[] stackColors = new Color[]
|
|
{
|
|
Color.DarkGreen, Color.Green, Color.Lime, Color.DarkPurple, Color.Yellow
|
|
};
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
float y = startY - (i * boxHeight);
|
|
Box stackBox = new Box(new Vector2(stackX, y), new Vector2(boxWidth, boxHeight), 20f);
|
|
stackBox.BaseColor = stackColors[i % stackColors.Length];
|
|
stackBox.Friction = 0.8f;
|
|
stackBox.Restitution = 0.0f;
|
|
world.AddBody(stackBox);
|
|
}
|
|
|
|
// 4. Secondary Platform Stack (3 boxes high)
|
|
float platformStackX = 9.0f;
|
|
float platformTopY = 4.5f - 0.15f; // Top surface of platform
|
|
float platformStartY = platformTopY - (boxHeight * 0.5f);
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
float y = platformStartY - (i * boxHeight);
|
|
Box pBox = new Box(new Vector2(platformStackX, y), new Vector2(0.5f, boxHeight), 12f);
|
|
pBox.BaseColor = Color.Blue;
|
|
pBox.Friction = 0.8f;
|
|
pBox.Restitution = 0.0f;
|
|
world.AddBody(pBox);
|
|
}
|
|
|
|
// 5. Dynamic Circles for Stack Interaction
|
|
// Circle balanced on top of the main ground stack
|
|
float mainStackTopY = startY - (4 * boxHeight) - (boxHeight * 0.5f);
|
|
Circle stackCap = new Circle(new Vector2(stackX, mainStackTopY - 0.3f), 0.3f, 8f);
|
|
stackCap.BaseColor = Color.Orange;
|
|
stackCap.Friction = 0.8f;
|
|
stackCap.Restitution = 0.0f;
|
|
world.AddBody(stackCap);
|
|
|
|
// Heavy ball spawned on the ramp to roll down and strike the main stack
|
|
Circle rollingBall = new Circle(new Vector2(1.0f, 1.5f), 0.45f, 350f);
|
|
rollingBall.BaseColor = Color.Red;
|
|
rollingBall.Friction = 0.5f;
|
|
rollingBall.Restitution = 0.1f;
|
|
world.AddBody(rollingBall);
|
|
|
|
// Bouncy ball dropped over the platform stack to test stability under impact
|
|
Circle droppingBall = new Circle(new Vector2(9.0f, 0.8f), 0.35f, 10f);
|
|
droppingBall.BaseColor = Color.Gold;
|
|
droppingBall.Friction = 0.4f;
|
|
droppingBall.Restitution = 0.4f;
|
|
droppingBall.Velocity = new Vector2(0.0f, 2.0f);
|
|
world.AddBody(droppingBall);
|
|
}
|
|
}
|
|
} |