public override void Bind(Entity result, Main main, bool creating = false) { base.Bind(result, main); Transform transform = result.Get<Transform>(); DynamicMap map = result.Get<DynamicMap>(); Direction initialDirection = result.GetProperty<Direction>("Direction"); Direction dir = initialDirection; Entity.Handle limit1 = result.GetProperty<Entity.Handle>("Limit 1"); Entity.Handle limit2 = result.GetProperty<Entity.Handle>("Limit 2"); Property<bool> isAtStart = new Property<bool> { Editable = false, Serialize = false }; Property<bool> isAtEnd = new Property<bool> { Editable = false, Serialize = false }; result.Add("IsAtStart", isAtStart); result.Add("IsAtEnd", isAtEnd); EntityMover mover = null; EntityRotator rotator = null; if (!main.EditorEnabled) { mover = new EntityMover(map.PhysicsEntity); mover.TargetPosition = transform.Position; main.Space.Add(mover); rotator = new EntityRotator(map.PhysicsEntity); rotator.TargetOrientation = transform.Quaternion; main.Space.Add(rotator); } Vector3 targetPosition = transform.Position; Property<float> speed = result.GetProperty<float>("Speed"); Property<bool> stopOnEnd = result.GetProperty<bool>("StopOnEnd"); Updater update = null; update = new Updater { delegate(float dt) { if (!result.Active || limit1.Target == null || limit2.Target == null) return; float currentLocation = targetPosition.GetComponent(dir); targetPosition = targetPosition.SetComponent(dir, currentLocation + dt * speed); mover.TargetPosition = targetPosition; float limit1Location = limit1.Target.Get<Transform>().Position.Value.GetComponent(dir); float limit2Location = limit2.Target.Get<Transform>().Position.Value.GetComponent(dir); float limitLocation = Math.Max(limit1Location, limit2Location); if (currentLocation > limitLocation) { dir = dir.GetReverse(); if (limitLocation == limit1Location) { isAtStart.Value = true; isAtEnd.Value = false; } else { isAtStart.Value = false; isAtEnd.Value = true; } if (stopOnEnd) update.Enabled.Value = false; } } }; update.Add(new TwoWayBinding<bool>(result.GetProperty<bool>("Enabled"), update.Enabled)); result.Add(update); }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public PathFollowingDemo(DemosGame game) : base(game) { Entity movingEntity; //The moving entity can be either kinematic or dynamic; the EntityMover/Rotator works for either. movingEntity = new Box(new Vector3(-10, 0, -10), 3, 1, 1); //We're going to use a speed-controlled curve that wraps another curve. //This is the internal curve. //Speed-controlled curves let the user specify speeds at which an evaluator //will move along the curve. Non-speed controlled curves can move at variable //rates based on the interpolation. var wrappedPositionCurve = new CardinalSpline3D(); //Since the endpoints don't overlap, just reverse direction when they're hit. //The default is wrapping around; if there's a distance between the starting //and ending endpoints, the entity will jump very quickly (smashing anything in the way). wrappedPositionCurve.PreLoop = CurveEndpointBehavior.Mirror; wrappedPositionCurve.PostLoop = CurveEndpointBehavior.Mirror; //Start the curve up above the blocks. //There's two control points because the very first and very last control points //aren't actually reached by the curve in a CardinalSpline3D; they are used //to define the tangents on the interior points. wrappedPositionCurve.ControlPoints.Add(-1, new Vector3(0, 30, 0)); wrappedPositionCurve.ControlPoints.Add(0f, new Vector3(0, 20, 0)); //Add a bunch of random control points to the curve. var random = new Random(); for (int i = 1; i <= 10; i++) { wrappedPositionCurve.ControlPoints.Add(i, new Vector3( (float) random.NextDouble() * 20 - 10, (float) random.NextDouble() * 12, (float) random.NextDouble() * 20 - 10)); } positionPath = wrappedPositionCurve; //There's also a constant speed and variable speed curve type that can be used. //Try the following instead to move the entity at a constant rate: //positionPath = new ConstantLinearSpeedCurve(5, wrappedPositionCurve); var slerpCurve = new QuaternionSlerpCurve(); slerpCurve.ControlPoints.Add(0, Quaternion.Identity); slerpCurve.ControlPoints.Add(1, Quaternion.CreateFromAxisAngle(Vector3.Up, MathHelper.PiOver2)); slerpCurve.ControlPoints.Add(2, Quaternion.CreateFromAxisAngle(Vector3.Up, MathHelper.Pi)); slerpCurve.ControlPoints.Add(3, Quaternion.CreateFromAxisAngle(Vector3.Up, 3 * MathHelper.PiOver2)); slerpCurve.ControlPoints.Add(4, Quaternion.Identity); slerpCurve.PostLoop = CurveEndpointBehavior.Mirror; orientationPath = slerpCurve; mover = new EntityMover(movingEntity); //Offset the place that the mover tries to reach a little. //Now, when the entity spins, it acts more like a hammer swing than a saw. mover.LocalOffset = new Vector3(3, 0, 0); rotator = new EntityRotator(movingEntity); //Add the entity and movers to the space. Space.Add(movingEntity); Space.Add(mover); Space.Add(rotator); //Add some extra stuff to the space. Space.Add(new Box(new Vector3(0, -5, 0), 25, 10, 25)); int numColumns = 7; int numRows = 7; int numHigh = 3; float xSpacing = 2.09f; float ySpacing = 2.08f; float zSpacing = 2.09f; for (int i = 0; i < numRows; i++) for (int j = 0; j < numColumns; j++) for (int k = 0; k < numHigh; k++) { Space.Add(new Box(new Vector3( xSpacing * i - (numRows - 1) * xSpacing / 2f, 1.58f + k * (ySpacing), 2 + zSpacing * j - (numColumns - 1) * zSpacing / 2f), 2, 2, 2, 10)); } game.Camera.Position = new Vector3(0, 5, 30); }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public CharacterPlaygroundDemo(DemosGame game) : base(game) { game.Camera.Position = new Vector3(-10, 7, 5); game.Camera.ViewDirection = new Vector3(0, 0, 1); //Since this is the character playground, turn on the character by default. character.Activate(); //Having the character body visible would be a bit distracting. character.CharacterController.Body.Tag = "noDisplayObject"; //Load in mesh data for the environment. Vector3[] staticTriangleVertices; int[] staticTriangleIndices; var playgroundModel = game.Content.Load<Model>("CharacterControllerTestTerrain"); //This is a little convenience method used to extract vertices and indices from a model. //It doesn't do anything special; any approach that gets valid vertices and indices will work. ModelDataExtractor.GetVerticesAndIndicesFromModel(playgroundModel, out staticTriangleVertices, out staticTriangleIndices); var staticMesh = new StaticMesh(staticTriangleVertices, staticTriangleIndices, new AffineTransform(new Vector3(0.01f, 0.01f, 0.01f), Quaternion.Identity, new Vector3(0, 0, 0))); staticMesh.Sidedness = TriangleSidedness.Counterclockwise; Space.Add(staticMesh); game.ModelDrawer.Add(staticMesh); //Add a spinning blade for the character to ram itself into. var fanBase = new Cylinder(new Vector3(-13, .5f, 50), 1.1f, 1); var fanBlade = new Box(fanBase.Position + new Vector3(0, .8f, 0), 5, .1f, 1f, 5); var fanJoint = new RevoluteJoint(fanBase, fanBlade, (fanBase.Position + fanBlade.Position) * .5f, Vector3.Up); fanJoint.Motor.IsActive = true; fanJoint.Motor.Settings.VelocityMotor.GoalVelocity = 30; fanJoint.Motor.Settings.MaximumForce = 300; Space.Add(fanBase); Space.Add(fanBlade); Space.Add(fanJoint); //Add a bridge connecting the two towers. Vector3 startPosition = new Vector3(-19.3f, 10.5f - .25f, 23 - .85f); var startPlatform = new Box(startPosition - new Vector3(0, 0, 2.2f), 4, .5f, 6); Space.Add(startPlatform); Vector3 offset = new Vector3(0, 0, 1.7f); Box previousLink = startPlatform; Vector3 position = new Vector3(); for (int i = 1; i <= 7; i++) { position = startPosition + offset * i; Box link = new Box(position, 3, .3f, 1.5f, 50); link.LinearDamping = .1f; link.AngularDamping = .1f; Space.Add(link); Space.Add(new RevoluteJoint(previousLink, link, position - offset * .5f, Vector3.Right)); previousLink = link; } var endPlatform = new Box(position - new Vector3(0, 0, -3.8f), 4, .5f, 6); Space.Add(endPlatform); Space.Add(new RevoluteJoint(previousLink, endPlatform, position + offset * .5f, Vector3.Right)); //Add in a floating platform controlled by a curve to serve as an elevator. Entity movingEntity = new Box(new Vector3(-10, 0, -10), 3, 1, 3); var positionCurve = new CardinalSpline3D(); positionCurve.PreLoop = CurveEndpointBehavior.Mirror; positionCurve.PostLoop = CurveEndpointBehavior.Mirror; positionCurve.ControlPoints.Add(-1, new Vector3(-19.3f, 0, 43)); positionCurve.ControlPoints.Add(0, new Vector3(-19.3f, 0, 43)); positionCurve.ControlPoints.Add(2, new Vector3(-19.3f, 0, 43)); positionCurve.ControlPoints.Add(3, new Vector3(-19.3f, 0, 43)); positionCurve.ControlPoints.Add(4, new Vector3(-19.3f, 5, 43)); positionCurve.ControlPoints.Add(5f, new Vector3(-19.3f, 10, 43)); positionCurve.ControlPoints.Add(6f, new Vector3(-19.3f, 10, 43)); positionCurve.ControlPoints.Add(8f, new Vector3(-19.3f, 10, 43)); positionCurve.ControlPoints.Add(9f, new Vector3(-19.3f, 10, 43)); elevatorMover = new EntityMover(movingEntity); Space.Add(elevatorMover); Space.Add(movingEntity); elevatorPath = positionCurve; //Add in another floating platform controlled by a curve for horizontal transport. movingEntity = new Box(new Vector3(-10, 0, -10), 2.5f, .5f, 2.5f); var platformCurve = new LinearInterpolationCurve3D(); platformCurve.PreLoop = CurveEndpointBehavior.Mirror; platformCurve.PostLoop = CurveEndpointBehavior.Mirror; platformCurve.ControlPoints.Add(0, new Vector3(-1.75f, 10, 21.5f)); platformCurve.ControlPoints.Add(2, new Vector3(-1.75f, 10, 21.5f)); platformCurve.ControlPoints.Add(5, new Vector3(-1.75f, 10, 15.5f)); platformCurve.ControlPoints.Add(10, new Vector3(-19.3f, 10, 15.5f)); platformCurve.ControlPoints.Add(12, new Vector3(-19.3f, 10, 15.5f)); platformCurve.ControlPoints.Add(15, new Vector3(-25, 10, 15.5f)); platformCurve.ControlPoints.Add(22, new Vector3(-25, 10, 38)); platformCurve.ControlPoints.Add(23, new Vector3(-22.75f, 10, 38)); platformCurve.ControlPoints.Add(25, new Vector3(-22.75f, 10, 38)); //Make it spin too. That'll be fun. Or something. var platformRotationCurve = new QuaternionSlerpCurve(); platformRotationCurve.PreLoop = CurveEndpointBehavior.Mirror; platformRotationCurve.PostLoop = CurveEndpointBehavior.Mirror; platformRotationCurve.ControlPoints.Add(0, Quaternion.Identity); platformRotationCurve.ControlPoints.Add(15, Quaternion.Identity); platformRotationCurve.ControlPoints.Add(22, Quaternion.CreateFromAxisAngle(Vector3.Up, MathHelper.PiOver2)); platformRotationCurve.ControlPoints.Add(25, Quaternion.CreateFromAxisAngle(Vector3.Up, MathHelper.PiOver2)); platformMover = new EntityMover(movingEntity); platformRotator = new EntityRotator(movingEntity); Space.Add(platformMover); Space.Add(platformRotator); Space.Add(movingEntity); platformPath = platformCurve; platformOrientationPath = platformRotationCurve; //Add in a diving board. Box divingBoardBase = new Box(new Vector3(-9, 10, 39.3f), 5, 1, 3); Box divingBoard = new Box(divingBoardBase.Position + new Vector3(-2, 0, 3.5f), 1, .3f, 3, 5); var divingBoardJoint = new RevoluteJoint(divingBoardBase, divingBoard, divingBoard.Position + new Vector3(0, 0, -1.5f), Vector3.Right); divingBoardJoint.Motor.IsActive = true; divingBoardJoint.Motor.Settings.Mode = MotorMode.Servomechanism; divingBoardJoint.Motor.Settings.Servo.Goal = 0; divingBoardJoint.Motor.Settings.Servo.SpringSettings.Stiffness = 5000; divingBoardJoint.Motor.Settings.Servo.SpringSettings.Damping = 0; Space.Add(divingBoardBase); Space.Add(divingBoard); Space.Add(divingBoardJoint); //Add a second diving board for comparison. Box divingBoard2 = new Box(divingBoardBase.Position + new Vector3(2, 0, 5f), 1, .3f, 6, 5); var divingBoardJoint2 = new RevoluteJoint(divingBoardBase, divingBoard2, divingBoard2.Position + new Vector3(0, 0, -3), Vector3.Right); divingBoardJoint2.Motor.IsActive = true; divingBoardJoint2.Motor.Settings.Mode = MotorMode.Servomechanism; divingBoardJoint2.Motor.Settings.Servo.Goal = 0; divingBoardJoint2.Motor.Settings.Servo.SpringSettings.Stiffness = 10000; divingBoardJoint2.Motor.Settings.Servo.SpringSettings.Damping = 0; Space.Add(divingBoard2); Space.Add(divingBoardJoint2); //Add a seesaw for people to jump on. Box seesawBase = new Box(new Vector3(-7, .45f, 52), 1, .9f, .3f); Box seesawPlank = new Box(seesawBase.Position + new Vector3(0, .65f, 0), 1.2f, .2f, 6, 3); RevoluteJoint seesawJoint = new RevoluteJoint(seesawBase, seesawPlank, seesawPlank.Position, Vector3.Right); Space.Add(seesawJoint); Space.Add(seesawBase); Space.Add(seesawPlank); Space.Add(new Box(seesawPlank.Position + new Vector3(0, 1.3f, 2), 1, 1, 1, 5)); //Add in some boxes to bump and jump on. int numColumns = 3; int numRows = 3; int numHigh = 3; float xSpacing = 1.01f; float ySpacing = 1.01f; float zSpacing = 1.01f; for (int i = 0; i < numRows; i++) for (int j = 0; j < numColumns; j++) for (int k = 0; k < numHigh; k++) { Space.Add(new Box(new Vector3( 5 + xSpacing * i - (numRows - 1) * xSpacing / 2f, 1.58f + k * (ySpacing), 45 + zSpacing * j - (numColumns - 1) * zSpacing / 2f), .5f, .5f, .5f, 5)); } //Add a log to roll! //Make it a compound so some boxes can be added to let the player know it's actually spinning. CompoundBody log = new CompoundBody(new List<CompoundShapeEntry>() { new CompoundShapeEntry(new CylinderShape(4, 1.8f), Quaternion.CreateFromAxisAngle(Vector3.Forward, MathHelper.PiOver2), 20), new CompoundShapeEntry(new BoxShape(.5f, .5f, 3.7f), new Vector3(1.75f, 0,0), 0), new CompoundShapeEntry(new BoxShape(.5f, 3.7f, .5f), new Vector3(1.75f, 0,0), 0), new CompoundShapeEntry(new BoxShape(.5f, .5f, 3.7f), new Vector3(-1.75f, 0,0), 0), new CompoundShapeEntry(new BoxShape(.5f, 3.7f, .5f), new Vector3(-1.75f, 0,0), 0) }, 50); log.Position = new Vector3(-14.5f, 10, 41); log.AngularDamping = 0; RevoluteJoint logJointA = new RevoluteJoint(divingBoardBase, log, log.Position + new Vector3(2.5f, 0, 0), Vector3.Right); RevoluteJoint logJointB = new RevoluteJoint(endPlatform, log, log.Position + new Vector3(-2.5f, 0, 0), Vector3.Right); Space.Add(logJointA); Space.Add(logJointB); Space.Add(log); //Put some planks to stand on that show various slopes. int numPads = 10; for (int i = 0; i < numPads; i++) { offset = new Vector3(0, 0, 4); Box a = new Box(new Vector3(i * 1.5f + 3.5f, 10, 24), 1.5f, 1, 4); Box b = new Box(new Vector3(i * 1.5f + 3.5f, 10, 24), 1.5f, 1, 4); float angle = -i * MathHelper.PiOver2 / numPads; b.Orientation = Quaternion.CreateFromAxisAngle(Vector3.Right, angle); b.Position += offset * .5f + Quaternion.Transform(offset * .5f, b.Orientation); Space.Add(a); Space.Add(b); } }
public override void Bind(Entity result, Main main, bool creating = false) { Factory.Get<DynamicMapFactory>().Bind(result, main); Transform transform = result.Get<Transform>(); DynamicMap map = result.Get<DynamicMap>(); PointLight light = result.Get<PointLight>(); Sound blastFireSound = result.Get<Sound>("BlastFireSound"); blastFireSound.Add(new Binding<Vector3>(blastFireSound.Position, transform.Position)); blastFireSound.Add(new Binding<Vector3>(blastFireSound.Velocity, map.LinearVelocity)); Sound blastChargeSound = result.Get<Sound>("BlastChargeSound"); blastChargeSound.Add(new Binding<Vector3>(blastChargeSound.Position, transform.Position)); blastChargeSound.Add(new Binding<Vector3>(blastChargeSound.Velocity, map.LinearVelocity)); map.Add(new CommandBinding(map.CompletelyEmptied, delegate() { if (!main.EditorEnabled) result.Delete.Execute(); })); EntityRotator rotator = null; EntityMover mover = null; if (!main.EditorEnabled) { rotator = new EntityRotator(map.PhysicsEntity); main.Space.Add(rotator); mover = new EntityMover(map.PhysicsEntity); mover.TargetPosition = transform.Position; main.Space.Add(mover); } Map.Coordinate blastSource = map.GetCoordinate(0, 0, 0); Map.Coordinate blastPosition = blastSource; Map.CellState criticalMaterial = WorldFactory.StatesByName["Critical"]; foreach (Map.Box box in map.Chunks.SelectMany(x => x.Boxes)) { if (box.Type == criticalMaterial) { blastSource = map.GetCoordinate(box.X, box.Y, box.Z); blastPosition = map.GetCoordinate(box.X, box.Y, box.Z - 3); break; } } Property<float> blastIntervalTime = result.GetProperty<float>("BlastInterval"); float blastInterval = 0.0f; Property<float> playerPositionMemoryTime = result.GetProperty<float>("PlayerPositionMemoryTime"); float timeSinceLastSpottedPlayer = playerPositionMemoryTime; Property<float> visibilityCheckInterval = result.GetProperty<float>("VisibilityCheckInterval"); float timeSinceLastVisibilityCheck = 0.0f; Property<float> blastChargeTime = result.GetProperty<float>("BlastChargeTime"); float blastCharge = 0.0f; Property<float> blastSpeed = result.GetProperty<float>("BlastSpeed"); Property<float> playerDetectionRadius = result.GetProperty<float>("PlayerDetectionRadius"); Updater update = new Updater(); update.Add(delegate(float dt) { if (map[blastSource].ID == 0) { update.Delete.Execute(); if (rotator != null) { main.Space.Remove(rotator); main.Space.Remove(mover); } light.Delete.Execute(); return; } Entity player = PlayerFactory.Instance; if (player != null) { Vector3 playerPosition = player.Get<Transform>().Position.Value; Vector3 rayStart = map.GetAbsolutePosition(blastPosition); Vector3 rayDirection = playerPosition - rayStart; rayDirection.Normalize(); timeSinceLastVisibilityCheck += dt; if (timeSinceLastVisibilityCheck > visibilityCheckInterval) { if ((playerPosition - transform.Position).Length() < playerDetectionRadius) timeSinceLastSpottedPlayer = 0.0f; else if (Vector3.Dot(rayDirection, map.GetAbsoluteVector(Vector3.Forward)) > 0) { RayCastResult hit; if (main.Space.RayCast(new Ray(rayStart, rayDirection), out hit)) { EntityCollidable collidable = hit.HitObject as EntityCollidable; if (collidable != null && collidable.Entity.Tag is Player) timeSinceLastSpottedPlayer = 0.0f; } } timeSinceLastVisibilityCheck = 0.0f; } timeSinceLastSpottedPlayer += dt; light.Attenuation.Value = 0.0f; if (timeSinceLastSpottedPlayer < playerPositionMemoryTime) { rotator.TargetOrientation = Quaternion.CreateFromRotationMatrix(Matrix.Invert(Matrix.CreateLookAt(rayStart, playerPosition, Vector3.Up))); if (blastInterval > blastIntervalTime) { if (blastCharge < blastChargeTime) { if (blastCharge == 0.0f) blastChargeSound.Play.Execute(); blastCharge += dt; light.Position.Value = rayStart; light.Attenuation.Value = (blastCharge / blastChargeTime) * 30.0f; } else { blastCharge = 0.0f; blastFireSound.Play.Execute(); blastInterval = 0.0f; Entity blast = Factory.CreateAndBind(main, "Blast"); PhysicsBlock physics = blast.Get<PhysicsBlock>(); Transform blastTransform = blast.Get<Transform>(); blastTransform.Position.Value = rayStart; physics.LinearVelocity.Value = (rayDirection * blastSpeed) + new Vector3(0.0f, 6.0f, 0.0f); main.Add(blast); } } else { blastInterval += dt; blastCharge = 0.0f; } } else blastCharge = 0.0f; } }); result.Add("Update", update); }