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); } } }