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