/// <inheritdoc /> public override void Draw(GameTime gameTime) { Game.Background = Color.Black; GraphicsDevice.DepthStencilState = DepthStencilState.Default; Floor.Draw(FloorWorld, Camera.View, Camera.Projection); BoxesWorld.ForEach(boxWorld => Box.Draw(boxWorld, Camera.View, Camera.Projection)); SpheresWorld.ForEach(sphereWorld => Sphere.Draw(sphereWorld, Camera.View, Camera.Projection)); base.Draw(gameTime); }
/// <inheritdoc /> public override void Draw(GameTime gameTime) { Game.Background = Color.Black; GraphicsDevice.DepthStencilState = DepthStencilState.Default; TilingEffect.Parameters["WorldViewProjection"].SetValue(FloorWorld * Camera.View * Camera.Projection); Floor.Draw(TilingEffect); BoxesWorld.ForEach(boxWorld => Box.Draw(boxWorld, Camera.View, Camera.Projection)); SpheresWorld.ForEach(sphereWorld => Sphere.Draw(sphereWorld, Camera.View, Camera.Projection)); Game.SpriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.Default, RasterizerState.CullCounterClockwise); Game.SpriteBatch.DrawString(SpriteFont, "Launch spheres with the 'Z' key.", new Vector2(GraphicsDevice.Viewport.Width - 400, 0), Color.White); Game.SpriteBatch.End(); base.Draw(gameTime); }
/// <inheritdoc /> public override void Update(GameTime gameTime) { // In the demos, we use one time step per frame. We don't bother modifying the physics time step duration for different monitors so different refresh rates // change the rate of simulation. This doesn't actually change the result of the simulation, though, and the simplicity is a good fit for the demos. // In the context of a 'real' application, you could instead use a time accumulator to take time steps of fixed length as needed, or // fully decouple simulation and rendering rates across different threads. // (In either case, you'd also want to interpolate or extrapolate simulation results during rendering for smoothness.) // Note that taking steps of variable length can reduce stability. Gradual or one-off changes can work reasonably well. Simulation.Timestep(1 / 60f, ThreadDispatcher); Camera.Update(gameTime); if (Game.CurrentKeyboardState.IsKeyDown(Keys.Z) && CanShoot) { CanShoot = false; // Create the shape that we'll launch at the pyramids when the user presses a button. var radius = 0.5f + 5 * (float)Random.NextDouble(); var bulletShape = new Sphere(radius); // Note that the use of radius^3 for mass can produce some pretty serious mass ratios. // Observe what happens when a large ball sits on top of a few boxes with a fraction of the mass- // the collision appears much squishier and less stable. For most games, if you want to maintain rigidity, you'll want to use some combination of: // 1) Limit the ratio of heavy object masses to light object masses when those heavy objects depend on the light objects. // 2) Use a shorter timestep duration and update more frequently. // 3) Use a greater number of solver iterations. // #2 and #3 can become very expensive. In pathological cases, it can end up slower than using a quality-focused solver for the same simulation. // Unfortunately, at the moment, bepuphysics v2 does not contain any alternative solvers, so if you can't afford to brute force the the problem away, // the best solution is to cheat as much as possible to avoid the corner cases. var position = new NumericVector3(-40 + 210 * (float)Random.NextDouble(), 130, 130); var bodyDescription = BodyDescription.CreateConvexDynamic(position, new BodyVelocity(new NumericVector3((float)Random.NextDouble(), 0, -110)), bulletShape.Radius * bulletShape.Radius * bulletShape.Radius, Simulation.Shapes, bulletShape); var bodyHandle = Simulation.Bodies.Add(bodyDescription); Radii.Add(radius); SphereHandles.Add(bodyHandle); } if (Game.CurrentKeyboardState.IsKeyUp(Keys.Z)) { CanShoot = true; } BoxesWorld.Clear(); var boxHandleCount = BoxHandles.Count; for (var index = 0; index < boxHandleCount; index++) { var pose = Simulation.Bodies.GetBodyReference(BoxHandles[index]).Pose; var position = pose.Position; var quaternion = pose.Orientation; var world = Matrix.CreateFromQuaternion(new Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W)) * Matrix.CreateTranslation(new Vector3(position.X, position.Y, position.Z)); BoxesWorld.Add(world); } SpheresWorld.Clear(); var sphereHandleCount = SphereHandles.Count; for (var index = 0; index < sphereHandleCount; index++) { var pose = Simulation.Bodies.GetBodyReference(SphereHandles[index]).Pose; var position = pose.Position; var quaternion = pose.Orientation; var world = Matrix.CreateScale(Radii[index]) * Matrix.CreateFromQuaternion(new Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W)) * Matrix.CreateTranslation(new Vector3(position.X, position.Y, position.Z)); SpheresWorld.Add(world); } Game.Gizmos.UpdateViewProjection(Camera.View, Camera.Projection); base.Update(gameTime); }