private IEnumerable <Voxel.Coord> spreadFromCenter(Voxel.Coord center, Direction dir) { for (Voxel.Coord z = center.Move(dir, -1); z.GetComponent(dir) > center.GetComponent(dir) - 3; z = z.Move(dir.GetReverse())) { yield return(z); } for (Voxel.Coord z = center.Clone(); z.GetComponent(dir) < center.GetComponent(dir) + 3; z = z.Move(dir)) { yield return(z); } }
public void BuildFloor(Voxel floorMap, Voxel.Coord floorCoordinate, Direction forwardDir, Direction rightDir) { List <EffectBlockFactory.BlockBuildOrder> buildCoords = new List <EffectBlockFactory.BlockBuildOrder>(); Voxel.Coord newFloorCoordinate = floorMap.GetCoordinate(this.Position); floorCoordinate.SetComponent(rightDir, newFloorCoordinate.GetComponent(rightDir)); floorCoordinate.SetComponent(forwardDir, newFloorCoordinate.GetComponent(forwardDir)); Direction upDir = floorMap.GetRelativeDirection(Direction.PositiveY); const int radius = 3; foreach (Voxel.Coord x in this.spreadFromCenter(floorCoordinate, rightDir)) { if (floorMap[x.Move(upDir)].Hard) { break; } int dx = x.GetComponent(rightDir) - floorCoordinate.GetComponent(rightDir); for (Voxel.Coord y = x.Move(forwardDir, -radius); y.GetComponent(forwardDir) < floorCoordinate.GetComponent(forwardDir) + radius; y = y.Move(forwardDir)) { if (floorMap[y.Move(upDir)].Hard) { break; } int dy = y.GetComponent(forwardDir) - floorCoordinate.GetComponent(forwardDir); if ((float)Math.Sqrt(dx * dx + dy * dy) < radius && floorMap[y].ID == 0) { buildCoords.Add(new EffectBlockFactory.BlockBuildOrder { Voxel = floorMap, Coordinate = y, State = Voxel.States.Blue, }); } } } Factory.Get <EffectBlockFactory>().Build(this.main, buildCoords, this.Position); }
public void Update(float dt) { State wallRunState = this.CurrentState; if (wallRunState != State.None) { this.Vault.Execute(); // Try to vault up if (this.CurrentState.Value == State.None) // We vaulted { return; } if (!this.WallRunVoxel.Value.Active || this.IsSupported) { this.Deactivate(); return; } Voxel voxel = this.WallRunVoxel.Value; if (voxel == null || !voxel.Active) { this.Deactivate(); return; } Vector3 wallRunVector = voxel.GetAbsoluteVector(this.WallRunDirection.Value.GetVector()); Vector3 baseVelocity = voxel.LinearVelocity + Vector3.Cross(voxel.AngularVelocity, this.Position - voxel.Transform.Value.Translation); float wallRunSpeed = Vector3.Dot(this.LinearVelocity.Value - baseVelocity, wallRunVector); Vector3 pos = this.Position + new Vector3(0, this.Height * -0.5f, 0); if (wallRunState == State.Straight) { if (wallRunSpeed < 0.0f) { // Start sliding down this.CurrentState.Value = wallRunState = State.Down; AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_SLIDE_LOOP, this.Entity); } } else if (wallRunState == State.Left || wallRunState == State.Right) { if (this.IsSupported || wallRunSpeed < minWallRunSpeed) { // We landed on the ground or we're going too slow to continue wall-running this.Deactivate(); return; } else { // Check if we should switch to another wall Vector3 wallVector = voxel.GetAbsoluteVector(this.WallDirection.Value.GetVector()); Voxel.GlobalRaycastResult result = Voxel.GlobalRaycast(pos, wallRunVector + wallVector, 2.0f); if (result.Voxel != null && result.Voxel != voxel) { float dot = Vector3.Dot(result.Voxel.GetAbsoluteVector(result.Normal.GetReverse().GetVector()), wallVector); if (dot > 0.7f) { Matrix matrix = Matrix.CreateRotationY(this.Rotation); Vector3 forwardVector = -matrix.Forward; this.setup(result.Voxel, result.Normal.GetReverse(), wallRunState, forwardVector, false, true); } } } } Voxel.Coord coord = voxel.GetCoordinate(pos); Voxel.Coord wallCoord = coord.Move(this.WallDirection, 2); Voxel.State wallType = voxel[wallCoord]; if (!wallCoord.Equivalent(this.lastWallRunCoord)) { this.lastWallRunCoord = wallCoord; this.WalkedOn.Execute(voxel, wallCoord, this.WallDirection); } if (this.EnableEnhancedWallRun && (wallRunState == State.Left || wallRunState == State.Right) && Zone.CanBuild(this.Position) && voxel.Entity.Type != "Bouncer") { Direction up = voxel.GetRelativeDirection(Direction.PositiveY); if (up.IsPerpendicular(this.WallDirection)) { Direction right = this.WallDirection.Value.Cross(up); List <EffectBlockFactory.BlockBuildOrder> buildCoords = new List <EffectBlockFactory.BlockBuildOrder>(); const int radius = 5; int upwardRadius = wallRunState == State.Down ? 0 : radius; for (Voxel.Coord x = wallCoord.Move(right, -radius); x.GetComponent(right) < wallCoord.GetComponent(right) + radius; x = x.Move(right)) { int dx = x.GetComponent(right) - wallCoord.GetComponent(right); for (Voxel.Coord y = x.Move(up, -radius); y.GetComponent(up) < wallCoord.GetComponent(up) + upwardRadius; y = y.Move(up)) { int dy = y.GetComponent(up) - wallCoord.GetComponent(up); if ((float)Math.Sqrt(dx * dx + dy * dy) < radius && voxel[y].ID == 0) { buildCoords.Add(new EffectBlockFactory.BlockBuildOrder { Voxel = voxel, Coordinate = y, State = Voxel.States.Blue, }); } } } Factory.Get <EffectBlockFactory>().Build(main, buildCoords, this.Position); } else { this.Deactivate(); return; } } else if (wallType.ID == 0 && wallInstantiationTimer == 0.0f) // We ran out of wall to walk on { this.Deactivate(); return; } wallInstantiationTimer = Math.Max(0.0f, wallInstantiationTimer - dt); Vector3 coordPos = voxel.GetAbsolutePosition(coord); Vector3 normal = voxel.GetAbsoluteVector(this.WallDirection.Value.GetVector()); // Equation of a plane // normal (dot) point = d float d = Vector3.Dot(normal, coordPos) + (wallRunState == State.Down ? 0.3f : 0.4f); // Distance along the normal to keep the player glued to the wall float snapDistance = d - Vector3.Dot(pos, normal); this.Position.Value += normal * snapDistance; Vector3 velocity = this.LinearVelocity; // Also fix the velocity so we don't jitter away from the wall velocity -= Vector3.Dot(velocity, normal) * normal; // Slow our descent velocity += new Vector3(0, (wallRunState == State.Straight ? 3.0f : 10.0f) * dt, 0); this.LinearVelocity.Value = velocity; } }
public static void Consolidate(Main main, DynamicVoxel voxel, Voxel targetVoxel, Voxel.Coord targetCoord, float interval = 1.0f) { if (targetVoxel != null) { // Combine this map with the other one Direction x = targetVoxel.GetRelativeDirection(voxel.GetAbsoluteVector(Vector3.Right)); Direction y = targetVoxel.GetRelativeDirection(voxel.GetAbsoluteVector(Vector3.Up)); Direction z = targetVoxel.GetRelativeDirection(voxel.GetAbsoluteVector(Vector3.Backward)); if (x.IsParallel(y)) { x = y.Cross(z); } else if (y.IsParallel(z)) { y = x.Cross(z); } Voxel.Coord offset = new Voxel.Coord(); float closestCoordDistance = float.MaxValue; Vector3 closestCoordPosition = targetVoxel.GetAbsolutePosition(targetCoord); foreach (Voxel.Coord c in voxel.Chunks.SelectMany(c => c.Boxes).SelectMany(b => b.GetCoords())) { float distance = (voxel.GetAbsolutePosition(c) - closestCoordPosition).LengthSquared(); if (distance < closestCoordDistance) { closestCoordDistance = distance; offset = c; } } Vector3 toLevitatingMap = voxel.Transform.Value.Translation - targetVoxel.GetAbsolutePosition(targetCoord); offset = offset.Move(voxel.GetRelativeDirection(-toLevitatingMap)); Quaternion orientation = Quaternion.CreateFromRotationMatrix(voxel.Transform.Value); EffectBlockFactory blockFactory = Factory.Get <EffectBlockFactory>(); int index = 0; List <Voxel.Coord> coords = voxel.Chunks.SelectMany(c => c.Boxes).SelectMany(b => b.GetCoords()).ToList(); Voxel.Coord camera = voxel.GetCoordinate(main.Camera.Position); foreach (Voxel.Coord c in coords.OrderBy(c2 => new Vector3(c2.X - camera.X, c2.Y - camera.Y, c2.Z - camera.Z).LengthSquared())) { Voxel.Coord offsetFromCenter = c.Move(-offset.X, -offset.Y, -offset.Z); Voxel.Coord targetCoord2 = new Voxel.Coord(); targetCoord2.SetComponent(x, offsetFromCenter.GetComponent(Direction.PositiveX)); targetCoord2.SetComponent(y, offsetFromCenter.GetComponent(Direction.PositiveY)); targetCoord2.SetComponent(z, offsetFromCenter.GetComponent(Direction.PositiveZ)); targetCoord2 = targetCoord2.Move(targetCoord.X, targetCoord.Y, targetCoord.Z); if (targetVoxel[targetCoord2].ID == 0) { Entity blockEntity = blockFactory.CreateAndBind(main); c.Data.ApplyToEffectBlock(blockEntity.Get <ModelInstance>()); EffectBlock effectBlock = blockEntity.Get <EffectBlock>(); effectBlock.Offset.Value = targetVoxel.GetRelativePosition(targetCoord2); effectBlock.DoScale = false; effectBlock.StartPosition = voxel.GetAbsolutePosition(c); effectBlock.StartOrientation = orientation; effectBlock.TotalLifetime = (0.05f + (index * 0.0075f)) * interval; effectBlock.Setup(targetVoxel.Entity, targetCoord2, c.Data.ID); main.Add(blockEntity); index++; } } // Delete the map voxel.Entity.Delete.Execute(); } }
public bool BreakWalls(Vector3 forward, Vector3 right) { BlockFactory blockFactory = Factory.Get <BlockFactory>(); Vector3 basePos = this.Position + new Vector3(0, 0.2f + (this.Height * -0.5f) - this.SupportHeight, 0) + forward * -1.0f; bool broke = false; foreach (Voxel map in Voxel.ActivePhysicsVoxels.ToList()) { List <Voxel.Coord> removals = new List <Voxel.Coord>(); Quaternion mapQuaternion = Quaternion.CreateFromRotationMatrix(map.Transform); Voxel.Coord top = map.GetCoordinate(basePos + new Vector3(0, this.Height + this.SupportHeight + 0.5f, 0)); Direction upDir = map.GetRelativeDirection(Vector3.Up); Direction rightDir = map.GetRelativeDirection(right); Direction forwardDir = map.GetRelativeDirection(forward); Voxel.Coord center = map.GetCoordinate(basePos); for (Voxel.Coord y = center.Clone(); y.GetComponent(upDir) <= top.GetComponent(upDir); y = y.Move(upDir)) { int minZ = center.GetComponent(rightDir) - 10; int maxZ = minZ + 20; foreach (Voxel.Coord x in this.spreadFromCenter(y, rightDir)) { Voxel.Coord z = x.Clone(); for (int i = 0; i < 4; i++) { Voxel.State state = map[z]; int zRightDimension = z.GetComponent(rightDir); if (zRightDimension > minZ && zRightDimension < maxZ && state.ID != 0 && !removals.Contains(z)) { if (state.Permanent || state.Hard) { if (zRightDimension >= center.GetComponent(rightDir)) { maxZ = zRightDimension; } else { minZ = zRightDimension; } break; } else { broke = true; removals.Add(z); Vector3 cellPos = map.GetAbsolutePosition(z); Vector3 toCell = cellPos - basePos; Entity block = blockFactory.CreateAndBind(this.main); Transform blockTransform = block.Get <Transform>(); blockTransform.Position.Value = cellPos; blockTransform.Quaternion.Value = mapQuaternion; state.ApplyToBlock(block); toCell += forward * 4.0f; toCell.Normalize(); PhysicsBlock physicsBlock = block.Get <PhysicsBlock>(); physicsBlock.LinearVelocity.Value = toCell * 15.0f; physicsBlock.AngularVelocity.Value = new Vector3(((float)this.random.NextDouble() - 0.5f) * 2.0f, ((float)this.random.NextDouble() - 0.5f) * 2.0f, ((float)this.random.NextDouble() - 0.5f) * 2.0f); main.Add(block); } } z = z.Move(forwardDir); } } } if (removals.Count > 0) { map.Empty(removals); map.Regenerate(); } } return(broke); }
public override void Bind(Entity entity, Main main, bool creating = false) { PointLight light = entity.GetOrCreate <PointLight>("PointLight"); light.Serialize = false; const float defaultLightAttenuation = 15.0f; light.Attenuation.Value = defaultLightAttenuation; Transform transform = entity.GetOrCreate <Transform>("Transform"); light.Add(new Binding <Vector3>(light.Position, transform.Position)); if (!main.EditorEnabled) { Sound.AttachTracker(entity); SoundKiller.Add(entity, AK.EVENTS.STOP_GLOWSQUARE); entity.Add(new PostInitialization(delegate() { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_GLOWSQUARE, entity); AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, -1.0f, entity); })); } AI ai = entity.GetOrCreate <AI>("AI"); ModelAlpha model = entity.GetOrCreate <ModelAlpha>(); model.Add(new Binding <Matrix>(model.Transform, transform.Matrix)); model.Filename.Value = "AlphaModels\\box"; model.Serialize = false; model.DrawOrder.Value = 15; const float defaultModelScale = 1.0f; 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)); default: return(new Vector3(1.0f, 1.0f, 1.0f)); } }, ai.CurrentState)); entity.Add(new Updater ( delegate(float dt) { float source = 1.0f + ((float)this.random.NextDouble() - 0.5f) * 2.0f * 0.05f; model.Scale.Value = new Vector3(defaultModelScale * source); light.Attenuation.Value = defaultLightAttenuation * source; } )); model.Add(new Binding <bool, string>(model.Enabled, x => x != "Exploding", ai.CurrentState)); light.Add(new Binding <Vector3>(light.Color, model.Color)); Agent agent = entity.GetOrCreate <Agent>(); agent.Add(new Binding <Vector3>(agent.Position, transform.Position)); RaycastAIMovement movement = entity.GetOrCreate <RaycastAIMovement>("Movement"); Exploder exploder = entity.GetOrCreate <Exploder>("Exploder"); AI.Task checkOperationalRadius = new AI.Task { Interval = 2.0f, Action = delegate() { bool shouldBeActive = (transform.Position.Value - main.Camera.Position).Length() < movement.OperationalRadius; if (shouldBeActive && ai.CurrentState == "Suspended") { ai.CurrentState.Value = "Idle"; } else if (!shouldBeActive && ai.CurrentState != "Suspended") { ai.CurrentState.Value = "Suspended"; } }, }; RaycastAI raycastAI = entity.GetOrCreate <RaycastAI>("RaycastAI"); raycastAI.Add(new TwoWayBinding <Vector3>(transform.Position, raycastAI.Position)); raycastAI.Add(new Binding <Quaternion>(transform.Quaternion, raycastAI.Orientation)); AI.Task updatePosition = new AI.Task { Action = delegate() { raycastAI.Update(); }, }; ai.Add(new AI.AIState { Name = "Suspended", Tasks = new[] { checkOperationalRadius, }, }); const float sightDistance = 40.0f; const float hearingDistance = 0.0f; ai.Add(new AI.AIState { Name = "Idle", Enter = delegate(AI.AIState previous) { AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, -1.0f, entity); }, Tasks = new[] { checkOperationalRadius, updatePosition, new AI.Task { Interval = 1.0f, Action = delegate() { raycastAI.Move(new Vector3(((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f)); } }, new AI.Task { Interval = 0.5f, Action = delegate() { Agent a = Agent.Query(transform.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player"); if (a != null) { ai.CurrentState.Value = "Alert"; } }, }, }, }); ai.Add(new AI.AIState { Name = "Alert", Enter = delegate(AI.AIState previous) { AkSoundEngine.PostEvent(AK.EVENTS.STOP_GLOWSQUARE, entity); }, Exit = delegate(AI.AIState next) { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_GLOWSQUARE, entity); }, Tasks = new[] { checkOperationalRadius, updatePosition, new AI.Task { Interval = 1.0f, 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"; } } }, }, }, }); 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"; } }, }; ai.Add(new AI.AIState { Name = "Chase", Enter = delegate(AI.AIState previous) { AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, 0.0f, entity); }, Tasks = new[] { checkOperationalRadius, checkTargetAgent, new AI.Task { Interval = 0.35f, Action = delegate() { raycastAI.Move(ai.TargetAgent.Value.Target.Get <Transform>().Position.Value - transform.Position); } }, new AI.Task { Action = delegate() { if ((ai.TargetAgent.Value.Target.Get <Transform>().Position.Value - transform.Position).Length() < 10.0f) { ai.CurrentState.Value = "Explode"; } } }, updatePosition, }, }); EffectBlockFactory factory = Factory.Get <EffectBlockFactory>(); ai.Add(new AI.AIState { Name = "Explode", Enter = delegate(AI.AIState previous) { exploder.CoordQueue.Clear(); Entity voxelEntity = raycastAI.Voxel.Value.Target; if (voxelEntity == null || !voxelEntity.Active) { ai.CurrentState.Value = "Alert"; return; } Voxel m = voxelEntity.Get <Voxel>(); Voxel.Coord c = raycastAI.Coord.Value; Direction toSupport = Direction.None; foreach (Direction dir in DirectionExtensions.Directions) { if (m[raycastAI.Coord.Value.Move(dir)].ID != 0) { toSupport = dir; break; } } if (toSupport == Direction.None) { ai.CurrentState.Value = "Alert"; return; } Direction up = toSupport.GetReverse(); exploder.ExplosionOriginalCoord.Value = raycastAI.Coord; Direction right; if (up.IsParallel(Direction.PositiveX)) { right = Direction.PositiveZ; } else { right = Direction.PositiveX; } Direction forward = up.Cross(right); for (Voxel.Coord y = c.Clone(); y.GetComponent(up) < c.GetComponent(up) + 3; y = y.Move(up)) { for (Voxel.Coord x = y.Clone(); x.GetComponent(right) < c.GetComponent(right) + 2; x = x.Move(right)) { for (Voxel.Coord z = x.Clone(); z.GetComponent(forward) < c.GetComponent(forward) + 2; z = z.Move(forward)) { exploder.CoordQueue.Add(z); } } } }, Exit = delegate(AI.AIState next) { exploder.CoordQueue.Clear(); }, Tasks = new[] { checkOperationalRadius, new AI.Task { Interval = 0.15f, Action = delegate() { if (exploder.CoordQueue.Length > 0) { raycastAI.MoveTo(exploder.CoordQueue[0]); exploder.CoordQueue.RemoveAt(0); Entity blockEntity = factory.CreateAndBind(main); Voxel.States.Infected.ApplyToEffectBlock(blockEntity.Get <ModelInstance>()); Entity mapEntity = raycastAI.Voxel.Value.Target; if (mapEntity != null && mapEntity.Active) { EffectBlock effectBlock = blockEntity.Get <EffectBlock>(); Voxel m = mapEntity.Get <Voxel>(); effectBlock.Offset.Value = m.GetRelativePosition(raycastAI.Coord); Vector3 absolutePos = m.GetAbsolutePosition(raycastAI.Coord); effectBlock.StartPosition = absolutePos + new Vector3(0.05f, 0.1f, 0.05f); effectBlock.StartOrientation = Quaternion.CreateFromYawPitchRoll(0.15f, 0.15f, 0); effectBlock.TotalLifetime = 0.05f; effectBlock.Setup(raycastAI.Voxel.Value.Target, raycastAI.Coord, Voxel.t.Infected); main.Add(blockEntity); } } } }, new AI.Task { Action = delegate() { AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.SFX_GLOWSQUARE_PITCH, MathHelper.Lerp(0.0f, 1.0f, ai.TimeInCurrentState.Value / 2.0f), entity); if (exploder.CoordQueue.Length == 0) { // Explode ai.CurrentState.Value = "Exploding"; } }, }, updatePosition, }, }); ai.Add(new AI.AIState { Name = "Exploding", Enter = delegate(AI.AIState previous) { exploder.Exploded.Value = false; AkSoundEngine.PostEvent(AK.EVENTS.STOP_GLOWSQUARE, entity); }, Exit = delegate(AI.AIState next) { exploder.Exploded.Value = false; AkSoundEngine.PostEvent(AK.EVENTS.PLAY_GLOWSQUARE, entity); }, Tasks = new[] { new AI.Task { Interval = 0.1f, Action = delegate() { const int radius = 9; float timeInCurrentState = ai.TimeInCurrentState; if (timeInCurrentState > 1.0f && !exploder.Exploded) { Entity mapEntity = raycastAI.Voxel.Value.Target; if (mapEntity != null && mapEntity.Active) { Explosion.Explode(main, mapEntity.Get <Voxel>(), raycastAI.Coord, radius, 18.0f); } exploder.Exploded.Value = true; } if (timeInCurrentState > 2.0f) { raycastAI.Move(new Vector3(((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f, ((float)this.random.NextDouble() * 2.0f) - 1.0f)); ai.CurrentState.Value = "Alert"; } }, }, updatePosition, }, }); this.SetMain(entity, main); entity.Add("OperationalRadius", movement.OperationalRadius); }