public override void Bind(Entity result, Main main, bool creating = false) { PointLight light = result.Get<PointLight>(); Transform transform = result.Get<Transform>(); Property<float> attachOffset = result.GetOrMakeProperty<float>("AttachmentOffset", true); light.Add(new TwoWayBinding<Vector3>(light.Position, transform.Position)); if (result.GetOrMakeProperty<bool>("Attach", true)) MapAttachable.MakeAttachable(result, main); this.SetMain(result, main); }
public static void Attach(Entity entity, Main main) { Transform transform = entity.Get<Transform>(); Property<float> attachOffset = entity.GetOrMakeProperty<float>("AttachmentOffset", true); Property<Entity.Handle> map = entity.GetOrMakeProperty<Entity.Handle>("AttachedMap"); Property<Map.Coordinate> coord = entity.GetOrMakeProperty<Map.Coordinate>("AttachedCoordinate"); if (main.EditorEnabled) return; entity.Add(new PostInitialization { delegate() { if (map.Value.Target == null) { Map closestMap = null; Map.Coordinate? closestCoord = null; int closestDistance = 3; float closestFloatDistance = 3.0f; Vector3 target = Vector3.Transform(new Vector3(0, 0, attachOffset), transform.Matrix); foreach (Map m in Map.Maps) { Map.Coordinate targetCoord = m.GetCoordinate(target); Map.Coordinate? c = m.FindClosestFilledCell(targetCoord, closestDistance); if (c.HasValue) { float distance = (m.GetRelativePosition(c.Value) - m.GetRelativePosition(targetCoord)).Length(); if (distance < closestFloatDistance) { closestFloatDistance = distance; closestDistance = (int)Math.Floor(distance); closestMap = m; closestCoord = c; } } } if (closestMap == null) entity.Delete.Execute(); else { map.Value = closestMap.Entity; coord.Value = closestCoord.Value; } } else { map.Reset(); coord.Reset(); } } }); }
public static void AttachEditorComponents(Entity result, Main main, Property<Vector3> color = null) { Model model = new Model(); model.Filename.Value = "Models\\cone"; if (color != null) model.Add(new Binding<Vector3>(model.Color, color)); model.Add(new Binding<bool>(model.Enabled, result.GetOrMakeProperty<bool>("EditorSelected"))); model.Add(new Binding<Vector3, float>(model.Scale, x => new Vector3(1.0f, 1.0f, x), result.GetOrMakeProperty<float>("AttachmentOffset", true))); model.Editable = false; model.Serialize = false; result.Add("EditorModel2", model); model.Add(new Binding<Matrix>(model.Transform, result.Get<Transform>().Matrix)); }
public override void Bind(Entity result, Main main, bool creating = false) { this.SetMain(result, main); result.CannotSuspendByDistance = true; Transform transform = result.Get<Transform>(); ModelAlpha model = new ModelAlpha(); model.Color.Value = new Vector3(1.2f, 1.0f, 0.8f); model.Editable = false; model.Serialize = false; model.Filename.Value = "Models\\electricity"; model.DrawOrder.Value = 11; result.Add("Model", model); result.GetOrMakeProperty<bool>("IsMapEdge", true, true); PhysicsBlock block = result.Get<PhysicsBlock>(); block.Box.BecomeKinematic(); this.boundaries.Add(result); result.Add(new CommandBinding(result.Delete, delegate() { this.boundaries.Remove(result); })); block.Add(new TwoWayBinding<Matrix>(transform.Matrix, block.Transform)); model.Add(new Binding<Matrix>(model.Transform, transform.Matrix)); model.Add(new Binding<Vector3>(model.Scale, x => new Vector3(x.X * 0.5f, x.Y * 0.5f, 1.0f), block.Size)); Property<Vector2> scaleParameter = model.GetVector2Parameter("Scale"); model.Add(new Binding<Vector2, Vector3>(scaleParameter, x => new Vector2(x.Y, x.X), model.Scale)); model.Add(new CommandBinding(main.ReloadedContent, delegate() { scaleParameter.Reset(); })); }
public static void AttachEditorComponents(Entity result, ListProperty<Entity.Handle> target) { Transform transform = result.Get<Transform>(); Property<bool> selected = result.GetOrMakeProperty<bool>("EditorSelected"); Command<Entity> toggleEntityConnected = new Command<Entity> { Action = delegate(Entity entity) { if (target.Contains(entity)) target.Remove(entity); else if (entity != result) target.Add(entity); } }; result.Add("ToggleEntityConnected", toggleEntityConnected); LineDrawer connectionLines = new LineDrawer { Serialize = false }; connectionLines.Add(new Binding<bool>(connectionLines.Enabled, selected)); Color connectionLineColor = new Color(1.0f, 1.0f, 1.0f, 0.5f); ListBinding<LineDrawer.Line, Entity.Handle> connectionBinding = new ListBinding<LineDrawer.Line, Entity.Handle>(connectionLines.Lines, target, delegate(Entity.Handle entity) { return new LineDrawer.Line { A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(transform.Position, connectionLineColor), B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(entity.Target.Get<Transform>().Position, connectionLineColor) }; }, x => x.Target != null && x.Target.Active); result.Add(new NotifyBinding(delegate() { connectionBinding.OnChanged(null); }, selected)); result.Add(new NotifyBinding(delegate() { connectionBinding.OnChanged(null); }, () => selected, transform.Position)); connectionLines.Add(connectionBinding); result.Add(connectionLines); }
public override void Bind(Entity result, Main main, bool creating = false) { if (result.GetOrMakeProperty<bool>("Attach", true)) MapAttachable.MakeAttachable(result, main); this.SetMain(result, main); if (main.EditorEnabled) { result.Add("Spawn Here", new Command { Action = delegate() { ((GameMain)main).StartSpawnPoint.Value = result.ID; Editor editor = main.Get("Editor").First().Get<Editor>(); if (editor.NeedsSave) editor.Save.Execute(); main.EditorEnabled.Value = false; IO.MapLoader.Load(main, null, main.MapFile); }, ShowInEditor = true, }); } Transform transform = result.Get<Transform>(); PlayerSpawn spawn = result.Get<PlayerSpawn>(); spawn.Add(new TwoWayBinding<Vector3>(transform.Position, spawn.Position)); spawn.Add(new Binding<float, Vector3>(spawn.Rotation, x => ((float)Math.PI * -0.5f) - (float)Math.Atan2(x.Z, x.X), transform.Forward)); PlayerTrigger trigger = result.Get<PlayerTrigger>(); trigger.Enabled.Editable = true; trigger.Add(new TwoWayBinding<Vector3>(transform.Position, trigger.Position)); trigger.Add(new CommandBinding<Entity>(trigger.PlayerEntered, delegate(Entity player) { spawn.Activate.Execute(); })); }
public override void Bind(Entity result, Main main, bool creating = false) { result.CannotSuspend = true; Script script = result.Get<Script>(); Property<bool> executeOnLoad = result.GetProperty<bool>("ExecuteOnLoad"); if (executeOnLoad && !main.EditorEnabled) { result.Add("Executor", new PostInitialization { delegate() { if (executeOnLoad) script.Execute.Execute(); } }); } Property<bool> deleteOnExecute = result.GetOrMakeProperty<bool>("DeleteOnExecute", true, false); if (deleteOnExecute) result.Add(new CommandBinding(script.Execute, result.Delete)); this.SetMain(result, main); }
public override void Bind(Entity result, Main main, bool creating = false) { Transform transform = result.GetOrCreate<Transform>("Transform"); PhysicsBlock physics = result.GetOrCreate<PhysicsBlock>(); physics.Size.Value = Vector3.One; physics.Editable = false; ModelInstance model = result.GetOrCreate<ModelInstance>(); model.Editable = false; physics.Add(new TwoWayBinding<Matrix>(transform.Matrix, physics.Transform)); Property<string> soundCue = result.GetOrMakeProperty<string>("CollisionSoundCue", false); soundCue.Serialize = false; model.Add(new Binding<Matrix>(model.Transform, transform.Matrix)); const float volumeMultiplier = 0.1f; physics.Add(new CommandBinding<Collidable, ContactCollection>(physics.Collided, delegate(Collidable collidable, ContactCollection contacts) { float volume = contacts[contacts.Count - 1].NormalImpulse * volumeMultiplier; if (volume > 0.1f && soundCue.Value != null) { Sound sound = Sound.PlayCue(main, soundCue, transform.Position, volume, 0.05f); if (sound != null) sound.GetProperty("Pitch").Value = 1.0f; } })); this.SetMain(result, main); Property<bool> valid = result.GetOrMakeProperty<bool>("Valid", false); valid.Serialize = false; Property<string> type = result.GetOrMakeProperty<string>("Type", true); type.Set = delegate(string value) { Map.CellState state; if (WorldFactory.StatesByName.TryGetValue(value, out state)) { state.ApplyToBlock(result); valid.Value = true; } type.InternalValue = value; }; }
public override void AttachEditorComponents(Entity result, Main main) { base.AttachEditorComponents(result, main); Model model = result.Get<Model>("Model"); Model editorModel = result.Get<Model>("EditorModel"); Property<bool> editorSelected = result.GetOrMakeProperty<bool>("EditorSelected", false); editorSelected.Serialize = false; editorModel.Add(new Binding<bool>(editorModel.Enabled, () => !editorSelected || !model.IsValid, editorSelected, model.IsValid)); }
public override void Bind(Entity result, Main main, bool creating = false) { base.Bind(result, main, creating); result.CannotSuspendByDistance = true; ModelAlpha clouds = result.Get<ModelAlpha>("Clouds"); Property<float> height = result.GetOrMakeProperty<float>("Height", true, 1.0f); result.Add(new Binding<float>(clouds.GetFloatParameter("Height"), height)); Property<Vector2> velocity = result.GetOrMakeProperty<Vector2>("Velocity", true, Vector2.One); result.Add(new Binding<Vector2>(clouds.GetVector2Parameter("Velocity"), x => x * (1.0f / 60.0f), velocity)); result.Add(new CommandBinding(main.ReloadedContent, delegate() { height.Reset(); velocity.Reset(); })); }
public override void Bind(Entity result, Main main, bool creating = false) { Transform transform = result.Get<Transform>(); SpotLight spotLight = result.Get<SpotLight>(); if (result.GetOrMakeProperty<bool>("Attach", true)) MapAttachable.MakeAttachable(result, main); this.SetMain(result, main); spotLight.Add(new TwoWayBinding<Vector3>(spotLight.Position, transform.Position)); spotLight.Add(new TwoWayBinding<Quaternion>(spotLight.Orientation, transform.Quaternion)); }
public static void AttachEditorComponents(Entity result, Property<Entity.Handle> target) { Transform transform = result.Get<Transform>(); Property<bool> selected = result.GetOrMakeProperty<bool>("EditorSelected"); selected.Serialize = false; Command<Entity> toggleEntityConnected = new Command<Entity> { Action = delegate(Entity entity) { if (target.Value.Target == entity) target.Value = null; else if (entity != result) target.Value = entity; } }; result.Add("ToggleEntityConnected", toggleEntityConnected); LineDrawer connectionLines = new LineDrawer { Serialize = false }; connectionLines.Add(new Binding<bool>(connectionLines.Enabled, selected)); Color connectionLineColor = new Color(1.0f, 1.0f, 1.0f, 0.5f); connectionLines.Add(new NotifyBinding(delegate() { connectionLines.Lines.Clear(); Entity targetEntity = target.Value.Target; if (targetEntity != null) { connectionLines.Lines.Add ( new LineDrawer.Line { A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(transform.Position, connectionLineColor), B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(targetEntity.Get<Transform>().Position, connectionLineColor) } ); } }, transform.Position, target, selected)); result.Add(connectionLines); }
public override void Bind(Entity result, Main main, bool creating = false) { this.InternalBind(result, main, creating, null, true); if (result.GetOrMakeProperty<bool>("Attached", true)) MapAttachable.MakeAttachable(result, main); Property<Entity.Handle> target = result.GetOrMakeProperty<Entity.Handle>("Target"); Map map = result.Get<Map>(); Property<float> intervalMultiplier = result.GetOrMakeProperty<float>("IntervalMultiplier", true, 1.0f); ListProperty<CoordinateEntry> coords = result.GetOrMakeListProperty<CoordinateEntry>("Coordinates"); Property<int> index = result.GetOrMakeProperty<int>("FillIndex"); Action populateCoords = delegate() { if (coords.Count == 0) { Entity targetEntity = target.Value.Target; if (targetEntity != null && targetEntity.Active) { Map m = targetEntity.Get<Map>(); foreach (CoordinateEntry e in map.Chunks.SelectMany(c => c.Boxes.SelectMany(x => x.GetCoords())).Select(delegate(Map.Coordinate y) { Map.Coordinate z = m.GetCoordinate(map.GetAbsolutePosition(y)); z.Data = y.Data; return new CoordinateEntry { Coord = z, }; })) coords.Add(e); } } }; if (main.EditorEnabled) coords.Clear(); else result.Add(new PostInitialization { populateCoords }); Property<float> blockLifetime = result.GetOrMakeProperty<float>("BlockLifetime", true, 0.25f); float intervalTimer = 0.0f; Updater update = new Updater { delegate(float dt) { intervalTimer += dt; Entity targetEntity = target.Value.Target; if (targetEntity != null && targetEntity.Active && index < coords.Count) { float interval = 0.03f * intervalMultiplier; while (intervalTimer > interval && index < coords.Count) { EffectBlockFactory factory = Factory.Get<EffectBlockFactory>(); Map m = targetEntity.Get<Map>(); CoordinateEntry entry = coords[index]; Entity block = factory.CreateAndBind(main); entry.Coord.Data.ApplyToEffectBlock(block.Get<ModelInstance>()); block.GetProperty<bool>("CheckAdjacent").Value = false; block.GetProperty<Vector3>("Offset").Value = m.GetRelativePosition(entry.Coord); block.GetProperty<bool>("Scale").Value = true; block.GetProperty<Vector3>("StartPosition").Value = entry.Position + new Vector3(8.0f, 20.0f, 8.0f) * blockLifetime.Value; block.GetProperty<Matrix>("StartOrientation").Value = Matrix.CreateRotationX(0.15f * index) * Matrix.CreateRotationY(0.15f * index); block.GetProperty<float>("TotalLifetime").Value = blockLifetime; factory.Setup(block, targetEntity, entry.Coord, entry.Coord.Data.ID); main.Add(block); index.Value++; intervalTimer -= interval; } } else result.Delete.Execute(); } }; update.Enabled.Value = index > 0; result.Add("Update", update); Action fill = delegate() { if (index > 0 || update.Enabled) return; // We're already filling Entity targetEntity = target.Value.Target; if (targetEntity != null && targetEntity.Active) { populateCoords(); Map m = targetEntity.Get<Map>(); Vector3 focusPoint = main.Camera.Position; foreach (CoordinateEntry entry in coords) { entry.Position = m.GetAbsolutePosition(entry.Coord); entry.Distance = (focusPoint - entry.Position).LengthSquared(); } List<CoordinateEntry> coordList = coords.ToList(); coords.Clear(); coordList.Sort(new LambdaComparer<CoordinateEntry>((x, y) => x.Distance.CompareTo(y.Distance))); foreach (CoordinateEntry e in coordList) coords.Add(e); update.Enabled.Value = true; } }; result.Add("Fill", new Command { Action = fill }); result.Add("Trigger", new Command<Entity> { Action = delegate(Entity p) { fill(); } }); }
public override void AttachEditorComponents(Entity result, Main main) { base.AttachEditorComponents(result, main); MapAttachable.AttachEditorComponents(result, main, result.Get<Model>().Color); EntityConnectable.AttachEditorComponents(result, result.GetOrMakeProperty<Entity.Handle>("Target")); }
public override void Bind(Entity result, Main main, bool creating = false) { result.CannotSuspend = true; result.Add(new TwoWayBinding<string>(result.GetProperty<string>("LightRampTexture"), main.Renderer.LightRampTexture)); result.Add(new TwoWayBinding<string>(result.GetOrMakeProperty<string>("EnvironmentMap", true, "Maps\\env0"), main.Renderer.EnvironmentMap)); result.Add(new TwoWayBinding<Vector3>(result.GetOrMakeProperty<Vector3>("EnvironmentColor", true, Vector3.One), main.Renderer.EnvironmentColor)); result.Add(new TwoWayBinding<Color>(result.GetProperty<Color>("BackgroundColor"), main.Renderer.BackgroundColor)); result.Add(new TwoWayBinding<float>(result.GetProperty<float>("FarPlaneDistance"), main.Camera.FarPlaneDistance)); WorldFactory.AddState(result.GetListProperty<Map.CellState>("AdditionalMaterials").ToArray()); result.Add(new CommandBinding(result.Delete, delegate() { WorldFactory.RemoveState(result.GetListProperty<Map.CellState>("AdditionalMaterials").ToArray()); })); // Zone management Zone currentZone = null; result.Add(new CommandBinding<Entity>(main.EntityAdded, delegate(Entity e) { if (!e.CannotSuspend) processEntity(e, currentZone, getActiveBoundingBoxes(main.Camera, currentZone), main.Camera.Position, main.Camera.FarPlaneDistance); })); IEnumerable<NonAxisAlignedBoundingBox> boxes = getActiveBoundingBoxes(main.Camera, currentZone); Vector3 cameraPosition = main.Camera.Position; float suspendDistance = main.Camera.FarPlaneDistance; foreach (Entity e in main.Entities) { if (!e.CannotSuspend) processEntity(e, currentZone, boxes, cameraPosition, suspendDistance); } result.Add("ProcessMap", new Command<Map> { Action = delegate(Map map) { processMap(map, boxes); } }); Property<float> reverbAmount = result.GetProperty<float>("ReverbAmount"); Property<float> reverbSize = result.GetProperty<float>("ReverbSize"); Sound.ReverbSettings(main, reverbAmount, reverbSize); Vector3 lastUpdatedCameraPosition = new Vector3(float.MinValue); bool lastFrameUpdated = false; Action<Zone> updateZones = delegate(Zone newZone) { currentZone = newZone; if (newZone != null) Sound.ReverbSettings(main, newZone.ReverbAmount, newZone.ReverbSize); else Sound.ReverbSettings(main, reverbAmount, reverbSize); boxes = getActiveBoundingBoxes(main.Camera, newZone); cameraPosition = main.Camera.Position; suspendDistance = main.Camera.FarPlaneDistance; foreach (Entity e in main.Entities) { if (!e.CannotSuspend) processEntity(e, newZone, boxes, cameraPosition, suspendDistance); } lastUpdatedCameraPosition = main.Camera.Position; }; result.Add("UpdateZones", new Command { Action = delegate() { updateZones(Zone.Get(main.Camera.Position)); }, }); Updater update = new Updater { delegate(float dt) { // Update every other frame if (lastFrameUpdated) { lastFrameUpdated = false; return; } lastFrameUpdated = true; Zone newZone = Zone.Get(main.Camera.Position); if (newZone != currentZone || (newZone == null && (main.Camera.Position - lastUpdatedCameraPosition).Length() > 10.0f)) updateZones(newZone); } }; update.EnabledInEditMode.Value = true; result.Add(update); this.SetMain(result, main); WorldFactory.instance = result; }
public override void Bind(Entity result, Main main, bool creating = false) { Property<float> maxForce = result.GetOrMakeProperty<float>("MaxForce", true, 150.0f); Property<float> damping = result.GetOrMakeProperty<float>("Damping", true, 1.5f); Property<float> stiffness = result.GetOrMakeProperty<float>("Stiffness", true, 15.0f); NoRotationJoint joint = null; EntityMover mover = null; Action setMaxForce = delegate() { if (mover != null) { if (maxForce > 0.001f) mover.LinearMotor.Settings.MaximumForce = maxForce * result.Get<DynamicMap>().PhysicsEntity.Mass; else mover.LinearMotor.Settings.MaximumForce = float.MaxValue; } }; result.Add(new NotifyBinding(setMaxForce, maxForce)); result.Add(new CommandBinding(result.Get<DynamicMap>().PhysicsUpdated, setMaxForce)); Action setDamping = delegate() { if (mover != null && damping != 0) mover.LinearMotor.Settings.Servo.SpringSettings.DampingConstant = damping; }; result.Add(new NotifyBinding(setDamping, damping)); Action setStiffness = delegate() { if (mover != null && stiffness != 0) mover.LinearMotor.Settings.Servo.SpringSettings.StiffnessConstant = stiffness * result.Get<DynamicMap>().PhysicsEntity.Mass; }; result.Add(new NotifyBinding(setStiffness, stiffness)); result.Add(new CommandBinding(result.Get<DynamicMap>().PhysicsUpdated, setStiffness)); Func<BEPUphysics.Entities.Entity, BEPUphysics.Entities.Entity, Vector3, Vector3, Vector3, ISpaceObject> createJoint = delegate(BEPUphysics.Entities.Entity entity1, BEPUphysics.Entities.Entity entity2, Vector3 pos, Vector3 direction, Vector3 anchor) { joint = new NoRotationJoint(entity1, entity2); if (mover != null && mover.Space != null) main.Space.Remove(mover); mover = new EntityMover(entity1); main.Space.Add(mover); setMaxForce(); setDamping(); setStiffness(); return joint; }; JointFactory.Bind(result, main, createJoint, true, creating); result.Add(new CommandBinding(result.Get<DynamicMap>().OnSuspended, delegate() { if (mover != null && mover.Space != null) main.Space.Remove(mover); })); result.Add(new CommandBinding(result.Get<DynamicMap>().OnResumed, delegate() { if (mover != null && mover.Space == null) main.Space.Add(mover); })); result.Add(new CommandBinding(result.Delete, delegate() { if (mover != null && mover.Space != null) { main.Space.Remove(mover); mover = null; } })); Property<Entity.Handle> parent = result.GetOrMakeProperty<Entity.Handle>("Parent"); Property<Map.Coordinate> coord = result.GetOrMakeProperty<Map.Coordinate>("Coord"); Updater updater = null; updater = new Updater { delegate(float dt) { Entity parentEntity = parent.Value.Target; if (parentEntity != null && parentEntity.Active) mover.TargetPosition = parentEntity.Get<Map>().GetAbsolutePosition(coord) + new Vector3(0, -0.01f, 0); else { updater.Delete.Execute(); parent.Value = null; if (mover != null && mover.Space != null) { main.Space.Remove(mover); mover = null; } } } }; result.Add(updater); }
public override void Bind(Entity result, Main main, bool creating = false) { Property<Direction> dir = result.GetOrMakeProperty<Direction>("Direction", true); Property<float> minimum = result.GetOrMakeProperty<float>("Minimum", true); Property<float> maximum = result.GetOrMakeProperty<float>("Maximum", true); Property<bool> locked = result.GetOrMakeProperty<bool>("Locked", true); Property<bool> servo = result.GetOrMakeProperty<bool>("Servo", true, true); Property<float> speed = result.GetOrMakeProperty<float>("Speed", true, 5); Property<float> goal = result.GetOrMakeProperty<float>("Goal", true); RevoluteJoint joint = null; Action setLimits = delegate() { if (joint != null) { float min = minimum, max = maximum; if (max > min) { joint.Limit.IsActive = true; joint.Limit.MinimumAngle = minimum; joint.Limit.MaximumAngle = maximum; } else joint.Limit.IsActive = false; } }; result.Add(new NotifyBinding(setLimits, minimum, maximum)); Action setSpeed = delegate() { if (joint != null) { joint.Motor.Settings.Servo.BaseCorrectiveSpeed = joint.Motor.Settings.Servo.MaxCorrectiveVelocity = speed; joint.Motor.Settings.VelocityMotor.GoalVelocity = speed; } }; result.Add(new NotifyBinding(setSpeed, speed)); Action setGoal = delegate() { if (joint != null) joint.Motor.Settings.Servo.Goal = goal; }; result.Add(new NotifyBinding(setGoal, goal)); Action setLocked = delegate() { if (joint != null) joint.Motor.IsActive = locked; }; result.Add(new NotifyBinding(setLocked, locked)); DynamicMap map = result.Get<DynamicMap>(); Action setServo = delegate() { if (joint != null) joint.Motor.Settings.Mode = servo ? MotorMode.Servomechanism : MotorMode.VelocityMotor; }; result.Add(new NotifyBinding(setServo, servo)); Func<BEPUphysics.Entities.Entity, BEPUphysics.Entities.Entity, Vector3, Vector3, Vector3, ISpaceObject> createJoint = delegate(BEPUphysics.Entities.Entity entity1, BEPUphysics.Entities.Entity entity2, Vector3 pos, Vector3 direction, Vector3 anchor) { joint = new RevoluteJoint(entity1, entity2, pos, direction); float multiplier = Math.Max(1.0f, map.PhysicsEntity.Mass); joint.AngularJoint.SpringSettings.StiffnessConstant *= multiplier; joint.Limit.SpringSettings.StiffnessConstant *= multiplier; joint.Motor.Settings.Mode = MotorMode.Servomechanism; setLimits(); setLocked(); setSpeed(); setServo(); setGoal(); return joint; }; JointFactory.Bind(result, main, createJoint, true, creating); result.Add("On", new Command { Action = delegate() { if (joint != null && locked) servo.Value = false; }, }); result.Add("Off", new Command { Action = delegate() { if (joint != null && locked) { BEPUphysics.Constraints.JointBasis2D basis = joint.Motor.Basis; basis.RotationMatrix = joint.Motor.ConnectionA.OrientationMatrix; Vector3 localTestAxis = joint.Motor.LocalTestAxis; Vector3 worldTestAxis; BEPUutilities.Matrix3x3 orientationMatrix = joint.Motor.ConnectionB.OrientationMatrix; BEPUutilities.Matrix3x3.Transform(ref localTestAxis, ref orientationMatrix, out worldTestAxis); float y, x; Vector3 yAxis = Vector3.Cross(basis.PrimaryAxis, basis.XAxis); Vector3.Dot(ref worldTestAxis, ref yAxis, out y); x = Vector3.Dot(worldTestAxis, basis.XAxis); goal.Value = (float)Math.Atan2(y, x); servo.Value = true; } }, }); result.Add("Forward", new Command { Action = delegate() { if (joint != null && locked) joint.Motor.Settings.Servo.Goal = maximum; }, }); result.Add("Backward", new Command { Action = delegate() { if (joint != null && locked) joint.Motor.Settings.Servo.Goal = minimum; }, }); Command hitMax = new Command(); result.Add("HitMax", hitMax); Command hitMin = new Command(); result.Add("HitMin", hitMin); bool lastLimitExceeded = false; result.Add(new Updater { delegate(float dt) { if (joint != null) { bool limitExceeded = joint.Limit.IsLimitExceeded; if (limitExceeded && !lastLimitExceeded) { if (joint.Limit.Error.X > 0) hitMin.Execute(); else hitMax.Execute(); } lastLimitExceeded = limitExceeded; } } }); }
public static void MakeAttachable(Entity entity, Main main) { Transform transform = entity.Get<Transform>(); Property<float> attachOffset = entity.GetOrMakeProperty<float>("AttachmentOffset", true); Property<Entity.Handle> map = entity.GetOrMakeProperty<Entity.Handle>("AttachedMap"); Property<Map.Coordinate> coord = entity.GetOrMakeProperty<Map.Coordinate>("AttachedCoordinate"); if (main.EditorEnabled) return; Binding<Matrix> attachmentBinding = null; CommandBinding deleteBinding = null; CommandBinding<IEnumerable<Map.Coordinate>, Map> cellEmptiedBinding = null; entity.Add(new NotifyBinding(delegate() { if (attachmentBinding != null) { entity.Remove(attachmentBinding); entity.Remove(deleteBinding); entity.Remove(cellEmptiedBinding); } Map m = map.Value.Target.Get<Map>(); coord.Value = m.GetCoordinate(Vector3.Transform(new Vector3(0, 0, attachOffset), transform.Matrix)); Matrix offset = transform.Matrix * Matrix.Invert(Matrix.CreateTranslation(m.Offset) * m.Transform); attachmentBinding = new Binding<Matrix>(transform.Matrix, () => offset * Matrix.CreateTranslation(m.Offset) * m.Transform, m.Transform, m.Offset); entity.Add(attachmentBinding); deleteBinding = new CommandBinding(m.Delete, entity.Delete); entity.Add(deleteBinding); cellEmptiedBinding = new CommandBinding<IEnumerable<Map.Coordinate>, Map>(m.CellsEmptied, delegate(IEnumerable<Map.Coordinate> coords, Map newMap) { foreach (Map.Coordinate c in coords) { if (c.Equivalent(coord)) { if (newMap == null) entity.Delete.Execute(); else map.Value = newMap.Entity; break; } } }); entity.Add(cellEmptiedBinding); }, map)); entity.Add(new PostInitialization { delegate() { if (map.Value.Target == null) { Map closestMap = null; int closestDistance = 3; float closestFloatDistance = 3.0f; Vector3 target = Vector3.Transform(new Vector3(0, 0, attachOffset), transform.Matrix); foreach (Map m in Map.Maps) { Map.Coordinate targetCoord = m.GetCoordinate(target); Map.Coordinate? c = m.FindClosestFilledCell(targetCoord, closestDistance); if (c.HasValue) { float distance = (m.GetRelativePosition(c.Value) - m.GetRelativePosition(targetCoord)).Length(); if (distance < closestFloatDistance) { closestFloatDistance = distance; closestDistance = (int)Math.Floor(distance); closestMap = m; } } } if (closestMap == null) entity.Delete.Execute(); else map.Value = closestMap.Entity; } else map.Reset(); } }); }
public static void Attach(Main main, Entity result, AnimatedModel model, FPSInput input, Phone phone, Property<bool> enableWalking, Property<bool> enableMoves) { Property<bool> phoneActive = result.GetOrMakeProperty<bool>("PhoneActive"); Property<bool> noteActive = result.GetOrMakeProperty<bool>("NoteActive"); UIRenderer phoneUi = result.GetOrCreate<UIRenderer>("PhoneUI"); Property<Entity.Handle> signalTower = result.GetOrMakeProperty<Entity.Handle>("SignalTower"); const float phoneWidth = 200.0f; phoneUi.RenderTargetBackground.Value = Microsoft.Xna.Framework.Color.White; phoneUi.RenderTargetSize.Value = new Point((int)phoneWidth, (int)(phoneWidth * 2.0f)); phoneUi.Serialize = false; phoneUi.Enabled.Value = false; Model phoneModel = result.GetOrCreate<Model>("PhoneModel"); phoneModel.Filename.Value = "Models\\phone"; phoneModel.Color.Value = new Vector3(0.13f, 0.13f, 0.13f); phoneModel.Serialize = false; phoneModel.Enabled.Value = false; Property<Matrix> phoneBone = model.GetBoneTransform("Phone"); phoneModel.Add(new Binding<Matrix>(phoneModel.Transform, () => phoneBone.Value * model.Transform, phoneBone, model.Transform)); Model screen = result.GetOrCreate<Model>("Screen"); screen.Filename.Value = "Models\\plane"; screen.Add(new Binding<Microsoft.Xna.Framework.Graphics.RenderTarget2D>(screen.GetRenderTarget2DParameter("Diffuse" + Model.SamplerPostfix), phoneUi.RenderTarget)); screen.Add(new Binding<Matrix>(screen.Transform, x => Matrix.CreateTranslation(0.015f, 0.0f, 0.0f) * x, phoneModel.Transform)); screen.Serialize = false; screen.Enabled.Value = false; PointLight phoneLight = result.GetOrCreate<PointLight>("PhoneLight"); phoneLight.Serialize = false; phoneLight.Enabled.Value = false; phoneLight.Attenuation.Value = 0.5f; phoneLight.Add(new Binding<Vector3, Matrix>(phoneLight.Position, x => x.Translation, screen.Transform)); const float screenScale = 0.0007f; screen.Scale.Value = new Vector3(1.0f, (float)phoneUi.RenderTargetSize.Value.Y * screenScale, (float)phoneUi.RenderTargetSize.Value.X * screenScale); // Transform screen space mouse position into 3D, then back into the 2D space of the phone UI Property<Matrix> screenTransform = new Property<Matrix>(); screen.Add(new Binding<Matrix>(screenTransform, () => Matrix.CreateScale(screen.Scale) * screen.Transform, screen.Scale, screen.Transform)); phoneUi.Setup3D(screenTransform); // Phone UI const float padding = 8.0f; const float messageWidth = phoneWidth - padding * 2.0f; Func<Color, string, float, Container> makeButton = delegate(Color color, string text, float width) { Container bg = new Container(); bg.Tint.Value = color; bg.PaddingBottom.Value = bg.PaddingLeft.Value = bg.PaddingRight.Value = bg.PaddingTop.Value = padding * 0.5f; Color highlightColor = new Color(color.ToVector4() + new Vector4(0.2f, 0.2f, 0.2f, 0.0f)); bg.Add(new Binding<Color, bool>(bg.Tint, x => x ? highlightColor : color, bg.Highlighted)); TextElement msg = new TextElement(); msg.Name.Value = "Text"; msg.FontFile.Value = "Font"; msg.Text.Value = text; msg.WrapWidth.Value = width; bg.Children.Add(msg); return bg; }; Func<UIComponent, bool, Container> makeAlign = delegate(UIComponent component, bool right) { Container container = new Container(); container.Opacity.Value = 0.0f; container.PaddingBottom.Value = container.PaddingLeft.Value = container.PaddingRight.Value = container.PaddingTop.Value = 0.0f; container.ResizeHorizontal.Value = false; container.Size.Value = new Vector2(messageWidth, 0.0f); component.AnchorPoint.Value = new Vector2(right ? 1.0f : 0.0f, 0.0f); component.Position.Value = new Vector2(right ? messageWidth : 0.0f, 0.0f); container.Children.Add(component); return container; }; Color incomingColor = new Color(0.0f, 0.0f, 0.0f, 1.0f); Color outgoingColor = new Color(0.0f, 0.175f, 0.35f, 1.0f); Container topBarContainer = new Container(); topBarContainer.ResizeHorizontal.Value = false; topBarContainer.Size.Value = new Vector2(phoneUi.RenderTargetSize.Value.X, 0.0f); topBarContainer.Tint.Value = new Color(0.15f, 0.15f, 0.15f, 1.0f); phoneUi.Root.Children.Add(topBarContainer); ListContainer phoneTopBar = new ListContainer(); phoneTopBar.Orientation.Value = ListContainer.ListOrientation.Horizontal; phoneTopBar.Spacing.Value = padding; topBarContainer.Children.Add(phoneTopBar); Sprite signalIcon = new Sprite(); signalIcon.Image.Value = "Images\\signal"; phoneTopBar.Children.Add(signalIcon); TextElement noService = new TextElement(); noService.FontFile.Value = "Font"; noService.Text.Value = "\\no service"; phoneTopBar.Children.Add(noService); signalIcon.Add(new Binding<bool, Entity.Handle>(signalIcon.Visible, x => x.Target != null && x.Target.Active, signalTower)); noService.Add(new Binding<bool, Entity.Handle>(noService.Visible, x => x.Target == null || !x.Target.Active, signalTower)); ListContainer phoneLayout = new ListContainer(); phoneLayout.Spacing.Value = padding; phoneLayout.Orientation.Value = ListContainer.ListOrientation.Vertical; phoneLayout.Add(new Binding<Vector2>(phoneLayout.Position, x => new Vector2(padding, x.Y), topBarContainer.Size)); phoneLayout.Add(new Binding<Vector2>(phoneLayout.Size, () => new Vector2(phoneUi.RenderTargetSize.Value.X - padding * 2.0f, phoneUi.RenderTargetSize.Value.Y - padding - topBarContainer.Size.Value.Y), phoneUi.RenderTargetSize, topBarContainer.Size)); phoneUi.Root.Children.Add(phoneLayout); Container composeButton = makeButton(new Color(0.5f, 0.0f, 0.0f, 1.0f), "\\compose", messageWidth - padding * 2.0f); TextElement composeText = (TextElement)composeButton.GetChildByName("Text"); composeText.Add(new Binding<string, bool>(composeText.Text, x => x ? "\\compose gamepad" : "\\compose", main.GamePadConnected)); UIComponent composeAlign = makeAlign(composeButton, true); Scroller phoneScroll = new Scroller(); phoneScroll.ResizeVertical.Value = false; phoneScroll.Add(new Binding<Vector2>(phoneScroll.Size, () => new Vector2(phoneLayout.Size.Value.X, phoneLayout.Size.Value.Y - phoneLayout.Spacing.Value - composeAlign.ScaledSize.Value.Y), phoneLayout.Size, phoneLayout.Spacing, composeAlign.ScaledSize)); phoneLayout.Children.Add(phoneScroll); phoneLayout.Children.Add(composeAlign); ListContainer msgList = new ListContainer(); msgList.Spacing.Value = padding * 0.5f; msgList.Orientation.Value = ListContainer.ListOrientation.Vertical; msgList.ResizePerpendicular.Value = false; msgList.Size.Value = new Vector2(messageWidth, 0.0f); phoneScroll.Children.Add(msgList); Container answerContainer = new Container(); answerContainer.PaddingBottom.Value = answerContainer.PaddingLeft.Value = answerContainer.PaddingRight.Value = answerContainer.PaddingTop.Value = padding; answerContainer.Tint.Value = incomingColor; answerContainer.AnchorPoint.Value = new Vector2(1.0f, 1.0f); answerContainer.Add(new Binding<Vector2>(answerContainer.Position, () => composeAlign.Position.Value + new Vector2(composeAlign.ScaledSize.Value.X + padding, padding * 3.0f), composeAlign.Position, composeAlign.ScaledSize)); phoneUi.Root.Children.Add(answerContainer); answerContainer.Visible.Value = false; ListContainer answerList = new ListContainer(); answerList.Orientation.Value = ListContainer.ListOrientation.Vertical; answerList.Alignment.Value = ListContainer.ListAlignment.Max; answerContainer.Children.Add(answerList); int selectedAnswer = 0; composeButton.Add(new CommandBinding<Point>(composeButton.MouseLeftUp, delegate(Point p) { answerContainer.Visible.Value = !answerContainer.Visible; if (answerContainer.Visible && main.GamePadConnected) { selectedAnswer = 0; foreach (UIComponent answer in answerList.Children) answer.Highlighted.Value = false; answerList.Children[0].Highlighted.Value = true; } })); Action scrollToBottom = delegate() { // HACK main.AddComponent(new Animation ( new Animation.Delay(0.01f), new Animation.Execute(delegate() { phoneScroll.ScrollToBottom(); }) )); }; // Note UIRenderer noteUi = result.GetOrCreate<UIRenderer>("NoteUI"); const float noteWidth = 400.0f; const float noteScale = 0.0009f; noteUi.RenderTargetBackground.Value = new Microsoft.Xna.Framework.Color(1.0f, 0.95f, 0.9f); noteUi.RenderTargetSize.Value = new Point((int)noteWidth, (int)(noteWidth * 1.29f)); // 8.5x11 aspect ratio noteUi.Serialize = false; noteUi.Enabled.Value = false; Model noteModel = result.GetOrCreate<Model>("Note"); noteModel.Filename.Value = "Models\\plane"; noteModel.EffectFile.Value = "Effects\\Default"; noteModel.Add(new Binding<Microsoft.Xna.Framework.Graphics.RenderTarget2D>(noteModel.GetRenderTarget2DParameter("Diffuse" + Model.SamplerPostfix), noteUi.RenderTarget)); noteModel.Add(new Binding<Matrix>(noteModel.Transform, x => Matrix.CreateTranslation(-0.005f, 0.05f, 0.08f) * x, phoneModel.Transform)); noteModel.Scale.Value = new Vector3(1.0f, (float)noteUi.RenderTargetSize.Value.Y * noteScale, (float)noteUi.RenderTargetSize.Value.X * noteScale); noteModel.Serialize = false; noteModel.Enabled.Value = false; Property<Entity.Handle> note = result.GetOrMakeProperty<Entity.Handle>("Note"); Container togglePhoneMessage = null; result.Add(new NotifyBinding(delegate() { bool hasNoteOrSignalTower = (note.Value.Target != null && note.Value.Target.Active) || (signalTower.Value.Target != null && signalTower.Value.Target.Active); if (togglePhoneMessage == null && hasNoteOrSignalTower) togglePhoneMessage = ((GameMain)main).Menu.ShowMessage(result, "[{{TogglePhone}}]"); else if (togglePhoneMessage != null && !hasNoteOrSignalTower && !phoneActive && !noteActive) { ((GameMain)main).Menu.HideMessage(result, togglePhoneMessage); togglePhoneMessage = null; } }, note, signalTower)); result.Add(new CommandBinding(result.Delete, delegate() { ((GameMain)main).Menu.HideMessage(null, togglePhoneMessage); })); // Note UI const float notePadding = 40.0f; ListContainer noteLayout = new ListContainer(); noteLayout.Spacing.Value = padding; noteLayout.Orientation.Value = ListContainer.ListOrientation.Vertical; noteLayout.Alignment.Value = ListContainer.ListAlignment.Min; noteLayout.Position.Value = new Vector2(notePadding, notePadding); noteLayout.Add(new Binding<Vector2, Point>(noteLayout.Size, x => new Vector2(x.X - notePadding * 2.0f, x.Y - notePadding * 2.0f), noteUi.RenderTargetSize)); noteUi.Root.Children.Add(noteLayout); Sprite noteUiImage = new Sprite(); noteLayout.Children.Add(noteUiImage); TextElement noteUiText = new TextElement(); noteUiText.FontFile.Value = "Font"; noteUiText.Tint.Value = new Microsoft.Xna.Framework.Color(0.1f, 0.1f, 0.1f); noteUiText.Add(new Binding<float, Vector2>(noteUiText.WrapWidth, x => x.X, noteLayout.Size)); noteLayout.Children.Add(noteUiText); // Toggle note Action<bool> showNote = delegate(bool show) { noteActive.Value = show; input.EnableLook.Value = input.EnableMouse.Value = !noteActive; main.IsMouseVisible.Value = false; enableWalking.Value = enableMoves.Value = !noteActive; noteModel.Enabled.Value = noteActive; noteUi.Enabled.Value = noteActive; model.Stop("Phone", "Note"); Entity noteEntity = note.Value.Target; if (noteEntity != null && noteEntity.Active) { if (noteActive) { noteUiImage.Image.Value = noteEntity.GetOrMakeProperty<string>("Image"); noteUiText.Text.Value = noteEntity.GetOrMakeProperty<string>("Text"); model.StartClip("Note", 6, true, AnimatedModel.DefaultBlendTime * 2.0f); float startRotationY = input.Mouse.Value.Y; // Level the player's view result.Add(new Animation ( new Animation.Ease ( new Animation.Custom(delegate(float x) { input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * (1.0f - x)); }, 0.5f), Animation.Ease.Type.OutQuadratic ) )); } else { Property<bool> collected = noteEntity.GetOrMakeProperty<bool>("Collected"); if (!collected) collected.Value = true; } } }; // Toggle phone Container phoneTutorialMessage = null; Action<bool> showPhone = delegate(bool show) { if (togglePhoneMessage != null) { ((GameMain)main).Menu.HideMessage(result, togglePhoneMessage); togglePhoneMessage = null; } if (phoneTutorialMessage != null) { ((GameMain)main).Menu.HideMessage(result, phoneTutorialMessage); phoneTutorialMessage = null; } if (show || (phone.Schedules.Count == 0 && !phone.WaitForAnswer)) { phoneActive.Value = show; input.EnableLook.Value = input.EnableMouse.Value = !phoneActive; main.IsMouseVisible.Value = phoneActive; enableWalking.Value = enableMoves.Value = !phoneActive; phoneModel.Enabled.Value = phoneActive; screen.Enabled.Value = phoneActive; phoneUi.Enabled.Value = phoneActive; phoneLight.Enabled.Value = phoneActive; answerContainer.Visible.Value = false; model.Stop("Phone", "Note"); if (phoneActive) { if (!phone.TutorialShown) { phone.TutorialShown.Value = true; phoneTutorialMessage = ((GameMain)main).Menu.ShowMessage(result, "\\scroll for more"); } phoneScroll.CheckLayout(); scrollToBottom(); model.StartClip("Phone", 6, true, AnimatedModel.DefaultBlendTime * 2.0f); // Level the player's view float startRotationY = input.Mouse.Value.Y; result.Add(new Animation ( new Animation.Ease ( new Animation.Custom(delegate(float x) { input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * (1.0f - x)); }, 0.5f), Animation.Ease.Type.OutQuadratic ) )); } } }; input.Bind(((GameMain)main).Settings.TogglePhone, PCInput.InputState.Up, delegate() { if (noteActive || phoneActive || phone.CanReceiveMessages) { if (!phoneActive && (noteActive || note.Value.Target != null && note.Value.Target.Active)) showNote(!noteActive); else if (phone.Enabled) showPhone(!phoneActive); } }); // Gamepad code for the phone input.Add(new CommandBinding(input.GetButtonUp(Buttons.A), () => phoneActive && composeButton.Visible, delegate() { if (answerContainer.Visible) answerList.Children[selectedAnswer].MouseLeftUp.Execute(new Point()); else answerContainer.Visible.Value = true; })); input.Add(new CommandBinding(input.GetButtonUp(Buttons.B), () => phoneActive && answerContainer.Visible, delegate() { answerContainer.Visible.Value = false; })); Action<int> scrollPhone = delegate(int delta) { if (answerContainer.Visible) { answerList.Children[selectedAnswer].Highlighted.Value = false; selectedAnswer += delta; while (selectedAnswer < 0) selectedAnswer += answerList.Children.Count; while (selectedAnswer > answerList.Children.Count - 1) selectedAnswer -= answerList.Children.Count; answerList.Children[selectedAnswer].Highlighted.Value = true; } else phoneScroll.MouseScrolled.Execute(new Point(), delta * -4); }; input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickUp), () => phoneActive, delegate() { scrollPhone(-1); })); input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadUp), () => phoneActive, delegate() { scrollPhone(-1); })); input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickDown), () => phoneActive, delegate() { scrollPhone(1); })); input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadDown), () => phoneActive, delegate() { scrollPhone(1); })); msgList.Add(new ListBinding<UIComponent, Phone.Message> ( msgList.Children, phone.Messages, delegate(Phone.Message msg) { return makeAlign(makeButton(msg.Incoming ? incomingColor : outgoingColor, "\\" + (msg.Text == null ? msg.ID : msg.Text), messageWidth - padding * 2.0f), !msg.Incoming); } )); answerList.Add(new ListBinding<UIComponent, Phone.Ans> ( answerList.Children, phone.ActiveAnswers, delegate(Phone.Ans answer) { UIComponent button = makeButton(outgoingColor, "\\" + (answer.Text == null ? answer.ID : answer.Text), messageWidth - padding * 4.0f); button.Add(new CommandBinding<Point>(button.MouseLeftUp, delegate(Point p) { phone.Answer(answer); // Disable the signal tower Entity s = signalTower.Value.Target; if (s != null && s.Active) s.Get<SignalTower>().Initial.Value = null; scrollToBottom(); if (togglePhoneMessage == null && phone.Schedules.Count == 0) // No more messages incoming togglePhoneMessage = ((GameMain)main).Menu.ShowMessage(result, "[{{TogglePhone}}]"); })); return button; } )); Action refreshComposeButtonVisibility = delegate() { bool show = phone.ActiveAnswers.Count > 0 && phone.Schedules.Count == 0; answerContainer.Visible.Value &= show; composeButton.Visible.Value = show; selectedAnswer = 0; }; composeButton.Add(new ListNotifyBinding<Phone.Ans>(refreshComposeButtonVisibility, phone.ActiveAnswers)); composeButton.Add(new ListNotifyBinding<Phone.Schedule>(refreshComposeButtonVisibility, phone.Schedules)); refreshComposeButtonVisibility(); result.Add(new CommandBinding(phone.MessageReceived, delegate() { if (phoneActive) scrollToBottom(); else showPhone(true); // Animate the new message Container lastMessage = (Container)msgList.Children[msgList.Children.Count - 1].Children[0]; lastMessage.CheckLayout(); Vector2 originalSize = lastMessage.Size; lastMessage.Size.Value = new Vector2(0, originalSize.Y); main.AddComponent(new Animation ( new Animation.Ease(new Animation.Vector2MoveTo(lastMessage.Size, originalSize, 0.5f), Animation.Ease.Type.OutExponential) )); AkSoundEngine.PostEvent("Phone_Play", result); if (togglePhoneMessage == null && phone.Schedules.Count == 0 && phone.ActiveAnswers.Count == 0) // No more messages incoming, and no more answers to give togglePhoneMessage = ((GameMain)main).Menu.ShowMessage(result, "[{{TogglePhone}}]"); })); if (noteActive) showNote(true); else if (phoneActive) showPhone(true); }
public override void Bind(Entity result, Main main, bool creating = false) { PointLight light = result.GetOrCreate<PointLight>("PointLight"); light.Serialize = false; const float defaultLightAttenuation = 15.0f; light.Attenuation.Value = defaultLightAttenuation; Transform transform = result.GetOrCreate<Transform>("Transform"); light.Add(new Binding<Vector3>(light.Position, transform.Position)); VoxelChaseAI chase = result.GetOrCreate<VoxelChaseAI>("VoxelChaseAI"); chase.Filter = delegate(Map.CellState state) { return state.ID == 0 ? VoxelChaseAI.Cell.Empty : VoxelChaseAI.Cell.Filled; }; chase.Add(new TwoWayBinding<Vector3>(transform.Position, chase.Position)); result.Add(new CommandBinding(chase.Delete, result.Delete)); Sound sound = result.GetOrCreate<Sound>("LoopSound"); sound.Serialize = false; sound.Cue.Value = "Orb Loop"; sound.Is3D.Value = true; sound.IsPlaying.Value = true; sound.Add(new Binding<Vector3>(sound.Position, chase.Position)); Property<float> volume = sound.GetProperty("Volume"); Property<float> pitch = sound.GetProperty("Pitch"); const float defaultVolume = 0.5f; volume.Value = defaultVolume; AI ai = result.GetOrCreate<AI>(); Model model = result.GetOrCreate<Model>(); model.Add(new Binding<Matrix>(model.Transform, transform.Matrix)); model.Filename.Value = "Models\\sphere"; model.Editable = false; model.Serialize = false; const float defaultModelScale = 0.25f; model.Scale.Value = new Vector3(defaultModelScale); model.Add(new Binding<Vector3, string>(model.Color, delegate(string state) { switch (state) { case "Alert": return new Vector3(1.5f, 1.5f, 0.5f); case "Chase": return new Vector3(1.5f, 0.5f, 0.5f); case "Explode": return new Vector3(2.0f, 1.0f, 0.5f); case "Idle": return new Vector3(1.0f, 1.0f, 1.0f); default: return new Vector3(0.0f, 0.0f, 0.0f); } }, ai.CurrentState)); Random random = new Random(); result.Add(new Updater { delegate(float dt) { float source = ((float)random.NextDouble() - 0.5f) * 2.0f; model.Scale.Value = new Vector3(defaultModelScale * (1.0f + (source * 0.5f))); light.Attenuation.Value = defaultLightAttenuation * (1.0f + (source * 0.05f)); } }); model.Add(new Binding<bool, string>(model.Enabled, x => x != "Exploding", ai.CurrentState)); light.Add(new Binding<Vector3>(light.Color, model.Color)); Agent agent = result.GetOrCreate<Agent>(); agent.Add(new Binding<Vector3>(agent.Position, chase.Position)); Property<int> operationalRadius = result.GetOrMakeProperty<int>("OperationalRadius", true, 100); AI.Task checkOperationalRadius = new AI.Task { Interval = 2.0f, Action = delegate() { bool shouldBeActive = (chase.Position.Value - main.Camera.Position).Length() < operationalRadius; if (shouldBeActive && ai.CurrentState == "Suspended") ai.CurrentState.Value = "Idle"; else if (!shouldBeActive && ai.CurrentState != "Suspended") ai.CurrentState.Value = "Suspended"; }, }; const float sightDistance = 30.0f; const float hearingDistance = 15.0f; ai.Add(new AI.State { Name = "Idle", Enter = delegate(AI.State previous) { chase.Speed.Value = 3.0f; }, Tasks = new[] { checkOperationalRadius, new AI.Task { Interval = 1.0f, Action = delegate() { Agent a = Agent.Query(chase.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player"); if (a != null) ai.CurrentState.Value = "Alert"; }, }, }, }); Property<Entity.Handle> targetAgent = result.GetOrMakeProperty<Entity.Handle>("TargetAgent"); ai.Add(new AI.State { Name = "Alert", Enter = delegate(AI.State previous) { chase.Enabled.Value = false; }, Exit = delegate(AI.State next) { chase.Enabled.Value = true; }, Tasks = new[] { checkOperationalRadius, new AI.Task { Interval = 1.0f, Action = delegate() { if (ai.TimeInCurrentState > 3.0f) ai.CurrentState.Value = "Idle"; else { Agent a = Agent.Query(chase.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player"); if (a != null) { targetAgent.Value = a.Entity; ai.CurrentState.Value = "Chase"; } } }, }, }, }); AI.Task checkTargetAgent = new AI.Task { Action = delegate() { Entity target = targetAgent.Value.Target; if (target == null || !target.Active) { targetAgent.Value = null; ai.CurrentState.Value = "Idle"; } }, }; ai.Add(new AI.State { Name = "Chase", Enter = delegate(AI.State previous) { chase.Speed.Value = 10.0f; chase.TargetActive.Value = true; }, Exit = delegate(AI.State next) { chase.TargetActive.Value = false; }, Tasks = new[] { checkOperationalRadius, checkTargetAgent, new AI.Task { Action = delegate() { Entity target = targetAgent.Value.Target; Vector3 targetPosition = target.Get<Transform>().Position; chase.Target.Value = targetPosition; if ((targetPosition - chase.Position).Length() < 10.0f) ai.CurrentState.Value = "Explode"; } } }, }); ListProperty<Map.Coordinate> coordQueue = result.GetOrMakeListProperty<Map.Coordinate>("CoordQueue"); Property<Map.Coordinate> explosionOriginalCoord = result.GetOrMakeProperty<Map.Coordinate>("ExplosionOriginalCoord"); ai.Add(new AI.State { Name = "Explode", Enter = delegate(AI.State previous) { chase.Speed.Value = 5.0f; coordQueue.Clear(); chase.EnablePathfinding.Value = false; Map map = chase.Map.Value.Target.Get<Map>(); Map.Coordinate coord = chase.Coord.Value; Direction toSupport = Direction.None; foreach (Direction dir in DirectionExtensions.Directions) { if (map[coord.Move(dir)].ID != 0) { toSupport = dir; break; } } if (toSupport == Direction.None) { // Try again with the last coord coord = chase.LastCoord.Value; foreach (Direction dir in DirectionExtensions.Directions) { if (map[coord.Move(dir)].ID != 0) { toSupport = dir; break; } } if (toSupport == Direction.None) { ai.CurrentState.Value = "Idle"; return; } } Direction up = toSupport.GetReverse(); explosionOriginalCoord.Value = coord; Direction right; if (up.IsParallel(Direction.PositiveX)) right = Direction.PositiveZ; else right = Direction.PositiveX; Direction forward = up.Cross(right); for (Map.Coordinate y = coord.Clone(); y.GetComponent(up) < coord.GetComponent(up) + 3; y = y.Move(up)) { for (Map.Coordinate x = y.Clone(); x.GetComponent(right) < coord.GetComponent(right) + 2; x = x.Move(right)) { for (Map.Coordinate z = x.Clone(); z.GetComponent(forward) < coord.GetComponent(forward) + 2; z = z.Move(forward)) coordQueue.Add(z); } } }, Exit = delegate(AI.State next) { coordQueue.Clear(); chase.EnablePathfinding.Value = true; chase.LastCoord.Value = chase.Coord.Value = explosionOriginalCoord; }, Tasks = new[] { checkOperationalRadius, new AI.Task { Action = delegate() { volume.Value = MathHelper.Lerp(defaultVolume, 1.0f, ai.TimeInCurrentState.Value / 2.0f); pitch.Value = MathHelper.Lerp(0.0f, 0.5f, ai.TimeInCurrentState.Value / 2.0f); if (coordQueue.Count == 0) { // Explode ai.CurrentState.Value = "Exploding"; } }, }, }, }); Property<bool> exploded = result.GetOrMakeProperty<bool>("Exploded"); ai.Add(new AI.State { Name = "Exploding", Enter = delegate(AI.State previous) { chase.EnablePathfinding.Value = false; exploded.Value = false; sound.Stop.Execute(AudioStopOptions.AsAuthored); }, Exit = delegate(AI.State next) { chase.EnablePathfinding.Value = true; exploded.Value = false; volume.Value = defaultVolume; pitch.Value = 0.0f; sound.Play.Execute(); }, Tasks = new[] { new AI.Task { Interval = 0.1f, Action = delegate() { const int radius = 8; float timeInCurrentState = ai.TimeInCurrentState; if (timeInCurrentState > 1.0f && !exploded) { Map map = chase.Map.Value.Target.Get<Map>(); Explosion.Explode(main, map, chase.Coord, radius, 18.0f); exploded.Value = true; } if (timeInCurrentState > 2.0f) { Map map = chase.Map.Value.Target.Get<Map>(); Map.Coordinate? closestCell = map.FindClosestFilledCell(chase.Coord, radius + 1); if (closestCell.HasValue) { chase.Blend.Value = 0.0f; chase.Coord.Value = closestCell.Value; ai.CurrentState.Value = "Alert"; } else result.Delete.Execute(); } }, }, }, }); EffectBlockFactory factory = Factory.Get<EffectBlockFactory>(); Map.CellState snakeState = WorldFactory.StatesByName["Snake"]; chase.Add(new CommandBinding<Map, Map.Coordinate>(chase.Moved, delegate(Map m, Map.Coordinate c) { if (chase.Active) { if (coordQueue.Count > 0) { Map.Coordinate coord = chase.Coord.Value = coordQueue[0]; coordQueue.RemoveAt(0); Entity block = factory.CreateAndBind(main); snakeState.ApplyToEffectBlock(block.Get<ModelInstance>()); Map map = chase.Map.Value.Target.Get<Map>(); block.GetProperty<Vector3>("Offset").Value = map.GetRelativePosition(coord); Vector3 absolutePos = map.GetAbsolutePosition(coord); block.GetProperty<Vector3>("StartPosition").Value = absolutePos + new Vector3(0.05f, 0.1f, 0.05f); block.GetProperty<Matrix>("StartOrientation").Value = Matrix.CreateRotationX(0.15f) * Matrix.CreateRotationY(0.15f); block.GetProperty<float>("TotalLifetime").Value = 0.05f; factory.Setup(block, chase.Map.Value.Target, coord, snakeState.ID); main.Add(block); } } })); this.SetMain(result, main); }
public override void AttachEditorComponents(Entity result, Main main) { base.AttachEditorComponents(result, main); result.Add(new Binding<bool>(result.Get<Model>("EditorModel").Enabled, x => !x, result.GetOrMakeProperty<bool>("Valid"))); }
public override void Bind(Entity result, Main main, bool creating = false) { if (ParticleSystem.Get(main, "SnakeSparks") == null) { ParticleSystem.Add(main, "SnakeSparks", new ParticleSystem.ParticleSettings { TextureName = "Particles\\splash", MaxParticles = 1000, Duration = TimeSpan.FromSeconds(1.0f), MinHorizontalVelocity = -7.0f, MaxHorizontalVelocity = 7.0f, MinVerticalVelocity = 0.0f, MaxVerticalVelocity = 7.0f, Gravity = new Vector3(0.0f, -10.0f, 0.0f), MinRotateSpeed = -2.0f, MaxRotateSpeed = 2.0f, MinStartSize = 0.3f, MaxStartSize = 0.7f, MinEndSize = 0.0f, MaxEndSize = 0.0f, BlendState = Microsoft.Xna.Framework.Graphics.BlendState.AlphaBlend, MinColor = new Vector4(2.0f, 2.0f, 2.0f, 1.0f), MaxColor = new Vector4(2.0f, 2.0f, 2.0f, 1.0f), }); } result.CannotSuspendByDistance = true; Transform transform = result.Get<Transform>(); PointLight light = result.GetOrCreate<PointLight>("Light"); light.Color.Value = new Vector3(1.3f, 0.5f, 0.5f); light.Attenuation.Value = 10.0f; light.Shadowed.Value = false; light.Serialize = false; EnemyBase enemy = result.GetOrCreate<EnemyBase>("Base"); enemy.Add(new Binding<Matrix>(enemy.Transform, transform.Matrix)); enemy.Add(new CommandBinding(enemy.Delete, result.Delete)); Property<float> operationalRadius = result.GetOrMakeProperty<float>("OperationalRadius", true, 100.0f); light.Add(new Binding<Vector3>(light.Position, enemy.Position)); ListProperty<Map.Coordinate> path = result.GetOrMakeListProperty<Map.Coordinate>("PathCoordinates"); Property<Entity.Handle> targetAgent = result.GetOrMakeProperty<Entity.Handle>("TargetAgent"); AI ai = result.GetOrCreate<AI>("AI"); Agent agent = result.GetOrCreate<Agent>("Agent"); Map.CellState fillState = WorldFactory.StatesByName["Snake"]; Map.CellState criticalState = WorldFactory.StatesByName["InfectedCritical"]; Map.CellState temporaryState = WorldFactory.StatesByName["Temporary"]; VoxelChaseAI chase = null; result.Add(new PostInitialization { delegate() { if (chase.Map.Value.Target == null) chase.Position.Value = enemy.Position; } }); chase = result.GetOrCreate<VoxelChaseAI>("VoxelChaseAI"); chase.Filter = delegate(Map.CellState state) { int id = state.ID; if (id == fillState.ID || id == temporaryState.ID || id == 0) return VoxelChaseAI.Cell.Empty; if (state.Permanent || id == criticalState.ID) return VoxelChaseAI.Cell.Filled; return VoxelChaseAI.Cell.Penetrable; }; result.Add(new CommandBinding(chase.Delete, result.Delete)); PointLight positionLight = null; Property<float> positionLightRadius = result.GetOrMakeProperty<float>("PositionLightRadius", true, 20.0f); if (!main.EditorEnabled) { positionLight = new PointLight(); positionLight.Serialize = false; positionLight.Color.Value = new Vector3(1.5f, 0.5f, 0.5f); positionLight.Add(new Binding<float>(positionLight.Attenuation, positionLightRadius)); positionLight.Shadowed.Value = false; positionLight.Add(new Binding<bool, string>(positionLight.Enabled, x => x != "Suspended", ai.CurrentState)); positionLight.Add(new Binding<Vector3, string>(positionLight.Color, delegate(string state) { switch (state) { case "Chase": case "Crush": return new Vector3(1.5f, 0.5f, 0.5f); case "Alert": return new Vector3(1.5f, 1.5f, 0.5f); default: return new Vector3(1.0f, 1.0f, 1.0f); } }, ai.CurrentState)); result.Add("PositionLight", positionLight); ParticleEmitter emitter = result.GetOrCreate<ParticleEmitter>("Particles"); emitter.Editable = false; emitter.Serialize = false; emitter.ParticlesPerSecond.Value = 100; emitter.ParticleType.Value = "SnakeSparks"; emitter.Add(new Binding<Vector3>(emitter.Position, chase.Position)); emitter.Add(new Binding<bool, string>(emitter.Enabled, x => x != "Suspended", ai.CurrentState)); positionLight.Add(new Binding<Vector3>(positionLight.Position, chase.Position)); emitter.Add(new Binding<Vector3>(emitter.Position, chase.Position)); agent.Add(new Binding<Vector3>(agent.Position, chase.Position)); } AI.Task checkMap = new AI.Task { Action = delegate() { if (enemy.Map.Value.Target == null || !enemy.Map.Value.Target.Active) result.Delete.Execute(); }, }; AI.Task checkOperationalRadius = new AI.Task { Interval = 2.0f, Action = delegate() { bool shouldBeActive = (chase.Position.Value - main.Camera.Position).Length() < operationalRadius || (enemy.Map.Value.Target.Get<Map>().GetAbsolutePosition(enemy.BaseBoxes.First().GetCoords().First()) - main.Camera.Position).Length() < operationalRadius; if (shouldBeActive && ai.CurrentState == "Suspended") ai.CurrentState.Value = "Idle"; else if (!shouldBeActive && ai.CurrentState != "Suspended") ai.CurrentState.Value = "Suspended"; }, }; AI.Task checkTargetAgent = new AI.Task { Action = delegate() { Entity target = targetAgent.Value.Target; if (target == null || !target.Active) { targetAgent.Value = null; ai.CurrentState.Value = "Idle"; } }, }; chase.Add(new CommandBinding<Map, Map.Coordinate>(chase.Moved, delegate(Map m, Map.Coordinate c) { if (chase.Active) { if (m[c].ID != criticalState.ID) { bool regenerate = m.Empty(c); regenerate |= m.Fill(c, fillState); if (regenerate) m.Regenerate(); } Sound.PlayCue(main, "SnakeMove", chase.Position); if (path.Count > 0) { chase.Coord.Value = path[0]; path.RemoveAt(0); } } })); Property<Map.Coordinate> crushCoordinate = result.GetOrMakeProperty<Map.Coordinate>("CrushCoordinate"); ai.Setup ( new AI.State { Name = "Suspended", Tasks = new[] { checkOperationalRadius }, }, new AI.State { Name = "Idle", Tasks = new[] { checkMap, checkOperationalRadius, new AI.Task { Interval = 1.0f, Action = delegate() { Agent a = Agent.Query(chase.Position, 30.0f, 10.0f, x => x.Entity.Type == "Player"); if (a != null) ai.CurrentState.Value = "Alert"; }, }, }, }, new AI.State { Name = "Alert", Enter = delegate(AI.State previous) { chase.Enabled.Value = false; }, Exit = delegate(AI.State next) { chase.Enabled.Value = true; }, Tasks = new[] { checkMap, checkOperationalRadius, new AI.Task { Interval = 1.0f, Action = delegate() { if (ai.TimeInCurrentState > 3.0f) ai.CurrentState.Value = "Idle"; else { Agent a = Agent.Query(chase.Position, 30.0f, 20.0f, x => x.Entity.Type == "Player"); if (a != null) { targetAgent.Value = a.Entity; ai.CurrentState.Value = "Chase"; } } }, }, }, }, new AI.State { Name = "Chase", Enter = delegate(AI.State previousState) { chase.TargetActive.Value = true; }, Exit = delegate(AI.State nextState) { chase.TargetActive.Value = false; }, Tasks = new[] { checkMap, checkOperationalRadius, checkTargetAgent, new AI.Task { Interval = 0.07f, Action = delegate() { Vector3 targetPosition = targetAgent.Value.Target.Get<Agent>().Position; float targetDistance = (targetPosition - chase.Position).Length(); if (targetDistance > 50.0f || ai.TimeInCurrentState > 40.0f) // He got away ai.CurrentState.Value = "Alert"; else if (targetDistance < 5.0f) // We got 'im ai.CurrentState.Value = "Crush"; else chase.Target.Value = targetPosition; }, }, }, }, new AI.State { Name = "Crush", Enter = delegate(AI.State lastState) { // Set up cage Map.Coordinate center = enemy.Map.Value.Target.Get<Map>().GetCoordinate(targetAgent.Value.Target.Get<Agent>().Position); int radius = 1; // Bottom for (int x = center.X - radius; x <= center.X + radius; x++) { for (int z = center.Z - radius; z <= center.Z + radius; z++) path.Add(new Map.Coordinate { X = x, Y = center.Y - 4, Z = z }); } // Outer shell radius = 2; for (int y = center.Y - 3; y <= center.Y + 3; y++) { // Left for (int z = center.Z - radius; z <= center.Z + radius; z++) path.Add(new Map.Coordinate { X = center.X - radius, Y = y, Z = z }); // Right for (int z = center.Z - radius; z <= center.Z + radius; z++) path.Add(new Map.Coordinate { X = center.X + radius, Y = y, Z = z }); // Backward for (int x = center.X - radius; x <= center.X + radius; x++) path.Add(new Map.Coordinate { X = x, Y = y, Z = center.Z - radius }); // Forward for (int x = center.X - radius; x <= center.X + radius; x++) path.Add(new Map.Coordinate { X = x, Y = y, Z = center.Z + radius }); } // Top for (int x = center.X - radius; x <= center.X + radius; x++) { for (int z = center.Z - radius; z <= center.Z + radius; z++) path.Add(new Map.Coordinate { X = x, Y = center.Y + 3, Z = z }); } chase.EnablePathfinding.Value = false; chase.Speed.Value = 125.0f; crushCoordinate.Value = chase.Coord; }, Exit = delegate(AI.State nextState) { chase.EnablePathfinding.Value = true; chase.Speed.Value = 8.0f; chase.Coord.Value = chase.LastCoord.Value = crushCoordinate; path.Clear(); }, Tasks = new[] { checkMap, checkOperationalRadius, checkTargetAgent, new AI.Task { Interval = 0.01f, Action = delegate() { Agent a = targetAgent.Value.Target.Get<Agent>(); a.Health.Value -= 0.01f / 1.5f; // seconds to kill if (!a.Active) ai.CurrentState.Value = "Alert"; else { if ((a.Position - chase.Position.Value).Length() > 5.0f) // They're getting away ai.CurrentState.Value = "Chase"; } } } }, } ); this.SetMain(result, main); }
public override void Bind(Entity result, Main main, bool creating = false) { PointLight light = result.GetOrCreate<PointLight>("PointLight"); light.Serialize = false; const float defaultLightAttenuation = 15.0f; light.Attenuation.Value = defaultLightAttenuation; Transform transform = result.GetOrCreate<Transform>("Transform"); light.Add(new Binding<Vector3>(light.Position, transform.Position)); VoxelChaseAI chase = result.GetOrCreate<VoxelChaseAI>("VoxelChaseAI"); chase.Filter = delegate(Map.CellState state) { return state.ID == 0 ? VoxelChaseAI.Cell.Empty : VoxelChaseAI.Cell.Filled; }; chase.Add(new TwoWayBinding<Vector3>(transform.Position, chase.Position)); result.Add(new CommandBinding(chase.Delete, result.Delete)); Sound sound = result.GetOrCreate<Sound>("LoopSound"); sound.Serialize = false; sound.Cue.Value = "Orb Loop"; sound.Is3D.Value = true; sound.IsPlaying.Value = true; sound.Add(new Binding<Vector3>(sound.Position, chase.Position)); Property<float> volume = sound.GetProperty("Volume"); Property<float> pitch = sound.GetProperty("Pitch"); const float defaultVolume = 0.5f; volume.Value = defaultVolume; AI ai = result.GetOrCreate<AI>(); Model model = result.GetOrCreate<Model>(); model.Add(new Binding<Matrix>(model.Transform, transform.Matrix)); model.Filename.Value = "Models\\sphere"; model.Editable = false; model.Serialize = false; const float defaultModelScale = 0.25f; model.Scale.Value = new Vector3(defaultModelScale); model.Add(new Binding<Vector3, string>(model.Color, delegate(string state) { switch (state) { case "Alert": return new Vector3(1.5f, 1.5f, 0.5f); case "Chase": return new Vector3(1.5f, 0.5f, 0.5f); case "Levitating": return new Vector3(2.0f, 1.0f, 0.5f); case "Idle": return new Vector3(1.0f, 1.0f, 1.0f); default: return new Vector3(0.0f, 0.0f, 0.0f); } }, ai.CurrentState)); Random random = new Random(); result.Add(new Updater { delegate(float dt) { float source = ((float)random.NextDouble() - 0.5f) * 2.0f; model.Scale.Value = new Vector3(defaultModelScale * (1.0f + (source * 0.5f))); light.Attenuation.Value = defaultLightAttenuation * (1.0f + (source * 0.05f)); } }); model.Add(new Binding<bool, string>(model.Enabled, x => x != "Exploding", ai.CurrentState)); light.Add(new Binding<Vector3>(light.Color, model.Color)); Agent agent = result.GetOrCreate<Agent>(); agent.Add(new Binding<Vector3>(agent.Position, chase.Position)); Property<int> operationalRadius = result.GetOrMakeProperty<int>("OperationalRadius", true, 100); AI.Task checkOperationalRadius = new AI.Task { Interval = 2.0f, Action = delegate() { bool shouldBeActive = (chase.Position.Value - main.Camera.Position).Length() < operationalRadius; if (shouldBeActive && ai.CurrentState == "Suspended") ai.CurrentState.Value = "Idle"; else if (!shouldBeActive && ai.CurrentState != "Suspended") ai.CurrentState.Value = "Suspended"; }, }; const float sightDistance = 30.0f; const float hearingDistance = 15.0f; ai.Add(new AI.State { Name = "Idle", Enter = delegate(AI.State previous) { chase.Speed.Value = 3.0f; }, Tasks = new[] { checkOperationalRadius, new AI.Task { Interval = 1.0f, Action = delegate() { Agent a = Agent.Query(chase.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player"); if (a != null) ai.CurrentState.Value = "Alert"; }, }, }, }); Property<Entity.Handle> targetAgent = result.GetOrMakeProperty<Entity.Handle>("TargetAgent"); ai.Add(new AI.State { Name = "Alert", Enter = delegate(AI.State previous) { chase.Enabled.Value = false; }, Exit = delegate(AI.State next) { chase.Enabled.Value = true; }, Tasks = new[] { checkOperationalRadius, new AI.Task { Interval = 1.0f, Action = delegate() { if (ai.TimeInCurrentState > 3.0f) ai.CurrentState.Value = "Idle"; else { Agent a = Agent.Query(chase.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player"); if (a != null) { targetAgent.Value = a.Entity; ai.CurrentState.Value = "Chase"; } } }, }, }, }); AI.Task checkTargetAgent = new AI.Task { Action = delegate() { Entity target = targetAgent.Value.Target; if (target == null || !target.Active) { targetAgent.Value = null; ai.CurrentState.Value = "Idle"; } }, }; // Levitate Property<Entity.Handle> levitatingMap = result.GetOrMakeProperty<Entity.Handle>("LevitatingMap"); Property<Map.Coordinate> grabCoord = result.GetOrMakeProperty<Map.Coordinate>("GrabCoord"); const int levitateRipRadius = 4; Func<bool> tryLevitate = delegate() { Map map = chase.Map.Value.Target.Get<Map>(); Map.Coordinate? candidate = map.FindClosestFilledCell(chase.Coord, 3); if (!candidate.HasValue) return false; Map.Coordinate center = candidate.Value; if (!map[center].Permanent) { // Break off a chunk of this map into a new DynamicMap. List<Map.Coordinate> edges = new List<Map.Coordinate>(); Map.Coordinate ripStart = center.Move(-levitateRipRadius, -levitateRipRadius, -levitateRipRadius); Map.Coordinate ripEnd = center.Move(levitateRipRadius, levitateRipRadius, levitateRipRadius); Dictionary<Map.Box, bool> permanentBoxes = new Dictionary<Map.Box, bool>(); foreach (Map.Coordinate c in ripStart.CoordinatesBetween(ripEnd)) { Map.Box box = map.GetBox(c); if (box != null && box.Type.Permanent) permanentBoxes[box] = true; } foreach (Map.Box b in permanentBoxes.Keys) { // Top and bottom for (int x = b.X - 1; x <= b.X + b.Width; x++) { for (int z = b.Z - 1; z <= b.Z + b.Depth; z++) { Map.Coordinate coord = new Map.Coordinate { X = x, Y = b.Y + b.Height, Z = z }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); coord = new Map.Coordinate { X = x, Y = b.Y - 1, Z = z }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); } } // Outer shell for (int y = b.Y; y < b.Y + b.Height; y++) { // Left and right for (int z = b.Z - 1; z <= b.Z + b.Depth; z++) { Map.Coordinate coord = new Map.Coordinate { X = b.X - 1, Y = y, Z = z }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); coord = new Map.Coordinate { X = b.X + b.Width, Y = y, Z = z }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); } // Backward and forward for (int x = b.X; x < b.X + b.Width; x++) { Map.Coordinate coord = new Map.Coordinate { X = x, Y = y, Z = b.Z - 1 }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); coord = new Map.Coordinate { X = x, Y = y, Z = b.Z + b.Depth }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); } } } if (edges.Contains(center)) return false; // Top and bottom for (int x = ripStart.X; x <= ripEnd.X; x++) { for (int z = ripStart.Z; z <= ripEnd.Z; z++) { edges.Add(new Map.Coordinate { X = x, Y = ripStart.Y, Z = z }); edges.Add(new Map.Coordinate { X = x, Y = ripEnd.Y, Z = z }); } } // Sides for (int y = ripStart.Y + 1; y <= ripEnd.Y - 1; y++) { // Left and right for (int z = ripStart.Z; z <= ripEnd.Z; z++) { edges.Add(new Map.Coordinate { X = ripStart.X, Y = y, Z = z }); edges.Add(new Map.Coordinate { X = ripEnd.X, Y = y, Z = z }); } // Backward and forward for (int x = ripStart.X; x <= ripEnd.X; x++) { edges.Add(new Map.Coordinate { X = x, Y = y, Z = ripStart.Z }); edges.Add(new Map.Coordinate { X = x, Y = y, Z = ripEnd.Z }); } } map.Empty(edges); map.Regenerate(delegate(List<DynamicMap> spawnedMaps) { foreach (DynamicMap spawnedMap in spawnedMaps) { if (spawnedMap[center].ID != 0) { levitatingMap.Value = spawnedMap.Entity; break; } } }); grabCoord.Value = center; return true; } return false; }; Action delevitateMap = delegate() { Entity levitatingMapEntity = levitatingMap.Value.Target; if (levitatingMapEntity == null || !levitatingMapEntity.Active) return; DynamicMap dynamicMap = levitatingMapEntity.Get<DynamicMap>(); int maxDistance = levitateRipRadius + 7; Map closestMap = null; Map.Coordinate closestCoord = new Map.Coordinate(); foreach (Map m in Map.ActivePhysicsMaps) { if (m == dynamicMap) continue; Map.Coordinate relativeCoord = m.GetCoordinate(dynamicMap.Transform.Value.Translation); Map.Coordinate? closestFilled = m.FindClosestFilledCell(relativeCoord, maxDistance); if (closestFilled != null) { maxDistance = Math.Min(Math.Abs(relativeCoord.X - closestFilled.Value.X), Math.Min(Math.Abs(relativeCoord.Y - closestFilled.Value.Y), Math.Abs(relativeCoord.Z - closestFilled.Value.Z))); closestMap = m; closestCoord = closestFilled.Value; } } if (closestMap != null) { // Combine this map with the other one Direction x = closestMap.GetRelativeDirection(dynamicMap.GetAbsoluteVector(Vector3.Right)); Direction y = closestMap.GetRelativeDirection(dynamicMap.GetAbsoluteVector(Vector3.Up)); Direction z = closestMap.GetRelativeDirection(dynamicMap.GetAbsoluteVector(Vector3.Backward)); if (x.IsParallel(y)) x = y.Cross(z); else if (y.IsParallel(z)) y = x.Cross(z); Map.Coordinate offset = new Map.Coordinate(); float closestCoordDistance = float.MaxValue; Vector3 closestCoordPosition = closestMap.GetAbsolutePosition(closestCoord); foreach (Map.Coordinate c in dynamicMap.Chunks.SelectMany(c => c.Boxes).SelectMany(b => b.GetCoords())) { float distance = (dynamicMap.GetAbsolutePosition(c) - closestCoordPosition).LengthSquared(); if (distance < closestCoordDistance) { closestCoordDistance = distance; offset = c; } } Vector3 toLevitatingMap = dynamicMap.Transform.Value.Translation - closestMap.GetAbsolutePosition(closestCoord); offset = offset.Move(dynamicMap.GetRelativeDirection(-toLevitatingMap)); Matrix orientation = dynamicMap.Transform.Value; orientation.Translation = Vector3.Zero; EffectBlockFactory blockFactory = Factory.Get<EffectBlockFactory>(); int index = 0; foreach (Map.Coordinate c in dynamicMap.Chunks.SelectMany(c => c.Boxes).SelectMany(b => b.GetCoords()).OrderBy(c2 => new Vector3(c2.X - offset.X, c2.Y - offset.Y, c2.Z - offset.Z).LengthSquared())) { Map.Coordinate offsetFromCenter = c.Move(-offset.X, -offset.Y, -offset.Z); Map.Coordinate targetCoord = new Map.Coordinate(); targetCoord.SetComponent(x, offsetFromCenter.GetComponent(Direction.PositiveX)); targetCoord.SetComponent(y, offsetFromCenter.GetComponent(Direction.PositiveY)); targetCoord.SetComponent(z, offsetFromCenter.GetComponent(Direction.PositiveZ)); targetCoord = targetCoord.Move(closestCoord.X, closestCoord.Y, closestCoord.Z); if (closestMap[targetCoord].ID == 0) { Entity block = blockFactory.CreateAndBind(main); c.Data.ApplyToEffectBlock(block.Get<ModelInstance>()); block.GetProperty<Vector3>("Offset").Value = closestMap.GetRelativePosition(targetCoord); block.GetProperty<bool>("Scale").Value = false; block.GetProperty<Vector3>("StartPosition").Value = dynamicMap.GetAbsolutePosition(c); block.GetProperty<Matrix>("StartOrientation").Value = orientation; block.GetProperty<float>("TotalLifetime").Value = 0.05f + (index * 0.0075f); blockFactory.Setup(block, closestMap.Entity, targetCoord, c.Data.ID); main.Add(block); index++; } } // Delete the map levitatingMapEntity.Delete.Execute(); } }; // Chase AI state ai.Add(new AI.State { Name = "Chase", Enter = delegate(AI.State previous) { chase.Speed.Value = 10.0f; chase.TargetActive.Value = true; }, Exit = delegate(AI.State next) { chase.TargetActive.Value = false; }, Tasks = new[] { checkOperationalRadius, checkTargetAgent, new AI.Task { Interval = 0.1f, Action = delegate() { Entity target = targetAgent.Value.Target; Vector3 targetPosition = target.Get<Transform>().Position; chase.Target.Value = targetPosition; Entity levitatingMapEntity = levitatingMap.Value.Target; if ((targetPosition - chase.Position).Length() < 10.0f && (levitatingMapEntity == null || !levitatingMapEntity.Active)) { if (tryLevitate()) ai.CurrentState.Value = "Levitating"; } } } }, }); Property<Vector3> lastPosition = result.GetOrMakeProperty<Vector3>("LastPosition"); Property<Vector3> nextPosition = result.GetOrMakeProperty<Vector3>("NextPosition"); Property<float> positionBlend = result.GetOrMakeProperty<float>("PositionBlend"); Action findNextPosition = delegate() { lastPosition.Value = chase.Position.Value; nextPosition.Value = targetAgent.Value.Target.Get<Transform>().Position + new Vector3((float)random.NextDouble() - 0.5f, (float)random.NextDouble(), (float)random.NextDouble() - 0.5f) * 5.0f; positionBlend.Value = 0.0f; }; ai.Add(new AI.State { Name = "Levitating", Enter = delegate(AI.State previous) { chase.Enabled.Value = false; findNextPosition(); }, Exit = delegate(AI.State next) { delevitateMap(); levitatingMap.Value = null; Map map = chase.Map.Value.Target.Get<Map>(); Map.Coordinate currentCoord = map.GetCoordinate(chase.Position); Map.Coordinate? closest = map.FindClosestFilledCell(currentCoord, 10); if (closest.HasValue) { chase.LastCoord.Value = currentCoord; chase.Coord.Value = closest.Value; chase.Blend.Value = 0.0f; } chase.Enabled.Value = true; volume.Value = defaultVolume; pitch.Value = 0.0f; }, Tasks = new[] { checkTargetAgent, new AI.Task { Action = delegate() { volume.Value = 1.0f; pitch.Value = 1.0f; Entity levitatingMapEntity = levitatingMap.Value.Target; if (!levitatingMapEntity.Active || ai.TimeInCurrentState.Value > 8.0f) { ai.CurrentState.Value = "Alert"; return; } DynamicMap dynamicMap = levitatingMapEntity.Get<DynamicMap>(); positionBlend.Value += (main.ElapsedTime.Value / 1.0f); if (positionBlend > 1.0f) findNextPosition(); chase.Position.Value = Vector3.Lerp(lastPosition, nextPosition, positionBlend); Vector3 grabPoint = dynamicMap.GetAbsolutePosition(grabCoord); Vector3 diff = chase.Position.Value - grabPoint; if (diff.Length() > 15.0f) { ai.CurrentState.Value = "Chase"; return; } diff *= (float)Math.Sqrt(dynamicMap.PhysicsEntity.Mass) * 0.5f; dynamicMap.PhysicsEntity.ApplyImpulse(ref grabPoint, ref diff); }, }, }, }); this.SetMain(result, main); }
private static void attachEditorComponents(Entity result, Main main) { Transform transform = result.Get<Transform>(); Property<bool> selected = new Property<bool> { Value = false, Editable = false, Serialize = false }; result.Add("EditorSelected", selected); Property<Entity.Handle> parentMap = result.GetOrMakeProperty<Entity.Handle>("Parent"); Command<Entity> toggleEntityConnected = new Command<Entity> { Action = delegate(Entity entity) { parentMap.Value = entity; } }; result.Add("ToggleEntityConnected", toggleEntityConnected); LineDrawer connectionLines = new LineDrawer { Serialize = false }; connectionLines.Add(new Binding<bool>(connectionLines.Enabled, selected)); Color connectionLineColor = new Color(1.0f, 1.0f, 1.0f, 0.5f); Action recalculateLine = delegate() { connectionLines.Lines.Clear(); Entity parent = parentMap.Value.Target; if (parent != null) { connectionLines.Lines.Add(new LineDrawer.Line { A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(transform.Position, connectionLineColor), B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(parent.Get<Transform>().Position, connectionLineColor) }); } }; Model model = new Model(); model.Filename.Value = "Models\\cone"; model.Editable = false; model.Serialize = false; result.Add("DirectionModel", model); Property<Direction> dir = result.GetProperty<Direction>("Direction"); Transform mapTransform = result.Get<Transform>("MapTransform"); model.Add(new Binding<Matrix>(model.Transform, delegate() { Matrix m = Matrix.Identity; m.Translation = transform.Position; if (dir == Direction.None) m.Forward = m.Right = m.Up = Vector3.Zero; else { Vector3 normal = Vector3.TransformNormal(dir.Value.GetVector(), mapTransform.Matrix); m.Forward = -normal; if (normal.Equals(Vector3.Up)) m.Right = Vector3.Left; else if (normal.Equals(Vector3.Down)) m.Right = Vector3.Right; else m.Right = Vector3.Normalize(Vector3.Cross(normal, Vector3.Down)); m.Up = Vector3.Cross(normal, m.Left); } return m; }, transform.Matrix, mapTransform.Matrix)); NotifyBinding recalculateBinding = null; Action rebuildBinding = delegate() { if (recalculateBinding != null) { connectionLines.Remove(recalculateBinding); recalculateBinding = null; } if (parentMap.Value.Target != null) { recalculateBinding = new NotifyBinding(recalculateLine, parentMap.Value.Target.Get<Transform>().Matrix); connectionLines.Add(recalculateBinding); } recalculateLine(); }; connectionLines.Add(new NotifyBinding(rebuildBinding, parentMap)); connectionLines.Add(new NotifyBinding(recalculateLine, selected)); connectionLines.Add(new NotifyBinding(recalculateLine, () => selected, transform.Position)); result.Add(connectionLines); }
public static void Bind(Entity result, Main main, Func<BEPUphysics.Entities.Entity, BEPUphysics.Entities.Entity, Vector3, Vector3, Vector3, ISpaceObject> createJoint, bool allowRotation, bool creating = false) { Transform mapTransform = result.GetOrCreate<Transform>("MapTransform"); Transform transform = result.GetOrCreate<Transform>("Transform"); Factory.Get<DynamicMapFactory>().InternalBind(result, main, creating, mapTransform); DynamicMap map = result.Get<DynamicMap>(); Property<Entity.Handle> parentMap = result.GetOrMakeProperty<Entity.Handle>("Parent"); Property<Map.Coordinate> coord = result.GetOrMakeProperty<Map.Coordinate>("Coord"); Property<Direction> dir = result.GetOrMakeProperty<Direction>("Direction", true); Action refreshMapTransform = delegate() { Entity parent = parentMap.Value.Target; if (parent != null) { if (!parent.Active) parent = null; else { Map staticMap = parent.Get<Map>(); coord.Value = staticMap.GetCoordinate(transform.Position); mapTransform.Position.Value = staticMap.GetAbsolutePosition(staticMap.GetRelativePosition(coord) - new Vector3(0.5f) + staticMap.Offset + map.Offset); if (!allowRotation) mapTransform.Orientation.Value = parent.Get<Transform>().Orientation; } } else mapTransform.Matrix.Value = transform.Matrix; }; if (main.EditorEnabled) result.Add(new NotifyBinding(refreshMapTransform, transform.Matrix, map.Offset)); ISpaceObject joint = null; CommandBinding jointDeleteBinding = null, physicsUpdateBinding = null; Action rebuildJoint = null; rebuildJoint = delegate() { if (joint != null) { if (joint.Space != null) main.Space.Remove(joint); result.Remove(jointDeleteBinding); if (physicsUpdateBinding != null) result.Remove(physicsUpdateBinding); physicsUpdateBinding = null; joint = null; jointDeleteBinding = null; } Entity parent = parentMap.Value.Target; if (main.EditorEnabled) { refreshMapTransform(); return; } if (parent != null) { if (!parent.Active) parent = null; else { Map staticMap = parent.Get<Map>(); map.PhysicsEntity.Position = mapTransform.Position; if (!allowRotation) map.PhysicsEntity.Orientation = mapTransform.Quaternion; if (dir != Direction.None && !main.EditorEnabled) { Vector3 relativeLineAnchor = staticMap.GetRelativePosition(coord) - new Vector3(0.5f) + staticMap.Offset + map.Offset; Vector3 lineAnchor = staticMap.GetAbsolutePosition(relativeLineAnchor); DynamicMap dynamicMap = parent.Get<DynamicMap>(); joint = createJoint(map.PhysicsEntity, dynamicMap == null ? null : dynamicMap.PhysicsEntity, map.PhysicsEntity.Position, staticMap.GetAbsoluteVector(dir.Value.GetVector()), lineAnchor); main.Space.Add(joint); map.PhysicsEntity.ActivityInformation.Activate(); if (dynamicMap != null) { physicsUpdateBinding = new CommandBinding(dynamicMap.PhysicsUpdated, rebuildJoint); result.Add(physicsUpdateBinding); } jointDeleteBinding = new CommandBinding(parent.Delete, delegate() { parentMap.Value = null; }); result.Add(jointDeleteBinding); } } } }; result.Add(new NotifyBinding(rebuildJoint, parentMap)); result.Add(new CommandBinding(result.Delete, delegate() { if (joint != null && joint.Space != null) { main.Space.Remove(joint); joint = null; } })); result.Add(new CommandBinding(map.OnSuspended, delegate() { if (joint != null && joint.Space != null) main.Space.Remove(joint); })); result.Add(new CommandBinding(map.OnResumed, delegate() { if (joint != null && joint.Space == null) main.Space.Add(joint); })); rebuildJoint(); Command rebuildJointCommand = new Command(); result.Add(new CommandBinding(rebuildJointCommand, rebuildJoint)); result.Add("RebuildJoint", rebuildJointCommand); if (main.EditorEnabled) JointFactory.attachEditorComponents(result, main); }
public override void Bind(Entity result, Main main, bool creating = false) { Property<Direction> dir = result.GetOrMakeProperty<Direction>("Direction", true); Property<int> minimum = result.GetOrMakeProperty<int>("Minimum", true); Property<int> maximum = result.GetOrMakeProperty<int>("Maximum", true); Property<bool> locked = result.GetOrMakeProperty<bool>("Locked", true); Property<float> speed = result.GetOrMakeProperty<float>("Speed", true, 5); Property<float> maxForce = result.GetOrMakeProperty<float>("MaxForce", true); Property<float> damping = result.GetOrMakeProperty<float>("Damping", true); Property<float> stiffness = result.GetOrMakeProperty<float>("Stiffness", true); Property<int> goal = result.GetOrMakeProperty<int>("Goal", true); PrismaticJoint joint = null; Action setLimits = delegate() { if (joint != null) { int min = minimum, max = maximum; if (max > min) { joint.Limit.IsActive = true; joint.Limit.Minimum = minimum; joint.Limit.Maximum = maximum; } else joint.Limit.IsActive = false; } }; result.Add(new NotifyBinding(setLimits, minimum, maximum)); Action setMaxForce = delegate() { if (joint != null) { if (maxForce > 0.001f) joint.Motor.Settings.MaximumForce = maxForce * result.Get<DynamicMap>().PhysicsEntity.Mass; else joint.Motor.Settings.MaximumForce = float.MaxValue; } }; result.Add(new NotifyBinding(setMaxForce, maxForce)); Action setSpeed = delegate() { if (joint != null) joint.Motor.Settings.Servo.BaseCorrectiveSpeed = speed; }; result.Add(new NotifyBinding(setSpeed, speed)); Action setLocked = delegate() { if (joint != null) joint.Motor.IsActive = locked; }; result.Add(new NotifyBinding(setLocked, locked)); Action setGoal = delegate() { if (joint != null) joint.Motor.Settings.Servo.Goal = goal; }; result.Add(new NotifyBinding(setGoal, goal)); Action setDamping = delegate() { if (joint != null && damping != 0) joint.Motor.Settings.Servo.SpringSettings.DampingConstant = damping; }; result.Add(new NotifyBinding(setDamping, damping)); Action setStiffness = delegate() { if (joint != null && stiffness != 0) joint.Motor.Settings.Servo.SpringSettings.StiffnessConstant = stiffness; }; result.Add(new NotifyBinding(setStiffness, stiffness)); Func<BEPUphysics.Entities.Entity, BEPUphysics.Entities.Entity, Vector3, Vector3, Vector3, ISpaceObject> createJoint = delegate(BEPUphysics.Entities.Entity entity1, BEPUphysics.Entities.Entity entity2, Vector3 pos, Vector3 direction, Vector3 anchor) { joint = new PrismaticJoint(entity1, entity2, pos, -direction, anchor); joint.Motor.Settings.Mode = MotorMode.Servomechanism; setLimits(); setLocked(); setSpeed(); setMaxForce(); setGoal(); setDamping(); setStiffness(); return joint; }; JointFactory.Bind(result, main, createJoint, false, creating); result.Add("Forward", new Command { Action = delegate() { if (joint != null && locked) goal.Value = maximum; }, }); result.Add("Backward", new Command { Action = delegate() { if (joint != null && locked) goal.Value = minimum; }, }); Command hitMax = new Command(); result.Add("HitMax", hitMax); Command hitMin = new Command(); result.Add("HitMin", hitMin); bool lastLimitExceeded = false; result.Add(new Updater { delegate(float dt) { if (joint != null) { bool limitExceeded = joint.Limit.IsLimitExceeded; if (limitExceeded && !lastLimitExceeded) { if (joint.Limit.Error < 0) hitMin.Execute(); else hitMax.Execute(); } lastLimitExceeded = limitExceeded; } } }); }
public override void Bind(Entity result, Main main, bool creating = false) { result.CannotSuspendByDistance = true; const float kernelSpacing = 8.0f; const int kernelSize = 10; const float raycastHeight = 30.0f; const float rainStartHeight = 25.0f; const float raycastInterval = 0.25f; const float verticalSpeed = 90.0f; const float maxLifetime = 1.0f; ParticleEmitter emitter = result.Get<ParticleEmitter>("Emitter"); emitter.Jitter.Value = new Vector3(kernelSpacing * kernelSize * 0.5f, 0.0f, kernelSpacing * kernelSize * 0.5f); Transform transform = result.Get<Transform>(); Sound rainSound = result.GetOrCreate<Sound>("RainSound"); rainSound.Cue.Value = "Rain"; rainSound.Is3D.Value = false; rainSound.IsPlaying.Value = true; Property<float> rainSoundVolume = rainSound.GetProperty("Volume"); Components.DirectionalLight lightning = result.GetOrCreate<Components.DirectionalLight>("Lightning"); lightning.Enabled.Value = false; Vector3 originalLightningColor = lightning.Color; float[,] audioKernel = new float[kernelSize, kernelSize]; float sum = 0.0f; for (int x = 0; x < kernelSize; x++) { for (int y = 0; y < kernelSize; y++) { float cell = (kernelSize / 2) - new Vector2(x - (kernelSize / 2), y - (kernelSize / 2)).Length(); audioKernel[x, y] = cell; sum += cell; } } for (int x = 0; x < kernelSize; x++) { for (int y = 0; y < kernelSize; y++) audioKernel[x, y] /= sum; } float[,] raycastHeights = new float[kernelSize, kernelSize]; float raycastTimer = raycastInterval; Vector3 kernelOffset = Vector3.Zero; Updater updater = new Updater { delegate(float dt) { raycastTimer += dt; if (raycastTimer > raycastInterval) { raycastTimer = 0.0f; Vector3 cameraPos = main.Camera.Position; float averageHeight = 0.0f; kernelOffset = main.Camera.Position + new Vector3(kernelSize * kernelSpacing * -0.5f, raycastHeight + rainStartHeight, kernelSize * kernelSpacing * -0.5f); for (int x = 0; x < kernelSize; x++) { for (int y = 0; y < kernelSize; y++) { Vector3 pos = kernelOffset + new Vector3(x * kernelSpacing, 0, y * kernelSpacing); Map.GlobalRaycastResult raycast = Map.GlobalRaycast(pos, Vector3.Down, rainStartHeight + raycastHeight + (verticalSpeed * maxLifetime)); float height = raycast.Map == null ? float.MinValue : raycast.Position.Y; raycastHeights[x, y] = height; averageHeight += Math.Max(cameraPos.Y, Math.Min(height, cameraPos.Y + rainStartHeight)) * audioKernel[x, y]; } } rainSoundVolume.Value = 1.0f - ((averageHeight - cameraPos.Y) / rainStartHeight); } } }; updater.EnabledInEditMode.Value = true; result.Add(updater); Random random = new Random(); Property<float> thunderIntervalMin = result.GetOrMakeProperty<float>("ThunderIntervalMin", true, 12.0f); Property<float> thunderIntervalMax = result.GetOrMakeProperty<float>("ThunderIntervalMax", true, 36.0f); Property<float> thunderMaxDelay = result.GetOrMakeProperty<float>("ThunderMaxDelay", true, 5.0f); Timer timer = result.GetOrCreate<Timer>(); timer.Serialize = false; timer.Repeat.Value = true; timer.Interval.Value = (float)random.NextDouble() * thunderIntervalMax; timer.Add(new CommandBinding(timer.Command, delegate() { float volume = 0.5f + ((float)random.NextDouble() * 0.5f); result.Add(new Animation ( new Animation.Set<bool>(lightning.Enabled, true), new Animation.Vector3MoveTo(lightning.Color, originalLightningColor * volume, 0.2f), new Animation.Vector3MoveTo(lightning.Color, Vector3.Zero, 0.25f), new Animation.Set<bool>(lightning.Enabled, false), new Animation.Delay((1.0f - volume) * thunderMaxDelay), new Animation.Execute(delegate() { Sound thunder = Sound.PlayCue(main, "Thunder", main.Camera.Position + Vector3.Normalize(new Vector3(2.0f * ((float)random.NextDouble() - 0.5f), 1.0f, 2.0f * ((float)random.NextDouble() - 0.5f))) * 1000.0f, volume); if (thunder != null) result.Add(thunder); }) )); timer.Interval.Value = thunderIntervalMin + ((float)random.NextDouble() * (thunderIntervalMax - thunderIntervalMin)); })); if (ParticleSystem.Get(main, "Rain") == null) { ParticleSystem.Add(main, "Rain", new ParticleSystem.ParticleSettings { TextureName = "Particles\\default", EffectFile = "Effects\\ParticleRain", MaxParticles = 25000, Duration = TimeSpan.FromSeconds(maxLifetime), MinHorizontalVelocity = 0.0f, MaxHorizontalVelocity = 0.0f, MinVerticalVelocity = -verticalSpeed, MaxVerticalVelocity = -verticalSpeed, Gravity = new Vector3(0.0f, 0.0f, 0.0f), MinRotateSpeed = 0.0f, MaxRotateSpeed = 0.0f, MinStartSize = 0.3f, MaxStartSize = 0.3f, MinEndSize = 0.3f, MaxEndSize = 0.3f, BlendState = BlendState.Opaque, MinColor = new Vector4(0.5f, 0.6f, 0.7f, 1.0f), MaxColor = new Vector4(0.5f, 0.6f, 0.7f, 1.0f), }); emitter.ParticleType.Reset(); } emitter.AddParticle = delegate(Vector3 position, Vector3 velocity) { Vector3 kernelCoord = (position - kernelOffset) / kernelSpacing; float height = raycastHeights[Math.Max(0, Math.Min(kernelSize - 1, (int)kernelCoord.X)), Math.Max(0, Math.Min(kernelSize - 1, (int)kernelCoord.Z))]; if (height < position.Y) emitter.ParticleSystem.AddParticle(position, Vector3.Zero, Math.Min((position.Y - height) / verticalSpeed, maxLifetime)); }; emitter.Add(new Binding<Vector3>(emitter.Position, x => x + new Vector3(0.0f, rainStartHeight, 0.0f), main.Camera.Position)); this.SetMain(result, main); }
private static void attachEditorComponents(Entity result, Main main) { Transform transform = result.Get<Transform>(); Property<Entity.Handle> parentMap = result.GetOrMakeProperty<Entity.Handle>("Parent"); EntityConnectable.AttachEditorComponents(result, parentMap); Model model = new Model(); model.Filename.Value = "Models\\cone"; model.Editable = false; model.Serialize = false; result.Add("DirectionModel", model); Property<Direction> dir = result.GetProperty<Direction>("Direction"); Transform mapTransform = result.Get<Transform>("MapTransform"); model.Add(new Binding<Matrix>(model.Transform, delegate() { Matrix m = Matrix.Identity; m.Translation = transform.Position; if (dir == Direction.None) m.Forward = m.Right = m.Up = Vector3.Zero; else { Vector3 normal = Vector3.TransformNormal(dir.Value.GetVector(), mapTransform.Matrix); m.Forward = -normal; if (normal.Equals(Vector3.Up)) m.Right = Vector3.Left; else if (normal.Equals(Vector3.Down)) m.Right = Vector3.Right; else m.Right = Vector3.Normalize(Vector3.Cross(normal, Vector3.Down)); m.Up = Vector3.Cross(normal, m.Left); } return m; }, transform.Matrix, mapTransform.Matrix)); }