View difference between Paste ID: 8PJ02mdX and qrRZFMWr
SHOW: | | - or go back to the newest paste.
1
using BEPUphysics.BroadPhaseEntries;
2
using BEPUphysics.Entities.Prefabs;
3
using BEPUutilities;
4
using BEPUphysics.CollisionShapes.ConvexShapes;
5
using BEPUphysics.Entities;
6
using BEPUphysics.Constraints.SolverGroups;
7
using BEPUphysics.Paths;
8
using BEPUphysics.Paths.PathFollowing;
9
using BEPUphysics.Constraints.TwoEntity.Motors;
10
using BEPUphysics.CollisionShapes;
11
using System.Collections.Generic;
12
using Microsoft.Xna.Framework.Graphics;
13
// MCMONKEY - pay no mind to me "using" the everything.
14
using BEPUphysics.BroadPhaseEntries.MobileCollidables;
15
using System;
16
using BEPUphysics.BroadPhaseEntries.Events;
17
using BEPUphysics.OtherSpaceStages;
18
using BEPUphysics.NarrowPhaseSystems;
19
using BEPUphysics.BroadPhaseSystems;
20
using BEPUphysics.NarrowPhaseSystems.Pairs;
21
using BEPUphysics.CollisionRuleManagement;
22
using BEPUutilities.DataStructures;
23
using BEPUphysics.CollisionTests.Manifolds;
24
using BEPUphysics.Constraints.Collision;
25
using BEPUphysics.CollisionTests.CollisionAlgorithms.GJK;
26
using BEPUphysics.PositionUpdating;
27
using BEPUphysics.Settings;
28
using BEPUphysics.Materials;
29
using System.Linq;
30
using System.Text;
31
using BEPUphysics.CollisionTests.CollisionAlgorithms;
32
using BEPUutilities.ResourceManagement;
33
using BEPUphysics.CollisionTests;
34
// MCMONKEY - end spam of "using" statements
35
36
namespace BEPUphysicsDemos.Demos
37
{
38
39
    // MCMONKEY - begin custom stuffs
40
    
41
    public class VoxelWorldShape : CollisionShape
42
    {
43
        // NOTE: No need for an entire voxel system yet... let's just pretend the voxels make up a flat terrain at Y=0, covering 10,000*10,000 units.
44
        Box testShape = new Box(new Vector3(0, -5000, 0), 10 * 1000, 10 * 1000, 10 * 1000);
45
46
        public bool RayCast(ref Ray ray, float maximumLength, out RayHit hit)
47
        {
48
            return testShape.CollisionInformation.RayCast(ray, maximumLength, out hit);
49
        }
50
51
52
        public bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, out RayHit hit)
53
        {
54
            return testShape.CollisionInformation.ConvexCast(castShape, ref startingTransform, ref sweep, out hit);
55
        }
56
    }
57
58
    public class VoxelWorldObject : StaticCollidable
59
    {
60
        public static void RegisterMe()
61
        {
62
            NarrowPhasePairFactory<ConvexVoxelPairHandler> fact = new NarrowPhasePairFactory<ConvexVoxelPairHandler>();
63
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(ConvexCollidable<BoxShape>), typeof(VoxelWorldObject)), fact);
64
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(ConvexCollidable<SphereShape>), typeof(VoxelWorldObject)), fact);
65
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(ConvexCollidable<CapsuleShape>), typeof(VoxelWorldObject)), fact);
66
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(ConvexCollidable<TriangleShape>), typeof(VoxelWorldObject)), fact);
67
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(ConvexCollidable<CylinderShape>), typeof(VoxelWorldObject)), fact);
68
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(ConvexCollidable<ConeShape>), typeof(VoxelWorldObject)), fact);
69
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(ConvexCollidable<TransformableShape>), typeof(VoxelWorldObject)), fact);
70
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(ConvexCollidable<MinkowskiSumShape>), typeof(VoxelWorldObject)), fact);
71
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(ConvexCollidable<WrappedShape>), typeof(VoxelWorldObject)), fact);
72
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(ConvexCollidable<ConvexHullShape>), typeof(VoxelWorldObject)), fact);
73
            NarrowPhaseHelper.CollisionManagers.Add(new TypePair(typeof(TriangleCollidable), typeof(VoxelWorldObject)), fact);
74
        }
75
76
        public VoxelWorldObject()
77
        {
78
            WorldShape = new VoxelWorldShape();
79
            boundingBox = new BoundingBox(new Vector3(-5 * 1000, -10 * 1000, -5 * 1000), new Vector3(5 * 1000, 0, 5 * 1000));
80
        }
81
82
        public VoxelWorldShape WorldShape;
83
84
        public ContactEventManager<VoxelWorldObject> Events = new ContactEventManager<VoxelWorldObject>();
85
86
        protected override IContactEventTriggerer EventTriggerer
87
        {
88
            get { return Events; }
89
        }
90
91
        protected override IDeferredEventCreator EventCreator
92
        {
93
            get { return Events; }
94
        }
95
96
        public override void UpdateBoundingBox()
97
        {
98
            boundingBox = new BoundingBox(new Vector3(-5 * 1000, -10 * 1000, -5 * 1000), new Vector3(5 * 1000, 0, 5 * 1000));
99
        }
100
101
        public override bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, Func<BroadPhaseEntry, bool> filter, out RayHit hit)
102
        {
103
            return WorldShape.ConvexCast(castShape, ref startingTransform, ref sweep, out hit);
104
        }
105
106
        public override bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, out RayHit hit)
107
        {
108
            return ConvexCast(castShape, ref startingTransform, ref sweep, null, out hit);
109
        }
110
111
        public override bool RayCast(Ray ray, float maximumLength, Func<BroadPhaseEntry, bool> filter, out RayHit rayHit)
112
        {
113
            return WorldShape.RayCast(ref ray, maximumLength, out rayHit);
114
        }
115
116
        public override bool RayCast(Ray ray, float maximumLength, out RayHit rayHit)
117
        {
118
            return RayCast(ray, maximumLength, null, out rayHit);
119
        }
120
    }
121
122
    public class ConvexVoxelPairHandler : StandardPairHandler
123
    {
124
        VoxelWorldObject VWO = null;
125
126
        ConvexCollidable convex = null;
127
128
        private NonConvexContactManifoldConstraint contactConstraint;
129
        
130
        public override Collidable CollidableA
131
        {
132
            get { return convex; }
133
        }
134
135
        public override Collidable CollidableB
136
        {
137
            get { return VWO; }
138
        }
139
140
        public override Entity EntityA
141
        {
142
            get { return convex.Entity; }
143
        }
144
145
        public override Entity EntityB
146
        {
147
            get { return null; }
148
        }
149
150
        public override ContactManifoldConstraint ContactConstraint
151
        {
152
            get { return contactConstraint; }
153
        }
154
155
        public override ContactManifold ContactManifold
156
        {
157
            get { return contactManifold; }
158
        }
159
160
        VoxelContactManifold contactManifold = new VoxelContactManifold();
161
162
        public ConvexVoxelPairHandler()
163
        {
164
            contactConstraint = new NonConvexContactManifoldConstraint(this);
165
        }
166
167
        bool noRecurse = false;
168
        
169
        public override void Initialize(BroadPhaseEntry entryA, BroadPhaseEntry entryB)
170
        {
171
            if (noRecurse) // NOTE: Needed because UpdateMaterialProperties will call this,
172
            { // because we can't access the internal method that does the same code without calling init :(
173
                return;
174
            }
175
            noRecurse = true;
176
            VWO = entryA as VoxelWorldObject;
177
            convex = entryB as ConvexCollidable;
178
            if (VWO == null || convex == null)
179
            {
180
                VWO = entryB as VoxelWorldObject;
181
                convex = entryA as ConvexCollidable;
182
                if (VWO == null || convex == null)
183
                {
184
                    throw new ArgumentException("Inappropriate types used to initialize pair.");
185
                }
186
            }
187
            BroadPhaseOverlap = new BEPUphysics.BroadPhaseSystems.BroadPhaseOverlap(convex, VWO);
188
            UpdateMaterialProperties(convex.Entity != null ? convex.Entity.Material : null, VWO.Material);
189
            base.Initialize(entryA, entryB);
190
            // NOTE: Just in case, force friction off for testing's sake
191
            InteractionProperties ip = contactConstraint.MaterialInteraction;
192
            ip.StaticFriction = 0f;
193
            ip.KineticFriction = 0f;
194
            ip.Bounciness = 0.5f;
195
            contactConstraint.MaterialInteraction = ip;
196
            noRecurse = false;
197
        }
198
        
199
        ///<summary>
200
        /// Cleans up the pair handler.
201
        ///</summary>
202
        public override void CleanUp()
203
        {
204
            base.CleanUp();
205
206
            VWO = null;
207
            convex = null;
208
        }
209
        
210
        public override void UpdateTimeOfImpact(Collidable requester, float dt)
211
        {
212
            if (convex.Entity != null && convex.Entity.ActivityInformation.IsActive && convex.Entity.PositionUpdateMode == PositionUpdateMode.Continuous)
213
            {
214
                timeOfImpact = 1;
215
                RigidTransform rt = new RigidTransform(convex.Entity.Position, convex.Entity.Orientation);
216
                Vector3 sweep = convex.Entity.LinearVelocity;
217
                sweep *= dt;
218
                RayHit rh;
219
                if (VWO.ConvexCast(convex.Shape, ref rt, ref sweep, out rh))
220
                {
221
                    timeOfImpact = rh.T;
222
                }
223
                if (TimeOfImpact < 0)
224
                {
225
                    timeOfImpact = 0;
226
                }
227
            }
228
        }
229
        
230
        protected override void GetContactInformation(int index, out ContactInformation info)
231
        {
232
            ContactInformation ci = new ContactInformation();
233
            ci.Contact = contactManifold.ctcts[index];
234
            ci.Pair = this;
235
            ReadOnlyList<ContactPenetrationConstraint> list = contactConstraint.ContactPenetrationConstraints;
236
            float totalimp = 0;
237
            for (int i = 0; i < list.Count; i++)
238
            {
239
                totalimp += list[i].NormalImpulse;
240
            }
241
            ci.NormalImpulse = list[index].NormalImpulse;
242
            ci.FrictionImpulse = (ci.NormalImpulse / totalimp) * list[index].RelativeVelocity;
243
            if (convex.Entity != null)
244
            {
245
                Vector3 velocity;
246
                Vector3 cep = convex.Entity.Position;
247
                Vector3 ceav = convex.Entity.AngularVelocity;
248
                Vector3 celv = convex.Entity.LinearVelocity;
249
                Vector3.Subtract(ref ci.Contact.Position, ref cep, out velocity);
250
                Vector3.Cross(ref ceav, ref velocity, out velocity);
251
                Vector3.Add(ref velocity, ref celv, out ci.RelativeVelocity);
252
            }
253
            else
254
            {
255
                ci.RelativeVelocity = new Vector3(0, 0, 0);
256
            }
257
            info = ci;
258
        }
259
    }
260
261
262
    public class VoxelContactManifold : ContactManifold
263
    {
264
        protected ConvexCollidable convex;
265
266
        protected VoxelWorldObject vwo;
267
268
        public override void Initialize(Collidable newCollidableA, Collidable newCollidableB)
269
        {
270
            convex = newCollidableA as ConvexCollidable;
271
            vwo = newCollidableB as VoxelWorldObject;
272
            if (convex == null || vwo == null)
273
            {
274
                convex = newCollidableB as ConvexCollidable;
275
                vwo = newCollidableA as VoxelWorldObject;
276
                if (convex == null || vwo == null)
277
                {
278
                    throw new ArgumentException("Inappropriate types used to initialize contact manifold.");
279
                }
280
            }
281
        }
282
283
        public VoxelContactManifold()
284
        {
285
            contacts = new RawList<Contact>();
286
            unusedContacts = new UnsafeResourcePool<Contact>(4);
287
            contactIndicesToRemove = new RawList<int>();
288
        }
289
290
        public RawList<Contact> ctcts
291
        {
292
            get
293
            {
294
                return contacts;
295
            }
296
        }
297
298
        public static bool IsNaNOrInfOrZero(ref Vector3 vec)
299
        {
300
            return float.IsInfinity(vec.X) || float.IsNaN(vec.X)
301
                || float.IsInfinity(vec.Y) || float.IsNaN(vec.Y)
302
                || float.IsInfinity(vec.Z) || float.IsNaN(vec.Z) || (vec.X == 0 && vec.Y == 0 && vec.Z == 0);
303
        }
304
305
        public static bool IsNaNOrInf(ref Vector3 vec)
306
        {
307
            return float.IsInfinity(vec.X) || float.IsNaN(vec.X)
308
                || float.IsInfinity(vec.Y) || float.IsNaN(vec.Y)
309
                || float.IsInfinity(vec.Z) || float.IsNaN(vec.Z);
310
        }
311
312
        public override void Update(float dt)
313
        {
314
315
            RigidTransform rt = convex.Entity == null ? convex.WorldTransform : new RigidTransform(convex.Entity.Position, convex.Entity.Orientation);
316
            if (IsNaNOrInf(ref rt.Position))
317
            {
318
                for (int i = contacts.Count - 1; i >= 0; i--)
319
                {
320
                    Remove(i);
321
                }
322
                return;
323
            }
324
            Vector3 sw = new Vector3(0, 0, 1f);
325
            if (convex.Entity != null)
326
            {
327
                sw = convex.Entity.LinearVelocity;
328
            }
329
            RayHit rh;
330
            bool hit = vwo.ConvexCast(convex.Shape, ref rt, ref sw, out rh);
331
            if (!hit || IsNaNOrInfOrZero(ref rh.Normal))
332
            {
333
                for (int i = contacts.Count - 1; i >= 0; i--)
334
                {
335
                    Remove(i);
336
                }
337
                return;
338
            }
339-
            float pendef = convex.BoundingBox.Min.Z; // NOTE: not sure whether to negate this
339+
            float pendef = convex.BoundingBox.Min.Y; // NOTE: not sure whether to negate this
340
            Vector3 norm;
341
            RigidTransform rtx = new RigidTransform(Vector3.Zero, rt.Orientation);
342
            RigidTransform.Transform(ref rh.Normal, ref rtx, out norm);
343
            norm = -norm; // TODO: Why must we negate here?
344
            for (int i = contacts.Count - 1; i >= 0; i--)
345
            {
346
                contacts[i].Normal = norm;
347
                contacts[i].Position = rh.Location;
348
                contacts[i].PenetrationDepth = pendef;
349
            }
350
            if (Contacts.Count == 0)
351
            {
352
                ContactData cd = new ContactData();
353
                cd.Normal = norm;
354
                cd.Position = rh.Location;
355
                cd.PenetrationDepth = pendef;
356
                cd.Id = contacts.Count;
357
                Add(ref cd);
358
            }
359
        }
360
361
        public override void CleanUp()
362
        {
363
            convex = null;
364
            vwo = null;
365
            base.CleanUp();
366
        }
367
    }
368
369
    // MCMONKEY - end custom stuffs
370
371
    /// <summary>
372
    /// A playground for the character controller to frolic in.
373
    /// </summary>
374
    public class CharacterPlaygroundDemo : StandardDemo
375
    {
376
        /// <summary>
377
        /// Constructs a new demo.
378
        /// </summary>
379
        /// <param name="game">Game owning this demo.</param>
380
        public CharacterPlaygroundDemo(DemosGame game)
381
            : base(game)
382
        {
383
            VoxelWorldObject.RegisterMe(); // MCMONKEY -> Register the voxel world!
384
            Space.Add(new VoxelWorldObject()); // MCMONKEY -> Add a voxel world to the space!
385
386
            game.Camera.Position = new Vector3(-10, 7, 5);
387
            game.Camera.ViewDirection = new Vector3(0, 0, 1);
388
            //Since this is the character playground, turn on the character by default.
389
            character.Activate();
390
            //Having the character body visible would be a bit distracting.
391
            character.CharacterController.Body.Tag = "noDisplayObject";
392
393
            //Load in mesh data for the environment.
394
            Vector3[] staticTriangleVertices;
395
            int[] staticTriangleIndices;
396
397
398
            var playgroundModel = game.Content.Load<Model>("CharacterControllerTestTerrain");
399
            //This is a little convenience method used to extract vertices and indices from a model.
400
            //It doesn't do anything special; any approach that gets valid vertices and indices will work.
401
            ModelDataExtractor.GetVerticesAndIndicesFromModel(playgroundModel, out staticTriangleVertices, out staticTriangleIndices);
402
            var staticMesh = new StaticMesh(staticTriangleVertices, staticTriangleIndices, new AffineTransform(new Vector3(0.01f, 0.01f, 0.01f), Quaternion.Identity, new Vector3(0, 0, 0)));
403
            staticMesh.Sidedness = TriangleSidedness.Counterclockwise;
404
405
            Space.Add(staticMesh);
406
            game.ModelDrawer.Add(staticMesh);
407
408
409
410
            //Add a spinning blade for the character to ram itself into.
411
            var fanBase = new Cylinder(new Vector3(-13, .5f, 50), 1.1f, 1);
412
            var fanBlade = new Box(fanBase.Position + new Vector3(0, .8f, 0), 5, .1f, 1f, 5);
413
            var fanJoint = new RevoluteJoint(fanBase, fanBlade, (fanBase.Position + fanBlade.Position) * .5f, Vector3.Up);
414
            fanJoint.Motor.IsActive = true;
415
            fanJoint.Motor.Settings.VelocityMotor.GoalVelocity = 30;
416
            fanJoint.Motor.Settings.MaximumForce = 300;
417
            Space.Add(fanBase);
418
            Space.Add(fanBlade);
419
            Space.Add(fanJoint);
420
421
            //Add a bridge connecting the two towers.
422
            Vector3 startPosition = new Vector3(-19.3f, 10.5f - .25f, 23 - .85f);
423
            var startPlatform = new Box(startPosition - new Vector3(0, 0, 2.2f), 4, .5f, 6);
424
            Space.Add(startPlatform);
425
            Vector3 offset = new Vector3(0, 0, 1.7f);
426
            Box previousLink = startPlatform;
427
            Vector3 position = new Vector3();
428
            for (int i = 1; i <= 7; i++)
429
            {
430
                position = startPosition + offset * i;
431
                Box link = new Box(position, 3, .3f, 1.5f, 50);
432
                link.LinearDamping = .1f;
433
                link.AngularDamping = .1f;
434
                Space.Add(link);
435
                Space.Add(new RevoluteJoint(previousLink, link, position - offset * .5f, Vector3.Right));
436
437
                previousLink = link;
438
            }
439
            var endPlatform = new Box(position - new Vector3(0, 0, -3.8f), 4, .5f, 6);
440
            Space.Add(endPlatform);
441
442
            Space.Add(new RevoluteJoint(previousLink, endPlatform, position + offset * .5f, Vector3.Right));
443
444
445
            //Add in a floating platform controlled by a curve to serve as an elevator.
446
            Entity movingEntity = new Box(new Vector3(-10, 0, -10), 3, 1, 3);
447
448
            var positionCurve = new CardinalSpline3D();
449
450
            positionCurve.PreLoop = CurveEndpointBehavior.Mirror;
451
            positionCurve.PostLoop = CurveEndpointBehavior.Mirror;
452
453
            positionCurve.ControlPoints.Add(-1, new Vector3(-19.3f, 0, 43));
454
            positionCurve.ControlPoints.Add(0, new Vector3(-19.3f, 0, 43));
455
            positionCurve.ControlPoints.Add(2, new Vector3(-19.3f, 0, 43));
456
            positionCurve.ControlPoints.Add(3, new Vector3(-19.3f, 0, 43));
457
            positionCurve.ControlPoints.Add(4, new Vector3(-19.3f, 5, 43));
458
            positionCurve.ControlPoints.Add(5f, new Vector3(-19.3f, 10, 43));
459
            positionCurve.ControlPoints.Add(6f, new Vector3(-19.3f, 10, 43));
460
            positionCurve.ControlPoints.Add(8f, new Vector3(-19.3f, 10, 43));
461
            positionCurve.ControlPoints.Add(9f, new Vector3(-19.3f, 10, 43));
462
463
            elevatorMover = new EntityMover(movingEntity);
464
            Space.Add(elevatorMover);
465
            Space.Add(movingEntity);
466
467
            elevatorPath = positionCurve;
468
469
            //Add in another floating platform controlled by a curve for horizontal transport.
470
            movingEntity = new Box(new Vector3(-10, 0, -10), 2.5f, .5f, 2.5f);
471
472
            var platformCurve = new LinearInterpolationCurve3D();
473
474
            platformCurve.PreLoop = CurveEndpointBehavior.Mirror;
475
            platformCurve.PostLoop = CurveEndpointBehavior.Mirror;
476
477
            platformCurve.ControlPoints.Add(0, new Vector3(-1.75f, 10, 21.5f));
478
            platformCurve.ControlPoints.Add(2, new Vector3(-1.75f, 10, 21.5f));
479
            platformCurve.ControlPoints.Add(5, new Vector3(-1.75f, 10, 15.5f));
480
            platformCurve.ControlPoints.Add(10, new Vector3(-19.3f, 10, 15.5f));
481
            platformCurve.ControlPoints.Add(12, new Vector3(-19.3f, 10, 15.5f));
482
            platformCurve.ControlPoints.Add(15, new Vector3(-25, 10, 15.5f));
483
            platformCurve.ControlPoints.Add(22, new Vector3(-25, 10, 38));
484
            platformCurve.ControlPoints.Add(23, new Vector3(-22.75f, 10, 38));
485
            platformCurve.ControlPoints.Add(25, new Vector3(-22.75f, 10, 38));
486
487
            //Make it spin too.  That'll be fun.  Or something.
488
            var platformRotationCurve = new QuaternionSlerpCurve();
489
            platformRotationCurve.PreLoop = CurveEndpointBehavior.Mirror;
490
            platformRotationCurve.PostLoop = CurveEndpointBehavior.Mirror;
491
            platformRotationCurve.ControlPoints.Add(0, Quaternion.Identity);
492
            platformRotationCurve.ControlPoints.Add(15, Quaternion.Identity);
493
            platformRotationCurve.ControlPoints.Add(22, Quaternion.CreateFromAxisAngle(Vector3.Up, MathHelper.PiOver2));
494
            platformRotationCurve.ControlPoints.Add(25, Quaternion.CreateFromAxisAngle(Vector3.Up, MathHelper.PiOver2));
495
496
            platformMover = new EntityMover(movingEntity);
497
            platformRotator = new EntityRotator(movingEntity);
498
            Space.Add(platformMover);
499
            Space.Add(platformRotator);
500
            Space.Add(movingEntity);
501
502
            platformPath = platformCurve;
503
            platformOrientationPath = platformRotationCurve;
504
505
            //Add in a diving board.
506
507
            Box divingBoardBase = new Box(new Vector3(-9, 10, 39.3f), 5, 1, 3);
508
            Box divingBoard = new Box(divingBoardBase.Position + new Vector3(-2, 0, 3.5f), 1, .3f, 3, 5);
509
            var divingBoardJoint = new RevoluteJoint(divingBoardBase, divingBoard, divingBoard.Position + new Vector3(0, 0, -1.5f), Vector3.Right);
510
            divingBoardJoint.Motor.IsActive = true;
511
            divingBoardJoint.Motor.Settings.Mode = MotorMode.Servomechanism;
512
            divingBoardJoint.Motor.Settings.Servo.Goal = 0;
513
            divingBoardJoint.Motor.Settings.Servo.SpringSettings.Stiffness = 5000;
514
            divingBoardJoint.Motor.Settings.Servo.SpringSettings.Damping = 0;
515
516
            Space.Add(divingBoardBase);
517
            Space.Add(divingBoard);
518
            Space.Add(divingBoardJoint);
519
520
521
            //Add a second diving board for comparison.
522
523
            Box divingBoard2 = new Box(divingBoardBase.Position + new Vector3(2, 0, 5f), 1, .3f, 6, 5);
524
            var divingBoardJoint2 = new RevoluteJoint(divingBoardBase, divingBoard2, divingBoard2.Position + new Vector3(0, 0, -3), Vector3.Right);
525
            divingBoardJoint2.Motor.IsActive = true;
526
            divingBoardJoint2.Motor.Settings.Mode = MotorMode.Servomechanism;
527
            divingBoardJoint2.Motor.Settings.Servo.Goal = 0;
528
            divingBoardJoint2.Motor.Settings.Servo.SpringSettings.Stiffness = 10000;
529
            divingBoardJoint2.Motor.Settings.Servo.SpringSettings.Damping = 0;
530
531
            Space.Add(divingBoard2);
532
            Space.Add(divingBoardJoint2);
533
534
            //Add a seesaw for people to jump on.
535
            Box seesawBase = new Box(new Vector3(-7, .45f, 52), 1, .9f, .3f);
536
            Box seesawPlank = new Box(seesawBase.Position + new Vector3(0, .65f, 0), 1.2f, .2f, 6, 3);
537
            RevoluteJoint seesawJoint = new RevoluteJoint(seesawBase, seesawPlank, seesawPlank.Position, Vector3.Right);
538
            Space.Add(seesawJoint);
539
            Space.Add(seesawBase);
540
            Space.Add(seesawPlank);
541
542
            Space.Add(new Box(seesawPlank.Position + new Vector3(0, 1.3f, 2), 1, 1, 1, 5));
543
544
545
            //Add in some boxes to bump and jump on.
546
            int numColumns = 3;
547
            int numRows = 3;
548
            int numHigh = 3;
549
            float xSpacing = 1.01f;
550
            float ySpacing = 1.01f;
551
            float zSpacing = 1.01f;
552
            for (int i = 0; i < numRows; i++)
553
                for (int j = 0; j < numColumns; j++)
554
                    for (int k = 0; k < numHigh; k++)
555
                    {
556
                        Space.Add(new Box(new Vector3(
557
                                                 5 + xSpacing * i - (numRows - 1) * xSpacing / 2f,
558
                                                 1.58f + k * (ySpacing),
559
                                                 45 + zSpacing * j - (numColumns - 1) * zSpacing / 2f),
560
                                             .5f, .5f, .5f, 5));
561
                    }
562
563
564
565
            //Add a log to roll!
566
            //Make it a compound so some boxes can be added to let the player know it's actually spinning.
567
            CompoundBody log = new CompoundBody(new List<CompoundShapeEntry>()
568
            {
569
                new CompoundShapeEntry(new CylinderShape(4, 1.8f), Quaternion.CreateFromAxisAngle(Vector3.Forward, MathHelper.PiOver2), 20),
570
                new CompoundShapeEntry(new BoxShape(.5f, .5f, 3.7f),  new Vector3(1.75f, 0,0), 0),
571
                new CompoundShapeEntry(new BoxShape(.5f, 3.7f, .5f), new Vector3(1.75f, 0,0), 0),
572
                new CompoundShapeEntry(new BoxShape(.5f, .5f, 3.7f),  new Vector3(-1.75f, 0,0), 0),
573
                new CompoundShapeEntry(new BoxShape(.5f, 3.7f, .5f), new Vector3(-1.75f, 0,0), 0)
574
            }, 50);
575
            log.Position = new Vector3(-14.5f, 10, 41);
576
            log.AngularDamping = 0;
577
578
579
            RevoluteJoint logJointA = new RevoluteJoint(divingBoardBase, log, log.Position + new Vector3(2.5f, 0, 0), Vector3.Right);
580
            RevoluteJoint logJointB = new RevoluteJoint(endPlatform, log, log.Position + new Vector3(-2.5f, 0, 0), Vector3.Right);
581
            Space.Add(logJointA);
582
            Space.Add(logJointB);
583
584
            Space.Add(log);
585
586
587
            //Put some planks to stand on that show various slopes.
588
            int numPads = 10;
589
            for (int i = 0; i < numPads; i++)
590
            {
591
                offset = new Vector3(0, 0, 4);
592
                Box a = new Box(new Vector3(i * 1.5f + 3.5f, 10, 24), 1.5f, 1, 4);
593
                Box b = new Box(new Vector3(i * 1.5f + 3.5f, 10, 24), 1.5f, 1, 4);
594
                float angle = -i * MathHelper.PiOver2 / numPads;
595
                b.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Right, angle);
596
                b.Position += offset * .5f + Quaternion.Transform(offset * .5f, b.Orientation);
597
598
                Space.Add(a);
599
                Space.Add(b);
600
            }
601
602
        }
603
604
        EntityMover elevatorMover;
605
        Path<Vector3> elevatorPath;
606
        EntityMover platformMover;
607
        EntityRotator platformRotator;
608
        Path<Vector3> platformPath;
609
        Path<Quaternion> platformOrientationPath;
610
        double pathTime;
611
612
613
        public override void Update(float dt)
614
        {
615
            //Increment the time.  Note that the space's timestep is used
616
            //instead of the method's dt.  This is because the demos, by
617
            //default, update the space once each game update.  Using the
618
            //space's update time keeps things synchronized.
619
            //If the engine is using internal time stepping,
620
            //the passed in dt should be used instead (or put this logic into
621
            //an updateable that runs with space updates).
622
            pathTime += Space.TimeStepSettings.TimeStepDuration;
623
            elevatorMover.TargetPosition = elevatorPath.Evaluate(pathTime);
624
            platformMover.TargetPosition = platformPath.Evaluate(pathTime);
625
            platformRotator.TargetOrientation = platformOrientationPath.Evaluate(pathTime);
626
            base.Update(dt);
627
        }
628
629
        public override void DrawUI()
630
        {
631
#if XBOX360
632
            Game.DataTextDrawer.Draw("Press \"A\" to toggle the character.", new Microsoft.Xna.Framework.(50, 50));
633
#else
634
            Game.DataTextDrawer.Draw("Press \"C\" to toggle the character.", new Microsoft.Xna.Framework.Vector2(50, 50));
635
#endif
636
            base.DrawUI();
637
        }
638
639
        /// <summary>
640
        /// Gets the name of the simulation.
641
        /// </summary>
642
        public override string Name
643
        {
644
            get { return "Character Playground"; }
645
        }
646
    }
647
}