public void Setup(Entity map, Voxel.Coord c, Voxel.t s) { this.TargetVoxel = map; this.Coord = c; this.StateId = s; this.addEntry(); }
private void updateMaterial() { if (!this.main.EditorEnabled) { DynamicVoxel map = this.Entity.Get <DynamicVoxel>(); if (map != null) { bool active = this.Locked && (!this.Servo || (this.Servo && this.Goal.Value != this.Minimum.Value)); Voxel.State desired = active ? Voxel.States.SliderPowered : Voxel.States.Slider; Voxel.t currentID = map[0, 0, 0].ID; if (currentID != desired.ID & (currentID == Voxel.t.Slider || currentID == Voxel.t.SliderPowered)) { List <Voxel.Coord> coords = map.GetContiguousByType(new[] { map.GetBox(0, 0, 0) }).SelectMany(x => x.GetCoords()).ToList(); map.Empty(coords, true, true, null, false); foreach (Voxel.Coord c in coords) { map.Fill(c, desired); } map.Regenerate(); } map.PhysicsEntity.ActivityInformation.Activate(); } } }
private void checkShouldBuildFloor() { if (this.EnableEnhancedRollSlide) { Voxel.GlobalRaycastResult floorRaycast = this.raycastFloor(); if (floorRaycast.Voxel != null && floorRaycast.Voxel.Entity.Type != "Bouncer") { Voxel.t t = floorRaycast.Voxel[floorRaycast.Coordinate.Value].ID; if (t != Voxel.t.Blue && t != Voxel.t.Powered && t != Voxel.t.Slider && t != Voxel.t.SliderPowered) { this.floorCoordinate = floorRaycast.Coordinate.Value; this.shouldBuildFloor = true; if (this.Kicking) { this.sliding = true; AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_SLIDE_LOOP, this.Entity); } } } } }
public override void Bind(Entity entity, Main main, bool creating = false) { Transform transform = entity.GetOrCreate <Transform>("Transform"); this.SetMain(entity, main); VoxelAttachable attachable = VoxelAttachable.MakeAttachable(entity, main, true, false); attachable.Offset.Value = 1; attachable.Enabled.Value = true; PowerBlockSocket socket = entity.GetOrCreate <PowerBlockSocket>("PowerBlockSocket"); socket.Add(new Binding <Voxel.Coord>(socket.Coord, attachable.Coord)); socket.Add(new Binding <Entity.Handle>(socket.AttachedVoxel, attachable.AttachedVoxel)); const float maxLightAttenuation = 15.0f; PointLight light = entity.Create <PointLight>(); light.Attenuation.Value = maxLightAttenuation; light.Add(new Binding <Vector3>(light.Position, transform.Position)); light.Add(new Binding <Vector3, Voxel.t>(light.Color, delegate(Voxel.t t) { switch (t) { case Voxel.t.GlowBlue: return(new Vector3(0.8f, 0.9f, 1.2f)); case Voxel.t.GlowYellow: return(new Vector3(1.2f, 1.2f, 0.8f)); default: return(Vector3.One); } }, socket.Type)); light.Add(new Binding <bool>(light.Enabled, socket.Powered)); PointLight animationLight = entity.Create <PointLight>(); animationLight.Add(new Binding <Vector3>(animationLight.Position, light.Position)); animationLight.Add(new Binding <Vector3>(animationLight.Color, light.Color)); animationLight.Enabled.Value = false; PlayerTrigger trigger = entity.GetOrCreate <PlayerTrigger>("PlayerTrigger"); trigger.Radius.Value = 7; trigger.Add(new Binding <Vector3>(trigger.Position, transform.Position)); const float minimumChangeTime = 1.5f; float lastChange = -minimumChangeTime; trigger.Add(new CommandBinding(trigger.PlayerEntered, delegate() { if (main.TotalTime - lastChange > minimumChangeTime) { BlockCloud cloud = PlayerFactory.Instance.Get <BlockCloud>(); bool changed = false; Voxel sockVoxel = attachable.AttachedVoxel.Value.Target.Get <Voxel>(); if (!socket.Powered && cloud.Type.Value == socket.Type.Value) { // Plug in to the socket List <Voxel.Coord> coords = new List <Voxel.Coord>(); Queue <Voxel.Coord> queue = new Queue <Voxel.Coord>(); queue.Enqueue(sockVoxel.GetCoordinate(transform.Position)); while (queue.Count > 0) { Voxel.Coord c = queue.Dequeue(); coords.Add(c); if (coords.Count >= cloud.Blocks.Length) { break; } Voxel.CoordDictionaryCache[c] = true; foreach (Direction adjacentDirection in DirectionExtensions.Directions) { Voxel.Coord adjacentCoord = c.Move(adjacentDirection); if (!Voxel.CoordDictionaryCache.ContainsKey(adjacentCoord)) { Voxel.t adjacentID = sockVoxel[adjacentCoord].ID; if (adjacentID == Voxel.t.Empty) { queue.Enqueue(adjacentCoord); } } } } Voxel.CoordDictionaryCache.Clear(); EffectBlockFactory factory = Factory.Get <EffectBlockFactory>(); int i = 0; foreach (Entity block in cloud.Blocks) { Entity effectBlockEntity = factory.CreateAndBind(main); Voxel.States.All[cloud.Type].ApplyToEffectBlock(effectBlockEntity.Get <ModelInstance>()); EffectBlock effectBlock = effectBlockEntity.Get <EffectBlock>(); effectBlock.DoScale = false; Transform blockTransform = block.Get <Transform>(); effectBlock.StartPosition = blockTransform.Position; effectBlock.StartOrientation = blockTransform.Quaternion; effectBlock.TotalLifetime = (i + 1) * 0.04f; effectBlock.Setup(sockVoxel.Entity, coords[i], cloud.Type); main.Add(effectBlockEntity); block.Delete.Execute(); i++; } cloud.Blocks.Clear(); cloud.Type.Value = Voxel.t.Empty; socket.Powered.Value = true; changed = true; } else if (socket.Powered && cloud.Type.Value == Voxel.t.Empty && !socket.PowerOnOnly) { // Pull blocks out of the socket SceneryBlockFactory factory = Factory.Get <SceneryBlockFactory>(); Quaternion quat = Quaternion.CreateFromRotationMatrix(sockVoxel.Transform); cloud.Type.Value = socket.Type; List <Voxel.Coord> coords = sockVoxel.GetContiguousByType(new[] { sockVoxel.GetBox(transform.Position) }).SelectMany(x => x.GetCoords()).ToList(); sockVoxel.Empty(coords, true); sockVoxel.Regenerate(); ParticleSystem particles = ParticleSystem.Get(main, "WhiteShatter"); foreach (Voxel.Coord c in coords) { Vector3 pos = sockVoxel.GetAbsolutePosition(c); for (int j = 0; j < 20; j++) { Vector3 offset = new Vector3((float)this.random.NextDouble() - 0.5f, (float)this.random.NextDouble() - 0.5f, (float)this.random.NextDouble() - 0.5f); particles.AddParticle(pos + offset, offset); } Entity block = factory.CreateAndBind(main); Transform blockTransform = block.Get <Transform>(); blockTransform.Position.Value = pos; blockTransform.Quaternion.Value = quat; SceneryBlock sceneryBlock = block.Get <SceneryBlock>(); sceneryBlock.Type.Value = socket.Type; sceneryBlock.Scale.Value = 0.5f; cloud.Blocks.Add(block); main.Add(block); } socket.Powered.Value = false; changed = true; } if (changed) { lastChange = main.TotalTime; animationLight.Enabled.Value = true; animationLight.Attenuation.Value = 0.0f; entity.Add(new Animation ( new Animation.FloatMoveTo(animationLight.Attenuation, maxLightAttenuation, 0.25f), new Animation.FloatMoveTo(animationLight.Attenuation, 0.0f, 2.0f), new Animation.Set <bool>(animationLight.Enabled, false) )); } } })); entity.Add("Type", socket.Type); entity.Add("Powered", socket.Powered, new PropertyEntry.EditorData { Readonly = true }); entity.Add("PowerOnOnly", socket.PowerOnOnly); entity.Add("OnPowerOn", socket.OnPowerOn); entity.Add("OnPowerOff", socket.OnPowerOff); }
public override void Awake() { base.Awake(); this.blockFactory = Factory.Get <EffectBlockFactory>(); this.EnabledWhenPaused = false; if (main.EditorEnabled) { this.BlockQueue.Clear(); } this.particles = ParticleSystem.Get(main, "WhiteShatter"); for (int i = 0; i < maxSparkLights; i++) { PointLight light = new PointLight(); light.Serialize = false; light.Color.Value = new Vector3(1.0f); light.Enabled.Value = false; this.Entity.Add(light); this.sparkLights.Add(light); } if (!this.main.EditorEnabled) { this.Add(new CommandBinding <Voxel, IEnumerable <Voxel.Coord>, Voxel>(Voxel.GlobalCellsFilled, delegate(Voxel map, IEnumerable <Voxel.Coord> coords, Voxel transferredFromMap) { foreach (Voxel.Coord c in coords) { Voxel.t id = c.Data.ID; if (id == Voxel.t.Blue || id == Voxel.t.Powered || id == Voxel.t.PoweredSwitch || id == Voxel.t.Infected || id == Voxel.t.Neutral || id == Voxel.t.HardPowered || id == Voxel.t.Hard || id == Voxel.t.HardInfected) { Voxel.Coord newCoord = c; newCoord.Data = Voxel.States.Empty; int generation; EffectBlock.Entry generationsKey = new EffectBlock.Entry { Voxel = map, Coordinate = newCoord }; if (this.generations.TryGetValue(generationsKey, out generation)) { this.generations.Remove(generationsKey); } if (!this.isInQueue(map.Entity, newCoord, false)) { this.BlockQueue.Add(new ScheduledBlock { Voxel = map.Entity, Coordinate = newCoord, Time = propagateDelay, Generation = generation, }); } } } })); this.Add(new CommandBinding <Voxel, IEnumerable <Voxel.Coord>, Voxel>(Voxel.GlobalCellsEmptied, delegate(Voxel map, IEnumerable <Voxel.Coord> coords, Voxel transferringToNewMap) { foreach (Voxel.Coord coord in coords) { Voxel.t id = coord.Data.ID; if (id == Voxel.t.Powered || id == Voxel.t.PoweredSwitch || id == Voxel.t.HardPowered || id == Voxel.t.PermanentPowered) { this.removedPoweredCoords.Add(coord); } if (transferringToNewMap != null) { continue; } if (id == Voxel.t.Critical) // Critical. Explodes when destroyed. { Explosion.Explode(main, map, coord); } else if (id == Voxel.t.HardInfected) // Infected. Shatter effects. { ParticleSystem shatter = ParticleSystem.Get(main, "InfectedShatter"); Vector3 pos = map.GetAbsolutePosition(coord); AkSoundEngine.PostEvent(AK.EVENTS.PLAY_INFECTED_CRITICAL_SHATTER, pos); for (int i = 0; i < 50; i++) { Vector3 offset = new Vector3((float)random.NextDouble() - 0.5f, (float)random.NextDouble() - 0.5f, (float)random.NextDouble() - 0.5f); shatter.AddParticle(pos + offset, offset); } } else if (id == Voxel.t.Powered || id == Voxel.t.Blue || id == Voxel.t.Neutral || id == Voxel.t.Infected || id == Voxel.t.Floater) { int generation; Voxel.Coord c = coord; c.Data = Voxel.States.Empty; EffectBlock.Entry generationKey = new EffectBlock.Entry { Voxel = map, Coordinate = c }; if (this.generations.TryGetValue(generationKey, out generation)) { this.generations.Remove(generationKey); } if (id == Voxel.t.Floater) { Entity blockEntity = this.blockFactory.CreateAndBind(main); EffectBlock effectBlock = blockEntity.Get <EffectBlock>(); coord.Data.ApplyToEffectBlock(blockEntity.Get <ModelInstance>()); effectBlock.Delay = 4.0f; effectBlock.Offset.Value = map.GetRelativePosition(coord); effectBlock.StartPosition = map.GetAbsolutePosition(coord) + new Vector3(2.5f, 5.0f, 2.5f); effectBlock.StartOrientation = Quaternion.CreateFromYawPitchRoll(1.0f, 1.0f, 0); effectBlock.TotalLifetime = 0.5f; effectBlock.Setup(map.Entity, coord, coord.Data.ID); main.Add(blockEntity); } if (generation == 0) { if (!this.isInQueue(map.Entity, coord, true)) { this.BlockQueue.Add(new ScheduledBlock { Voxel = map.Entity, Coordinate = coord, Time = propagateDelay, Removing = true, }); } } else if (generation < maxGenerations) { Direction down = map.GetRelativeDirection(Direction.NegativeY); for (int i = 0; i < 6; i++) { Direction dir = DirectionExtensions.Directions[i]; Voxel.Coord adjacent = coord.Move(dir); if (!coords.Contains(adjacent)) { Voxel.t adjacentID = map[adjacent].ID; bool adjacentIsFloater = adjacentID == Voxel.t.Floater; if (dir != down || adjacentIsFloater) { if (adjacentID == Voxel.t.Powered || adjacentID == Voxel.t.Blue || adjacentID == Voxel.t.Neutral || adjacentID == Voxel.t.Infected || adjacentIsFloater) { if (!this.isInQueue(map.Entity, adjacent, true)) { this.BlockQueue.Add(new ScheduledBlock { Voxel = map.Entity, Coordinate = adjacent, Time = propagateDelay, Removing = true, Generation = generation + 1, }); } } } } } } } else if (id == Voxel.t.White || id == Voxel.t.Glass) // Shatter effects. { ParticleSystem shatter = ParticleSystem.Get(main, "WhiteShatter"); Vector3 pos = map.GetAbsolutePosition(coord); for (int i = 0; i < 50; i++) { Vector3 offset = new Vector3((float)this.random.NextDouble() - 0.5f, (float)this.random.NextDouble() - 0.5f, (float)this.random.NextDouble() - 0.5f); shatter.AddParticle(pos + offset, offset); } float time = this.main.TotalTime; if (time - this.lastShatterSound > 0.3f) { this.lastShatterSound = time; AkSoundEngine.PostEvent(AK.EVENTS.PLAY_WHITE_SHATTER, pos); } } } if (this.removedPoweredCoords.Count > 0) { IEnumerable <IEnumerable <Voxel.Box> > poweredIslands = map.GetAdjacentIslands(this.removedPoweredCoords, x => x.ID == Voxel.t.Powered || x.ID == Voxel.t.HardPowered, x => x == Voxel.States.PermanentPowered || x == Voxel.States.PoweredSwitch); List <Voxel.Coord> poweredCoords = poweredIslands.SelectMany(x => x).SelectMany(x => x.GetCoords()).ToList(); if (poweredCoords.Count > 0) { lock (map.MutationLock) { map.Empty(poweredCoords, true, true, map, false); for (int i = 0; i < poweredCoords.Count; i++) { Voxel.Coord coord = poweredCoords[i]; if (coord.Data.ID == Voxel.t.HardPowered) { map.Fill(coord, Voxel.States.Hard, false); } else { map.Fill(coord, Voxel.States.Blue, false); } } } this.toRegenerate.Add(map); } this.removedPoweredCoords.Clear(); } })); } }
public void Update(float dt) { float sparkLightFade = sparkLightBrightness * dt / sparkLightFadeTime; for (int i = 0; i < activeSparkLights; i++) { PointLight light = this.sparkLights[i]; float a = light.Color.Value.X - sparkLightFade; if (a < 0.0f) { light.Enabled.Value = false; PointLight swap = this.sparkLights[activeSparkLights - 1]; this.sparkLights[i] = swap; this.sparkLights[activeSparkLights - 1] = light; activeSparkLights--; oldestSparkLight = activeSparkLights; } else { light.Color.Value = new Vector3(a); } } for (int i = 0; i < this.BlockQueue.Length; i++) { ScheduledBlock entry = this.BlockQueue[i]; entry.Time -= dt; if (entry.Time < 0.0f) { this.BlockQueue.RemoveAt(i); i--; Entity mapEntity = entry.Voxel.Target; if (mapEntity != null && mapEntity.Active) { Voxel map = mapEntity.Get <Voxel>(); Voxel.Coord c = entry.Coordinate; Voxel.t id = map[c].ID; bool regenerate = false; if (entry.Removing) { if (entry.Generation == 0 && id == 0) { Direction down = map.GetRelativeDirection(Direction.NegativeY); for (int j = 0; j < 6; j++) { Direction dir = DirectionExtensions.Directions[j]; Voxel.Coord adjacent = c.Move(dir); Voxel.t adjacentID = map[adjacent].ID; bool adjacentIsFloater = adjacentID == Voxel.t.Floater; if (dir != down || adjacentIsFloater) { if (adjacentID == Voxel.t.Powered || adjacentID == Voxel.t.Blue || adjacentID == Voxel.t.Neutral || adjacentID == Voxel.t.Infected || adjacentIsFloater) { if (!this.isInQueue(map.Entity, adjacent, true)) { this.BlockQueue.Add(new ScheduledBlock { Voxel = map.Entity, Coordinate = adjacent, Time = propagateDelay, Removing = true, Generation = 1, }); } } } } } else if (entry.Generation > 0 && (id == Voxel.t.Blue || id == Voxel.t.Infected || id == Voxel.t.Powered || id == Voxel.t.PermanentPowered || id == Voxel.t.HardPowered || id == Voxel.t.PoweredSwitch || id == Voxel.t.Neutral || id == Voxel.t.Floater)) { this.generations[new EffectBlock.Entry { Voxel = map, Coordinate = c }] = entry.Generation; map.Empty(c); this.SparksLowPriority(map.GetAbsolutePosition(c), Spark.Burn); regenerate = true; } } else if (id == Voxel.t.Blue) { for (int j = 0; j < 6; j++) { Direction dir = DirectionExtensions.Directions[j]; Voxel.Coord adjacent = c.Move(dir); Voxel.t adjacentID = map[adjacent].ID; if (adjacentID == Voxel.t.Powered || adjacentID == Voxel.t.PermanentPowered || adjacentID == Voxel.t.HardPowered || adjacentID == Voxel.t.PoweredSwitch) { map.Empty(c, false, true, map); map.Fill(c, Voxel.States.Powered); this.SparksLowPriority(map.GetAbsolutePosition(c), Spark.Normal); regenerate = true; } else if (adjacentID == Voxel.t.Neutral && entry.Generation < maxGenerations) { map.Empty(adjacent, false, true, map); this.generations[new EffectBlock.Entry { Voxel = map, Coordinate = adjacent }] = entry.Generation + 1; map.Fill(adjacent, Voxel.States.Blue); this.SparksLowPriority(map.GetAbsolutePosition(adjacent), Spark.Normal); regenerate = true; } } } else if (id == Voxel.t.Neutral) { for (int j = 0; j < 6; j++) { Direction dir = DirectionExtensions.Directions[j]; Voxel.Coord adjacent = c.Move(dir); Voxel.t adjacentID = map[adjacent].ID; if (adjacentID == Voxel.t.Infected || adjacentID == Voxel.t.Blue || adjacentID == Voxel.t.Powered) { map.Empty(adjacent, false, true, map); map.Fill(adjacent, Voxel.States.Neutral); this.SparksLowPriority(map.GetAbsolutePosition(adjacent), Spark.Normal); regenerate = true; } else if (adjacentID == Voxel.t.HardInfected) { map.Empty(adjacent, false, true, map); map.Fill(adjacent, Voxel.States.Hard); this.SparksLowPriority(map.GetAbsolutePosition(adjacent), Spark.Normal); regenerate = true; } } } else if (id == Voxel.t.Hard) { for (int j = 0; j < 6; j++) { Direction dir = DirectionExtensions.Directions[j]; Voxel.Coord adjacent = c.Move(dir); Voxel.t adjacentID = map[adjacent].ID; if (adjacentID == Voxel.t.HardInfected) { map.Empty(adjacent, false, true, map); map.Fill(adjacent, Voxel.States.Hard); this.SparksLowPriority(map.GetAbsolutePosition(adjacent), Spark.Normal); regenerate = true; } } } else if (id == Voxel.t.Powered || id == Voxel.t.PermanentPowered || id == Voxel.t.HardPowered || id == Voxel.t.PoweredSwitch) { for (int j = 0; j < 6; j++) { Direction dir = DirectionExtensions.Directions[j]; Voxel.Coord adjacent = c.Move(dir); Voxel.t adjacentID = map[adjacent].ID; if (id == Voxel.t.Powered && adjacentID == Voxel.t.Neutral && entry.Generation < maxGenerations) { map.Empty(adjacent, false, true, map); this.generations[new EffectBlock.Entry { Voxel = map, Coordinate = adjacent }] = entry.Generation + 1; map.Fill(adjacent, Voxel.States.Powered); this.SparksLowPriority(map.GetAbsolutePosition(adjacent), Spark.Normal); regenerate = true; } else if (adjacentID == Voxel.t.Blue) { map.Empty(adjacent, false, true, map); map.Fill(adjacent, Voxel.States.Powered); this.SparksLowPriority(map.GetAbsolutePosition(adjacent), Spark.Normal); regenerate = true; } else if (adjacentID == Voxel.t.Switch) { map.Empty(adjacent, true, true, map); map.Fill(adjacent, Voxel.States.PoweredSwitch); this.SparksLowPriority(map.GetAbsolutePosition(adjacent), Spark.Normal); regenerate = true; } else if (adjacentID == Voxel.t.Hard) { map.Empty(adjacent, true, true, map); map.Fill(adjacent, Voxel.States.HardPowered); this.SparksLowPriority(map.GetAbsolutePosition(adjacent), Spark.Normal); regenerate = true; } else if (adjacentID == Voxel.t.Critical) { map.Empty(adjacent); regenerate = true; } } } else if (id == Voxel.t.Infected || id == Voxel.t.HardInfected) { for (int j = 0; j < 6; j++) { Direction dir = DirectionExtensions.Directions[j]; Voxel.Coord adjacent = c.Move(dir); Voxel.t adjacentID = map[adjacent].ID; if (adjacentID == Voxel.t.Neutral && entry.Generation < maxGenerations) { map.Empty(adjacent, false, true, map); this.generations[new EffectBlock.Entry { Voxel = map, Coordinate = adjacent }] = entry.Generation + 1; map.Fill(adjacent, Voxel.States.Infected); this.SparksLowPriority(map.GetAbsolutePosition(adjacent), Spark.Dangerous); regenerate = true; } else if (adjacentID == Voxel.t.Hard && entry.Generation < maxGenerations) { map.Empty(adjacent, false, true, map); this.generations[new EffectBlock.Entry { Voxel = map, Coordinate = adjacent }] = entry.Generation + 1; map.Fill(adjacent, Voxel.States.HardInfected); this.SparksLowPriority(map.GetAbsolutePosition(adjacent), Spark.Dangerous); regenerate = true; } else if (adjacentID == Voxel.t.Critical) { map.Empty(adjacent); regenerate = true; } } } if (regenerate) { this.toRegenerate.Add(map); } } } } for (int i = 0; i < this.toRegenerate.Count; i++) { this.toRegenerate[i].Regenerate(); } this.toRegenerate.Clear(); }
public override void Bind(Entity entity, 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), }); ParticleSystem.Add(main, "SnakeSparksRed", 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(1.4f, 0.8f, 0.7f, 1.0f), MaxColor = new Vector4(1.4f, 0.8f, 0.7f, 1.0f), }); ParticleSystem.Add(main, "SnakeSparksYellow", 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(1.4f, 1.4f, 0.7f, 1.0f), MaxColor = new Vector4(1.4f, 1.4f, 0.7f, 1.0f), }); } Snake snake = entity.GetOrCreate <Snake>("Snake"); entity.CannotSuspendByDistance = true; Transform transform = entity.GetOrCreate <Transform>("Transform"); AI ai = entity.GetOrCreate <AI>("AI"); Agent agent = entity.GetOrCreate <Agent>("Agent"); const float defaultSpeed = 5.0f; const float chaseSpeed = 18.0f; const float closeChaseSpeed = 12.0f; const float crushSpeed = 125.0f; VoxelChaseAI chase = entity.GetOrCreate <VoxelChaseAI>("VoxelChaseAI"); chase.Add(new TwoWayBinding <Vector3>(transform.Position, chase.Position)); chase.Speed.Value = defaultSpeed; chase.EnablePathfinding.Value = ai.CurrentState.Value == "Chase"; chase.Filter = delegate(Voxel.State state) { if (state == Voxel.States.Infected || state == Voxel.States.Neutral || state == Voxel.States.Hard || state == Voxel.States.HardInfected) { return(true); } return(false); }; entity.Add(new CommandBinding(chase.Delete, entity.Delete)); PointLight positionLight = null; if (!main.EditorEnabled) { positionLight = new PointLight(); positionLight.Serialize = false; positionLight.Color.Value = new Vector3(1.5f, 0.5f, 0.5f); positionLight.Attenuation.Value = 20.0f; 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)); entity.Add("PositionLight", positionLight); ParticleEmitter emitter = entity.GetOrCreate <ParticleEmitter>("Particles"); emitter.Serialize = false; emitter.ParticlesPerSecond.Value = 100; emitter.Add(new Binding <string>(emitter.ParticleType, delegate(string state) { switch (state) { case "Chase": case "Crush": return("SnakeSparksRed"); case "Alert": return("SnakeSparksYellow"); default: return("SnakeSparks"); } }, ai.CurrentState)); emitter.Add(new Binding <Vector3>(emitter.Position, transform.Position)); emitter.Add(new Binding <bool, string>(emitter.Enabled, x => x != "Suspended", ai.CurrentState)); positionLight.Add(new Binding <Vector3>(positionLight.Position, transform.Position)); emitter.Add(new Binding <Vector3>(emitter.Position, transform.Position)); agent.Add(new Binding <Vector3>(agent.Position, transform.Position)); Sound.AttachTracker(entity); } AI.Task checkMap = new AI.Task { Action = delegate() { if (chase.Voxel.Value.Target == null || !chase.Voxel.Value.Target.Active) { entity.Delete.Execute(); } }, }; AI.Task checkOperationalRadius = new AI.Task { Interval = 2.0f, Action = delegate() { bool shouldBeActive = (transform.Position.Value - main.Camera.Position).Length() < snake.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 = ai.TargetAgent.Value.Target; if (target == null || !target.Active) { ai.TargetAgent.Value = null; ai.CurrentState.Value = "Idle"; } }, }; Func <Voxel, Direction> randomValidDirection = delegate(Voxel m) { Voxel.Coord c = chase.Coord; Direction[] dirs = new Direction[6]; Array.Copy(DirectionExtensions.Directions, dirs, 6); // Shuffle directions int i = 5; while (i > 0) { int k = this.random.Next(i); Direction temp = dirs[i]; dirs[i] = dirs[k]; dirs[k] = temp; i--; } foreach (Direction dir in dirs) { if (chase.Filter(m[c.Move(dir)])) { return(dir); } } return(Direction.None); }; Direction currentDir = Direction.None; chase.Add(new CommandBinding <Voxel, Voxel.Coord>(chase.Moved, delegate(Voxel m, Voxel.Coord c) { if (chase.Active) { string currentState = ai.CurrentState.Value; Voxel.t id = m[c].ID; if (id == Voxel.t.Hard) { m.Empty(c); m.Fill(c, Voxel.States.HardInfected); m.Regenerate(); } else if (id == Voxel.t.Neutral) { m.Empty(c); m.Fill(c, Voxel.States.Infected); m.Regenerate(); } else if (id == Voxel.t.Empty) { m.Fill(c, Voxel.States.Infected); m.Regenerate(); } if (currentState == "Idle") { if (currentDir == Direction.None || !chase.Filter(m[chase.Coord.Value.Move(currentDir)]) || this.random.Next(8) == 0) { currentDir = randomValidDirection(m); } chase.Coord.Value = chase.Coord.Value.Move(currentDir); } else if (snake.Path.Length > 0) { chase.Coord.Value = snake.Path[0]; snake.Path.RemoveAt(0); } } })); Sound.AttachTracker(entity); SoundKiller.Add(entity, AK.EVENTS.STOP_SNAKE); ai.Add(new ChangeBinding <string>(ai.CurrentState, delegate(string old, string value) { if (value == "Suspended" || value == "Alert") { AkSoundEngine.PostEvent(AK.EVENTS.STOP_SNAKE, entity); } else if (old != "Idle" && old != "Chase" && old != "Crush") { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_SNAKE, entity); } })); const float sightDistance = 50.0f; const float hearingDistance = 0.0f; ai.Setup ( new AI.AIState { Name = "Suspended", Tasks = new[] { checkOperationalRadius }, }, new AI.AIState { Name = "Idle", Enter = delegate(AI.AIState previous) { Entity voxelEntity = chase.Voxel.Value.Target; if (voxelEntity != null) { Voxel m = voxelEntity.Get <Voxel>(); if (currentDir == Direction.None || !chase.Filter(m[chase.Coord.Value.Move(currentDir)])) { currentDir = randomValidDirection(m); } chase.Coord.Value = chase.Coord.Value.Move(currentDir); } }, Tasks = new[] { checkMap, checkOperationalRadius, new AI.Task { Interval = 1.0f, Action = delegate() { Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player"); if (a != null) { ai.CurrentState.Value = "Alert"; } }, }, }, }, new AI.AIState { Name = "Alert", Enter = delegate(AI.AIState previous) { chase.EnableMovement.Value = false; }, Exit = delegate(AI.AIState next) { chase.EnableMovement.Value = true; }, Tasks = new[] { checkMap, checkOperationalRadius, new AI.Task { Interval = 0.4f, Action = delegate() { if (ai.TimeInCurrentState > 3.0f) { ai.CurrentState.Value = "Idle"; } else { Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player"); if (a != null) { ai.TargetAgent.Value = a.Entity; ai.CurrentState.Value = "Chase"; } } }, }, }, }, new AI.AIState { Name = "Chase", Enter = delegate(AI.AIState previousState) { chase.EnablePathfinding.Value = true; chase.Speed.Value = chaseSpeed; }, Exit = delegate(AI.AIState nextState) { chase.EnablePathfinding.Value = false; chase.Speed.Value = defaultSpeed; }, Tasks = new[] { checkMap, checkOperationalRadius, checkTargetAgent, new AI.Task { Interval = 0.07f, Action = delegate() { Vector3 targetPosition = ai.TargetAgent.Value.Target.Get <Agent>().Position; float targetDistance = (targetPosition - transform.Position).Length(); chase.Speed.Value = targetDistance < 15.0f ? closeChaseSpeed : chaseSpeed; if (targetDistance > 50.0f || ai.TimeInCurrentState > 30.0f) // He got away { ai.CurrentState.Value = "Alert"; } else if (targetDistance < 4.0f) // We got 'im { // First, make sure we're not near a reset block Voxel v = chase.Voxel.Value.Target.Get <Voxel>(); if (VoxelAStar.BroadphaseSearch(v, chase.Coord, 6, x => x.Type == Lemma.Components.Voxel.States.Reset) == null) { ai.CurrentState.Value = "Crush"; } } else { chase.Target.Value = targetPosition; } }, }, }, }, new AI.AIState { Name = "Crush", Enter = delegate(AI.AIState lastState) { // Set up cage Voxel.Coord center = chase.Voxel.Value.Target.Get <Voxel>().GetCoordinate(ai.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++) { snake.Path.Add(new Voxel.Coord { 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++) { snake.Path.Add(new Voxel.Coord { X = center.X - radius, Y = y, Z = z }); } // Right for (int z = center.Z - radius; z <= center.Z + radius; z++) { snake.Path.Add(new Voxel.Coord { X = center.X + radius, Y = y, Z = z }); } // Backward for (int x = center.X - radius; x <= center.X + radius; x++) { snake.Path.Add(new Voxel.Coord { X = x, Y = y, Z = center.Z - radius }); } // Forward for (int x = center.X - radius; x <= center.X + radius; x++) { snake.Path.Add(new Voxel.Coord { 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++) { snake.Path.Add(new Voxel.Coord { X = x, Y = center.Y + 3, Z = z }); } } chase.EnablePathfinding.Value = false; chase.Speed.Value = crushSpeed; snake.CrushCoordinate.Value = chase.Coord; }, Exit = delegate(AI.AIState nextState) { chase.Speed.Value = defaultSpeed; chase.Coord.Value = chase.LastCoord.Value = snake.CrushCoordinate; snake.Path.Clear(); }, Tasks = new[] { checkMap, checkOperationalRadius, checkTargetAgent, new AI.Task { Interval = 0.01f, Action = delegate() { Agent a = ai.TargetAgent.Value.Target.Get <Agent>(); a.Damage.Execute(0.01f / 1.5f); // seconds to kill if (!a.Active) { ai.CurrentState.Value = "Alert"; } else { if ((a.Position - transform.Position.Value).Length() > 5.0f) // They're getting away { ai.CurrentState.Value = "Chase"; } } } } }, } ); this.SetMain(entity, main); entity.Add("OperationalRadius", snake.OperationalRadius); }
public void Update(float dt) { if (this.TargetVoxel.Target == null || !this.TargetVoxel.Target.Active) { this.Delete.Execute(); return; } this.Lifetime += dt; if (this.Lifetime < this.Delay) { return; } float blend = (this.Lifetime - this.Delay) / this.TotalLifetime; Voxel m = this.TargetVoxel.Target.Get <Voxel>(); Matrix finalOrientation = m.Transform; finalOrientation.Translation = Vector3.Zero; Quaternion finalQuat = Quaternion.CreateFromRotationMatrix(finalOrientation); Vector3 finalPosition = m.GetAbsolutePosition(this.Coord); if (blend > 1.0f) { if (this.StateId != Voxel.t.Empty) { Voxel.Coord c = this.Coord; bool blue = this.StateId == Voxel.t.Blue; bool foundAdjacentCell = false; bool foundConflict = false; if (this.CheckAdjacent) { foreach (Direction dir in DirectionExtensions.Directions) { Voxel.Coord adjacent = c.Move(dir); Voxel.t adjacentID = m[adjacent].ID; if (adjacentID != Voxel.t.Empty) { if (blue && (adjacentID == Voxel.t.Infected || adjacentID == Voxel.t.HardInfected || adjacentID == Voxel.t.Slider || adjacentID == Voxel.t.SliderPowered || adjacentID == Voxel.t.SocketWhite || adjacentID == Voxel.t.SocketBlue || adjacentID == Voxel.t.SocketYellow)) { foundConflict = true; } else { foundAdjacentCell = true; if (blue) { if (adjacentID == Voxel.t.Reset) { this.StateId = Voxel.t.Neutral; break; } else if (adjacentID == Voxel.t.Powered || adjacentID == Voxel.t.PermanentPowered || adjacentID == Voxel.t.PoweredSwitch || adjacentID == Voxel.t.HardPowered) { this.StateId = Voxel.t.Powered; break; } } else { break; } } } } } else { foundAdjacentCell = true; } if (foundAdjacentCell) { Vector3 absolutePos = m.GetAbsolutePosition(c); if (blue && !Zone.CanBuild(absolutePos)) { foundConflict = true; } if (!foundConflict) { bool isDynamic = m.GetType() == typeof(DynamicVoxel); foreach (Voxel m2 in Voxel.ActivePhysicsVoxels) { bool atLeastOneDynamic = isDynamic || m2.GetType() == typeof(DynamicVoxel); if (m2 != m && atLeastOneDynamic && m2[absolutePos].ID != 0) { foundConflict = true; break; } } } if (!foundConflict) { Voxel.State state = m[this.Coord]; if (state.Permanent || state.Hard || state.ID == this.StateId || (blue && state == Voxel.States.Powered)) { foundConflict = true; } else { if (state.ID != 0) { m.Empty(this.Coord); } m.Fill(this.Coord, Voxel.States.All[this.StateId]); m.Regenerate(); if (EffectBlock.random.Next(0, 4) == 0) { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_BLOCK_BUILD, this.Entity); } this.Entity.Delete.Execute(); return; } } } // For one reason or another, we can't fill the cell // Animate nicely into oblivion this.StateId = Voxel.t.Empty; } else { // For one reason or another, we can't fill the cell // Animate nicely into oblivion if (blend > 2.0f) { this.Delete.Execute(); } else { Matrix result = Matrix.CreateFromQuaternion(finalQuat); float scale = 2.0f - blend; result.Right *= scale; result.Up *= scale; result.Forward *= scale; result.Translation = finalPosition; this.Transform.Value = result; } } } else { float scale; if (this.DoScale) { scale = blend; } else { scale = 1.0f; } float distance = (finalPosition - this.StartPosition).Length() * 0.1f * Math.Max(0.0f, 0.5f - Math.Abs(blend - 0.5f)); Matrix result = Matrix.CreateFromQuaternion(Quaternion.Lerp(this.StartOrientation, finalQuat, blend)); result.Right *= scale; result.Up *= scale; result.Forward *= scale; result.Translation = Vector3.Lerp(this.StartPosition, finalPosition, blend) + new Vector3((float)Math.Sin(blend * Math.PI) * distance); this.Transform.Value = result; } }
public static bool DefaultVoxelFilter(Voxel.t x) { return(x != Components.Voxel.t.AvoidAI); }
public override void Awake() { base.Awake(); this.EnabledWhenPaused = false; this.Serialize = false; this.Footstep.Action = delegate() { if (this.SoundEnabled && this.main.TotalTime - this.lastFootstepSound > footstepSoundInterval) { AkSoundEngine.PostEvent(AK.EVENTS.FOOTSTEP_PLAY, this.Entity); this.lastFootstepSound = this.main.TotalTime; } }; this.Add(new CommandBinding <Voxel, Voxel.Coord, Direction>(this.WalkedOn, delegate(Voxel map, Voxel.Coord coord, Direction dir) { Voxel.State state = map[coord]; if (state != Voxel.States.Empty) { AkSoundEngine.SetSwitch(AK.SWITCHES.FOOTSTEP_MATERIAL.GROUP, state.FootstepSwitch, this.Entity); if (this.WallRunState.Value == WallRun.State.None) { if (map.GetAbsoluteDirection(dir) == Direction.NegativeY && !this.IsSwimming) { this.walkedOnCount++; if (this.walkedOnCount >= 2) { // Every few tiles, save off the location for the auto-respawn system coord.Data = null; this.RespawnLocations.Add(new RespawnLocation { Coordinate = coord, Map = map.Entity, Rotation = this.Rotation, OriginalPosition = map.GetAbsolutePosition(coord), }); while (this.RespawnLocations.Length > Spawner.RespawnMemoryLength) { this.RespawnLocations.RemoveAt(0); } this.walkedOnCount = 0; } } } } Voxel.t id = state.ID; if (id == Voxel.t.Neutral) { map.Empty(coord, false, true, map); bool isPowered = false; for (int i = 0; i < 6; i++) { Voxel.Coord adjacentCoord = coord.Move(DirectionExtensions.Directions[i]); Voxel.t adjacentId = map[coord].ID; if (adjacentId == Voxel.t.Powered || adjacentId == Voxel.t.PermanentPowered || adjacentId == Voxel.t.PoweredSwitch || adjacentId == Voxel.t.HardPowered) { isPowered = true; break; } } map.Fill(coord, isPowered ? Voxel.States.Powered : Voxel.States.Blue); map.Regenerate(); WorldFactory.Instance.Get <Propagator>().Sparks(map.GetAbsolutePosition(coord), Propagator.Spark.Normal); } else if (id == Voxel.t.Reset) { bool regenerate = false; Queue <Voxel.Coord> queue = new Queue <Voxel.Coord>(); queue.Enqueue(coord); Voxel.CoordSetCache.Add(coord); while (queue.Count > 0) { Voxel.Coord c = queue.Dequeue(); for (int i = 0; i < 6; i++) { Voxel.Coord adjacentCoord = c.Move(DirectionExtensions.Directions[i]); if (!Voxel.CoordSetCache.Contains(adjacentCoord)) { Voxel.CoordSetCache.Add(adjacentCoord); Voxel.t adjacentID = map[adjacentCoord].ID; if (adjacentID == Voxel.t.Reset || adjacentID == Voxel.t.Hard) { queue.Enqueue(adjacentCoord); } else if (adjacentID == Voxel.t.Infected || adjacentID == Voxel.t.Blue || adjacentID == Voxel.t.Powered) { map.Empty(adjacentCoord, false, true, map); map.Fill(adjacentCoord, Voxel.States.Neutral); regenerate = true; } else if (adjacentID == Voxel.t.HardPowered || adjacentID == Voxel.t.HardInfected) { map.Empty(adjacentCoord, false, true, map); map.Fill(adjacentCoord, Voxel.States.Hard); regenerate = true; } } } } Voxel.CoordSetCache.Clear(); if (regenerate) { map.Regenerate(); } } // Lava. Damage the player character if it steps on lava. bool isInfected = id == Voxel.t.Infected || id == Voxel.t.HardInfected; if (isInfected) { this.Damage.Execute(0.2f); } else if (id == Voxel.t.Floater) { // Floater. Delete the block after a delay. Vector3 pos = map.GetAbsolutePosition(coord); ParticleEmitter.Emit(main, "Smoke", pos, 1.0f, 10); Sound.PostEvent(AK.EVENTS.PLAY_CRUMBLE, pos); WorldFactory.Instance.Add(new Animation ( new Animation.Delay(0.5f), new Animation.Execute(delegate() { if (map[coord].ID == Voxel.t.Floater) { map.Empty(coord); map.Regenerate(); } }) )); } this.infectedDamage = isInfected; })); }