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 static bool canConnect(Voxel.State state) { return(state == Voxel.States.Powered || state == Voxel.States.HardPowered || state == Voxel.States.PoweredSwitch || state == Voxel.States.Blue || state == Voxel.States.Neutral || state == Voxel.States.Switch || state == Voxel.States.Hard); }
public override Voxel.State Apply(int x, int y, Voxel.State voxel) { x -= centerX; y -= centerY; if (x * x + y * y <= sqrRadius) { return(fillType); } return(voxel); }
private bool canBuild(Voxel.State s) { return(s != Voxel.States.Blue && s != Voxel.States.Powered && s != Voxel.States.Infected && s != Voxel.States.HardInfected && s != Voxel.States.SliderPowered && s != Voxel.States.Slider && s != Voxel.States.SocketBlue && s != Voxel.States.SocketWhite && s != Voxel.States.SocketYellow); }
public void Implode(Main main, Voxel v, Voxel.Coord coord, Voxel.State state, Vector3 target) { Entity block = this.CreateAndBind(main); ImplodeBlock implodeBlock = block.Get <ImplodeBlock>(); state.ApplyToEffectBlock(block.Get <ModelInstance>()); implodeBlock.Offset.Value = v.GetRelativePosition(coord); implodeBlock.StateId = state.ID; implodeBlock.StartPosition = v.GetAbsolutePosition(coord); implodeBlock.Type = Rift.Style.In; implodeBlock.StartOrientation = Quaternion.CreateFromRotationMatrix(v.Transform); implodeBlock.EndOrientation = Quaternion.CreateFromYawPitchRoll((float)this.random.NextDouble() * (float)Math.PI * 2.0f, (float)this.random.NextDouble() * (float)Math.PI * 2.0f, 0.0f); implodeBlock.EndPosition = target; main.Add(block); }
private void set() { Entity voxelEntity = this.AttachedVoxel.Value.Target; if (voxelEntity == null) { return; } Voxel map = voxelEntity.Get <Voxel>(); if (map == null) { return; } Voxel.State state = Voxel.States.All[this.State]; if (this.Contiguous) { lock (map.MutationLock) { Voxel.Box b = map.GetBox(this.Coord); if (b != null && b.Type != state) { List <Voxel.Coord> coords = map.GetContiguousByType(new[] { b }).SelectMany(x => x.GetCoords()).Select(x => x.WithData(state)).ToList(); map.Empty(coords, true, true, map); map.Fill(coords, true, map); map.Regenerate(); } } } else { lock (map.MutationLock) { if (map[this.Coord] != state) { map.Empty(this.Coord, true, true, map); map.Fill(this.Coord, state, true, map); map.Regenerate(); } } } this.OnSet.Execute(); }
private bool determineShouldBuildFloor(Voxel v, Voxel.State floorState) { bool result = false; if (floorState == Voxel.States.Blue || floorState == Voxel.States.Powered) { // If we're standing on blue or powered, we need to check if we're close to a non-blue block before we can build a floor // This prevents the player from building a floor infinitely if (VoxelAStar.BroadphaseSearch(this.floorMap, this.floorCoordinate, 6, x => x.Type != Voxel.States.Blue && x.Type != Voxel.States.Powered) != null) { result = true; } } else if (v == null || v.Entity.Type != "Bouncer") { result = true; } return(result); }
public override void Awake() { base.Awake(); this.Add(new CommandBinding(this.Set, delegate() { Entity voxelEntity = this.AttachedVoxel.Value.Target; if (voxelEntity == null) { return; } Voxel map = voxelEntity.Get <Voxel>(); Voxel.State state = Voxel.States.All[this.State]; if (this.Contiguous) { Voxel.Box b = map.GetBox(this.Coord); if (b != null && b.Type != state) { List <Voxel.Coord> coords = map.GetContiguousByType(new[] { b }).SelectMany(x => x.GetCoords()).Select(x => x.WithData(state)).ToList(); lock (map.MutationLock) { map.Empty(coords, true, true); map.Fill(coords); } map.Regenerate(); } } else { if (map[this.Coord] != state) { lock (map.MutationLock) { map.Empty(this.Coord, true, true); map.Fill(this.Coord, state); } map.Regenerate(); } } })); }
private static void explode(Main main, Voxel map, Voxel.Coord coord, Vector3 pos, int radius, float physicsRadius) { float distanceToCamera = (main.Camera.Position.Value - pos).Length(); // Kaboom Sound.PostEvent(distanceToCamera < physicsRadius * 1.5f ? AK.EVENTS.PLAY_EXPLOSION_CLOSE : AK.EVENTS.PLAY_EXPLOSION, pos); Entity lightEntity = Factory.Get <PointLightFactory>().CreateAndBind(main); lightEntity.Serialize = false; PointLight light = lightEntity.Get <PointLight>(); light.Color.Value = new Vector3(1.3f, 1.1f, 0.9f); light.Attenuation.Value = 20.0f; light.Position.Value = pos; lightEntity.Add(new Animation ( new Animation.FloatMoveTo(light.Attenuation, 0.0f, 1.0f), new Animation.Execute(light.Delete) )); main.Add(lightEntity); SmokeFactory smokeFactory = Factory.Get <SmokeFactory>(); for (int i = 0; i < 5; i++) { Entity smoke = smokeFactory.CreateAndBind(main); smoke.Get <Transform>().Position.Value = pos; main.Add(smoke); } ParticleEmitter.Emit(main, "Smoke", pos, physicsRadius * 0.4f, 250); Entity player = PlayerFactory.Instance; if (player != null && player.Active) { player.Get <CameraController>().Shake.Execute(pos, 50.0f); } const float physicsImpulse = 70.0f; const float minPlayerDamage = 0.1f; const float playerDamageMultiplier = 2.0f; // Remove the cells BlockFactory blockFactory = Factory.Get <BlockFactory>(); foreach (Voxel m in Voxel.ActiveVoxels.ToList()) { List <Voxel.Coord> removals = new List <Voxel.Coord>(); Voxel.Coord c = m.GetCoordinate(pos); Vector3 relativePos = m.GetRelativePosition(c); Quaternion quat = m.Entity.Get <Transform>().Quaternion; for (Voxel.Coord x = c.Move(Direction.NegativeX, radius - 1); x.X < c.X + radius; x.X++) { for (Voxel.Coord y = x.Move(Direction.NegativeY, radius - 1); y.Y < c.Y + radius; y.Y++) { for (Voxel.Coord z = y.Move(Direction.NegativeZ, radius - 1); z.Z < c.Z + radius; z.Z++) { Voxel.State s = m[z]; if (s.ID == 0 || s.Permanent) { continue; } Vector3 cellPos = m.GetRelativePosition(z); if ((cellPos - relativePos).Length() < radius - 1) { removals.Add(z); if (random.NextDouble() > 0.5) { Entity block = blockFactory.CreateAndBind(main); Transform blockTransform = block.Get <Transform>(); blockTransform.Position.Value = m.GetAbsolutePosition(cellPos); blockTransform.Quaternion.Value = Quaternion.CreateFromYawPitchRoll(((float)random.NextDouble() - 0.5f) * 2.0f * (float)Math.PI, ((float)random.NextDouble() - 0.5f) * 2.0f * (float)Math.PI, ((float)random.NextDouble() - 0.5f) * 2.0f * (float)Math.PI); s.ApplyToBlock(block); main.Add(block); } } } } } if (removals.Count > 0) { m.Empty(removals); m.Regenerate(); } } // Damage the player if (player != null && player.Active) { Vector3 toPlayer = player.Get <Transform>().Position - pos; float d = toPlayer.Length(); if (d < physicsRadius) { float attenuation = 1.0f; if (d > 0) { Voxel.GlobalRaycast(pos, toPlayer / d, d, delegate(int x, Voxel.t c) { Voxel.State s = Voxel.States.All[c]; if (s.Permanent) { attenuation = 0.0f; return(true); } else if (s.Hard) { attenuation -= 0.6f; } else { attenuation -= 0.35f; } return(false); }); attenuation = Math.Max(0, attenuation); } player.Get <Agent>().Damage.Execute(attenuation * (minPlayerDamage + (1.0f - (d / physicsRadius)) * playerDamageMultiplier)); } } // Apply impulse to dynamic maps foreach (Voxel m in Voxel.ActiveVoxels) { DynamicVoxel dm = m as DynamicVoxel; if (dm == null) { continue; } Vector3 toMap = dm.Transform.Value.Translation - pos; float distanceToMap = toMap.Length(); toMap /= distanceToMap; toMap *= Math.Max(0.0f, 1.0f - (distanceToMap / physicsRadius)) * Math.Min(200.0f, dm.PhysicsEntity.Mass) * physicsImpulse; dm.PhysicsEntity.ApplyImpulse(dm.Transform.Value.Translation + new Vector3(((float)random.NextDouble() - 0.5f) * 2.0f, ((float)random.NextDouble() - 0.5f) * 2.0f, ((float)random.NextDouble() - 0.5f) * 2.0f), toMap); } // Apply impulse to physics blocks foreach (Entity b in main.Get("Block")) { PhysicsBlock block = b.Get <PhysicsBlock>(); Vector3 fromExplosion = b.Get <Transform>().Position.Value - pos; float distance = fromExplosion.Length(); if (distance > 0.0f && distance < physicsRadius) { float blend = 1.0f - (distance / physicsRadius); block.Box.LinearVelocity += fromExplosion * blend * 10.0f / distance; block.Box.AngularVelocity += new Vector3(((float)random.NextDouble() - 0.5f) * 2.0f, ((float)random.NextDouble() - 0.5f) * 2.0f, ((float)random.NextDouble() - 0.5f) * 2.0f) * blend; } } }
public bool Go() { if (this.main.TotalTime - this.LastJump < jumpCoolDown || this.Crouched) { return(false); } bool supported = this.IsSupported; WallRun.State wallRunState = this.WallRunState; Matrix rotationMatrix = Matrix.CreateRotationY(this.Rotation); Vector3 forward = -rotationMatrix.Forward; Vector2 jumpDirection = this.AbsoluteMovementDirection; Vector3 baseVelocity = Vector3.Zero; bool wallJumping = false; const float wallJumpHorizontalVelocityAmount = 0.75f; const float wallJumpDistance = 2.0f; Action <Voxel, Direction, Voxel.Coord> wallJump = delegate(Voxel wallJumpMap, Direction wallNormalDirection, Voxel.Coord wallCoordinate) { this.LastWallRunMap.Value = wallJumpMap; this.LastWallDirection.Value = wallNormalDirection.GetReverse(); this.LastWallJump.Value = main.TotalTime; Voxel.State wallType = wallJumpMap[wallCoordinate]; if (wallType == Voxel.States.Empty) // Empty. Must be a block possibility that hasn't been instantiated yet { wallType = Voxel.States.Blue; } this.WalkedOn.Execute(wallJumpMap, wallCoordinate, wallNormalDirection.GetReverse()); AkSoundEngine.PostEvent(AK.EVENTS.FOOTSTEP_PLAY, this.Entity); wallJumping = true; // Set up wall jump velocity Vector3 absoluteWallNormal = wallJumpMap.GetAbsoluteVector(wallNormalDirection.GetVector()); Vector2 wallNormal2 = new Vector2(absoluteWallNormal.X, absoluteWallNormal.Z); wallNormal2.Normalize(); bool wallRunningStraight = wallRunState == WallRun.State.Straight || wallRunState == WallRun.State.Down; if (wallRunningStraight) { jumpDirection = new Vector2(main.Camera.Forward.Value.X, main.Camera.Forward.Value.Z); } else { jumpDirection = new Vector2(forward.X, forward.Z); } jumpDirection.Normalize(); float dot = Vector2.Dot(wallNormal2, jumpDirection); if (dot < 0) { jumpDirection = jumpDirection - (2.0f * dot * wallNormal2); } jumpDirection *= wallJumpHorizontalVelocityAmount; if (!wallRunningStraight && Math.Abs(dot) < 0.5f) { // If we're jumping perpendicular to the wall, add some velocity so we jump away from the wall a bit jumpDirection += wallJumpHorizontalVelocityAmount * 0.75f * wallNormal2; } Vector3 supportLocation = this.FloorPosition; baseVelocity += wallJumpMap.LinearVelocity + Vector3.Cross(wallJumpMap.AngularVelocity, supportLocation - wallJumpMap.Transform.Value.Translation); }; if (!supported && wallRunState == WallRun.State.None && this.LinearVelocity.Value.Y > Lemma.Components.FallDamage.DamageVelocity * 1.5f) { // We're not doing our normal jump, and not wall-runnign // See if we can wall-jump Vector3 playerPos = this.Position; Voxel.GlobalRaycastResult?closestWallRaycastHit = null; Vector3 closestWallRaycastDirection = Vector3.Zero; foreach (Vector3 dir in new[] { rotationMatrix.Left, rotationMatrix.Right, rotationMatrix.Backward, rotationMatrix.Forward }) { Voxel.GlobalRaycastResult hit = Voxel.GlobalRaycast(playerPos, dir, wallJumpDistance); if (hit.Voxel != null && (!closestWallRaycastHit.HasValue || hit.Distance < closestWallRaycastHit.Value.Distance)) { closestWallRaycastDirection = dir; closestWallRaycastHit = hit; } } if (closestWallRaycastHit != null) { Voxel m = closestWallRaycastHit.Value.Voxel; wallJump(m, closestWallRaycastHit.Value.Normal, closestWallRaycastHit.Value.Coordinate.Value); } } // If we're wall-running, we can wall-jump // Add some velocity so we jump away from the wall a bit if (wallRunState != WallRun.State.None) { Vector3 pos = this.FloorPosition + new Vector3(0, 0.5f, 0); Voxel.Coord wallCoord = this.WallRunMap.Value.GetCoordinate(pos).Move(this.WallDirection, 2); wallJump(this.WallRunMap, this.WallDirection.Value.GetReverse(), wallCoord); } bool go = supported || wallJumping; BlockPredictor.Possibility instantiatedBlockPossibility = null; Voxel.Coord instantiatedBlockPossibilityCoord = default(Voxel.Coord); if (!go) { // Check block possibilities beneath us Vector3 jumpPos = this.FloorPosition + new Vector3(0, -1.0f, 0); foreach (BlockPredictor.Possibility possibility in this.Predictor.AllPossibilities) { Voxel.Coord possibilityCoord = possibility.Map.GetCoordinate(jumpPos); if (possibilityCoord.Between(possibility.StartCoord, possibility.EndCoord) && !possibility.Map.GetCoordinate(jumpPos + new Vector3(2.0f)).Between(possibility.StartCoord, possibility.EndCoord)) { this.Predictor.InstantiatePossibility(possibility); go = true; instantiatedBlockPossibility = possibility; instantiatedBlockPossibilityCoord = possibilityCoord; break; } } } if (!go) { // Check block possibilities for wall jumping Vector3 playerPos = this.Position; Vector3[] wallJumpDirections = new[] { rotationMatrix.Left, rotationMatrix.Right, rotationMatrix.Forward }; foreach (BlockPredictor.Possibility possibility in this.Predictor.AllPossibilities) { foreach (Vector3 dir in wallJumpDirections) { foreach (Voxel.Coord coord in possibility.Map.Rasterize(playerPos, playerPos + (dir * wallJumpDistance))) { if (coord.Between(possibility.StartCoord, possibility.EndCoord)) { this.Predictor.InstantiatePossibility(possibility); instantiatedBlockPossibility = possibility; instantiatedBlockPossibilityCoord = coord; wallJump(possibility.Map, possibility.Map.GetRelativeDirection(dir).GetReverse(), coord); wallJumping = true; go = true; break; } } if (wallJumping) { break; } } if (wallJumping) { break; } } } if (go) { float totalMultiplier = 1.0f; bool grunted = false; if (wallJumping) { if (this.wallJumpCount == 0) { this.wallJumpChainStart = this.Position; } else { Vector3 chainDistance = this.Position - this.wallJumpChainStart; chainDistance.Y = 0.0f; if (chainDistance.Length() > 6.0f) { this.wallJumpCount = 0; this.wallJumpChainStart = this.Position; } } if (this.wallJumpCount > 3) { return(false); } totalMultiplier = 1.0f - Math.Min(1.0f, this.wallJumpCount / 8.0f); this.wallJumpCount++; } else { // Regular jump // Take base velocity into account baseVelocity += this.SupportVelocity; grunted = this.FallDamage.ApplyJump(); if (!this.Active) // We got killed by fall damage { return(false); } if (instantiatedBlockPossibility != null) { this.WalkedOn.Execute(instantiatedBlockPossibility.Map, instantiatedBlockPossibilityCoord, instantiatedBlockPossibility.Map.GetRelativeDirection(Direction.NegativeY)); } // Also manually reset our ability to kick and wall-jump this.CanKick.Value = true; this.wallJumpCount = 0; } Vector3 velocity = this.LinearVelocity - baseVelocity; float currentVerticalSpeed = velocity.Y; velocity.Y = 0.0f; float jumpSpeed = jumpDirection.Length(); if (jumpSpeed > 0) { jumpDirection *= (wallJumping ? Math.Max(this.MaxSpeed, Vector3.Dot(forward, velocity)) : velocity.Length()) / jumpSpeed; } if (main.TotalTime - this.LastRollKickEnded < 0.3f) { totalMultiplier *= 1.2f; } float verticalJumpSpeed = this.JumpSpeed; // If we're not instantiating a block possibility beneath us or we're not currently falling, incorporate some of our existing vertical velocity in our jump if (instantiatedBlockPossibility == null || wallJumping || currentVerticalSpeed > 0.0f) { verticalJumpSpeed += currentVerticalSpeed * 0.5f; } this.LinearVelocity.Value = baseVelocity + new Vector3(jumpDirection.X, verticalJumpSpeed, jumpDirection.Y) * totalMultiplier; velocity = this.LinearVelocity; velocity.Y = 0.0f; this.LastSupportedSpeed.Value = velocity.Length(); if (supported && this.SupportEntity.Value != null) { Vector3 impulsePosition = this.FloorPosition; Vector3 impulse = this.LinearVelocity.Value * this.Mass * -1.0f; this.SupportEntity.Value.ApplyImpulse(ref impulsePosition, ref impulse); } Session.Recorder.Event(main, "Jump"); this.IsSupported.Value = false; this.SupportEntity.Value = null; this.HasTraction.Value = false; AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_JUMP, this.Entity); if (!grunted && (float)this.random.NextDouble() < 0.15f) { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_LAND, this.Entity); // Grunt } this.model.Stop ( "Vault", "Mantle", "TopOut", "Jump", "Jump02", "Jump03", "JumpLeft", "JumpRight", "JumpBackward" ); velocity = -Vector3.TransformNormal(this.LinearVelocity, Matrix.CreateRotationY(-this.Rotation)); velocity.Y = 0.0f; if (wallRunState == WallRun.State.Left || wallRunState == WallRun.State.Right) { velocity.Z = 0.0f; } else if (wallJumping) { velocity.Z *= 0.5f; } else { velocity.X = 0.0f; } Direction direction = DirectionExtensions.GetDirectionFromVector(velocity); string animation; switch (direction) { case Direction.NegativeX: animation = "JumpLeft"; break; case Direction.PositiveX: animation = "JumpRight"; break; case Direction.PositiveZ: animation = wallJumping ? "JumpBackward" : this.randomJumpAnimation(); break; default: animation = this.randomJumpAnimation(); break; } this.model.StartClip(animation, 4, false); this.model[animation].CurrentTime = TimeSpan.FromSeconds(0.2); // Deactivate any wall-running we're doing this.DeactivateWallRun.Execute(); // Play a footstep sound since we're jumping off the ground AkSoundEngine.PostEvent(AK.EVENTS.FOOTSTEP_PLAY, this.Entity); this.LastJump.Value = this.main.TotalTime; return(true); } return(false); }
public virtual void Initialize(Voxel.State fillType, int radius) { this.fillType = fillType; this.radius = radius; }
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 static bool Go(Voxel voxel, Voxel.Coord center, int radius, Action <List <DynamicVoxel> > callback = null) { if (!voxel[center].Permanent) { // Break off a chunk of this voxel into a new DynamicMap. List <Voxel.Coord> edges = new List <Voxel.Coord>(); Voxel.Coord ripStart = center.Move(-radius, -radius, -radius); Voxel.Coord ripEnd = center.Move(radius, radius, radius); Dictionary <Voxel.Box, bool> permanentBoxes = new Dictionary <Voxel.Box, bool>(); foreach (Voxel.Coord c in ripStart.CoordinatesBetween(ripEnd)) { Voxel.Box box = voxel.GetBox(c); if (box != null && box.Type.Permanent) { permanentBoxes[box] = true; } } foreach (Voxel.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++) { Voxel.Coord coord = new Voxel.Coord { X = x, Y = b.Y + b.Height, Z = z }; if (coord.Between(ripStart, ripEnd)) { edges.Add(coord); } coord = new Voxel.Coord { 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++) { Voxel.Coord coord = new Voxel.Coord { X = b.X - 1, Y = y, Z = z }; if (coord.Between(ripStart, ripEnd)) { edges.Add(coord); } coord = new Voxel.Coord { 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++) { Voxel.Coord coord = new Voxel.Coord { X = x, Y = y, Z = b.Z - 1 }; if (coord.Between(ripStart, ripEnd)) { edges.Add(coord); } coord = new Voxel.Coord { 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++) { Voxel.Coord c = new Voxel.Coord { X = x, Y = ripStart.Y, Z = z }; Voxel.State s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } c = new Voxel.Coord { X = x, Y = ripEnd.Y, Z = z }; s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } } } // Sides for (int y = ripStart.Y + 1; y <= ripEnd.Y - 1; y++) { // Left and right for (int z = ripStart.Z; z <= ripEnd.Z; z++) { Voxel.Coord c = new Voxel.Coord { X = ripStart.X, Y = y, Z = z }; Voxel.State s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } c = new Voxel.Coord { X = ripEnd.X, Y = y, Z = z }; s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } } // Backward and forward for (int x = ripStart.X; x <= ripEnd.X; x++) { Voxel.Coord c = new Voxel.Coord { X = x, Y = y, Z = ripStart.Z }; Voxel.State s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } c = new Voxel.Coord { X = x, Y = y, Z = ripEnd.Z }; s = voxel[c]; if (s != Voxel.States.Empty && !s.Permanent) { edges.Add(c); } } } Propagator p = WorldFactory.Instance.Get <Propagator>(); foreach (Voxel.Coord c in edges) { p.SparksLowPriority(voxel.GetAbsolutePosition(c), Propagator.Spark.Dangerous); } voxel.Empty(edges); voxel.Regenerate(callback); return(true); } return(false); }
// Function for finding a platform to build for the player public Possibility FindPlatform(Vector3 position) { int shortestDistance = searchDistance; Direction relativeShortestDirection = Direction.None, absoluteShortestDirection = Direction.None; Voxel.Coord shortestCoordinate = new Voxel.Coord(); Voxel shortestMap = null; EffectBlockFactory blockFactory = Factory.Get <EffectBlockFactory>(); foreach (Voxel map in Voxel.ActivePhysicsVoxels) { if (!ignoreTypes.Contains(map.Entity.Type)) { List <Matrix> results = new List <Matrix>(); Voxel.Coord absolutePlayerCoord = map.GetCoordinate(position); bool inMap = map.GetChunk(absolutePlayerCoord, false) != null; foreach (Direction absoluteDir in platformBuildableDirections) { Voxel.Coord playerCoord = absoluteDir == Direction.NegativeY ? absolutePlayerCoord : map.GetCoordinate(position + new Vector3(0, platformSize / -2.0f, 0)); Direction relativeDir = map.GetRelativeDirection(absoluteDir); if (!inMap && map.GetChunk(playerCoord.Move(relativeDir, searchDistance), false) == null) { continue; } for (int i = 1; i < shortestDistance; i++) { Voxel.Coord coord = playerCoord.Move(relativeDir, i); Voxel.State state = map[coord]; if (state == Voxel.States.Empty) { continue; } if (this.canBuild(state) && this.canBuild(map.GetAbsolutePosition(coord))) { shortestDistance = i; relativeShortestDirection = relativeDir; absoluteShortestDirection = absoluteDir; shortestCoordinate = playerCoord; shortestMap = map; } break; } } } } if (shortestMap != null && shortestDistance > 1) { Direction yDir = relativeShortestDirection.IsParallel(Direction.PositiveY) ? Direction.PositiveX : Direction.PositiveY; Direction zDir = relativeShortestDirection.Cross(yDir); int initialOffset = absoluteShortestDirection == Direction.NegativeY ? 0 : -2; Voxel.Coord startCoord = shortestCoordinate.Move(relativeShortestDirection, initialOffset).Move(yDir, platformSize / -2).Move(zDir, platformSize / -2); Voxel.Coord endCoord = startCoord.Move(relativeShortestDirection, -initialOffset + shortestDistance).Move(yDir, platformSize).Move(zDir, platformSize); return(new Possibility { Map = shortestMap, StartCoord = new Voxel.Coord { X = Math.Min(startCoord.X, endCoord.X), Y = Math.Min(startCoord.Y, endCoord.Y), Z = Math.Min(startCoord.Z, endCoord.Z) }, EndCoord = new Voxel.Coord { X = Math.Max(startCoord.X, endCoord.X), Y = Math.Max(startCoord.Y, endCoord.Y), Z = Math.Max(startCoord.Z, endCoord.Z) }, }); } return(null); }
public override void Awake() { base.Awake(); Switch.all.Add(this); this.Add(new NotifyBinding(delegate() { if (this.On) { this.OnPowerOn.Execute(); } else { this.OnPowerOff.Execute(); } }, this.On)); this.Add(new CommandBinding(this.OnPowerOff, delegate() { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_SWITCH_OFF, this.Entity); })); this.Add(new CommandBinding(this.OnPowerOn, delegate() { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_SWITCH_ON, this.Entity); Voxel map = this.AttachedVoxel.Value.Target.Get <Voxel>(); List <Voxel.Coord> changes = new List <Voxel.Coord>(); Stack <Voxel.Box> path = new Stack <Voxel.Box>(); Queue <Voxel.Coord> queue = new Queue <Voxel.Coord>(); foreach (Switch s in Switch.all) { if (s.On && s != this && s.AttachedVoxel.Value.Target == this.AttachedVoxel.Value.Target && VoxelAStar.Broadphase(map, map.GetBox(this.Coord), s.Coord, canConnect, path, 2000)) { Voxel.Coord start = s.Coord; start.Data = map[start]; queue.Enqueue(start); while (queue.Count > 0) { Voxel.Coord c = queue.Dequeue(); c.Data = null; // Ensure the visited dictionary works correctly Voxel.CoordDictionaryCache[c] = true; Voxel.Coord change = c.Clone(); change.Data = Voxel.States.Switch; changes.Add(change); foreach (Direction adjacentDirection in DirectionExtensions.Directions) { Voxel.Coord adjacentCoord = c.Move(adjacentDirection); if (!Voxel.CoordDictionaryCache.ContainsKey(adjacentCoord)) { Voxel.State adjacentState = map[adjacentCoord]; if (adjacentState == Voxel.States.PoweredSwitch) { queue.Enqueue(adjacentCoord); } else if ((adjacentState == Voxel.States.Blue || adjacentState == Voxel.States.Powered) && path.Contains(map.GetBox(adjacentCoord))) { adjacentCoord.Data = Voxel.States.Neutral; changes.Add(adjacentCoord); } } } } } path.Clear(); queue.Clear(); } Voxel.CoordDictionaryCache.Clear(); if (changes.Count > 0) { lock (map.MutationLock) { map.Empty(changes, true, true, map); map.Fill(changes); } map.Regenerate(); } })); }
private static bool canConnect(Voxel.State state) { return(state == Voxel.States.Powered || state == Voxel.States.HardPowered || state == Voxel.States.PoweredSwitch); }
public override void Awake() { base.Awake(); Switch.all.Add(this); this.Add(new NotifyBinding(delegate() { if (this.On) { this.OnPowerOn.Execute(); } else { this.OnPowerOff.Execute(); } }, this.On)); this.Add(new CommandBinding(this.OnPowerOff, delegate() { if (this.main.TotalTime > 0.1f) { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_SWITCH_OFF, this.Entity); } })); this.Add(new CommandBinding(this.OnPowerOn, delegate() { if (this.main.TotalTime > 0.1f && this.PowerOnCue != 0) { AkSoundEngine.PostEvent(this.PowerOnCue, this.Entity); } Voxel map = this.AttachedVoxel.Value.Target.Get <Voxel>(); Switch closestConnectedSwitch = null; Stack <Voxel.Box> closestConnectedPath = null; foreach (Switch s in Switch.all) { Stack <Voxel.Box> path = new Stack <Voxel.Box>(); if (s.On && s != this && s.AttachedVoxel.Value.Target == this.AttachedVoxel.Value.Target && VoxelAStar.Broadphase(map, map.GetBox(this.Coord), s.Coord, canConnect, path, 2000)) { if (closestConnectedPath == null || path.Count < closestConnectedPath.Count) { closestConnectedSwitch = s; closestConnectedPath = path; } } } if (closestConnectedSwitch != null) { List <Voxel.Coord> changes = new List <Voxel.Coord>(); Queue <Voxel.Coord> queue = new Queue <Voxel.Coord>(); Voxel.Coord start = closestConnectedSwitch.Coord; start.Data = null; queue.Enqueue(start); Voxel.CoordSetCache.Add(start); start.Data = Voxel.States.Switch; changes.Add(start); while (queue.Count > 0) { Voxel.Coord c = queue.Dequeue(); foreach (Direction adjacentDirection in DirectionExtensions.Directions) { Voxel.Coord adjacentCoord = c.Move(adjacentDirection); if (!Voxel.CoordSetCache.Contains(adjacentCoord)) { Voxel.CoordSetCache.Add(adjacentCoord); Voxel.State adjacentState = map[adjacentCoord]; if (adjacentState == Voxel.States.PoweredSwitch) { queue.Enqueue(adjacentCoord); adjacentCoord.Data = Voxel.States.Switch; changes.Add(adjacentCoord); } else if (adjacentState == Voxel.States.Hard) { queue.Enqueue(adjacentCoord); } else if (adjacentState == Voxel.States.HardPowered) { queue.Enqueue(adjacentCoord); adjacentCoord.Data = Voxel.States.Hard; changes.Add(adjacentCoord); } else if ((adjacentState == Voxel.States.Blue || adjacentState == Voxel.States.Powered) && closestConnectedPath.Contains(map.GetBox(adjacentCoord))) { adjacentCoord.Data = Voxel.States.Neutral; changes.Add(adjacentCoord); adjacentCoord.Data = null; } } } } Voxel.CoordSetCache.Clear(); if (changes.Count > 0) { lock (map.MutationLock) { map.Empty(changes, true, true, map); map.Fill(changes); } map.Regenerate(); } } })); }
private bool determineShouldBuildFloor(Voxel.State floorState) { bool result = false; if (floorState == Voxel.States.Blue || floorState == Voxel.States.Powered) { // If we're standing on blue or powered, we need to check if we're close to a non-blue block before we can build a floor // This prevents the player from building a floor infinitely Queue <Voxel.Box> queue = new Queue <Voxel.Box>(); Dictionary <Voxel.Box, int> visited = new Dictionary <Voxel.Box, int>(); Voxel.Box floorBox = this.floorMap.GetBox(this.floorCoordinate); queue.Enqueue(floorBox); visited[floorBox] = 0; const int radius = 6; const int maxSearch = radius * radius * radius; int searchIndex = 0; while (queue.Count > 0 && searchIndex < maxSearch) { searchIndex++; Voxel.Box b = queue.Dequeue(); lock (b.Adjacent) { int parentGScore = visited[b]; for (int i = 0; i < b.Adjacent.Count; i++) { Voxel.Box adjacent = b.Adjacent[i]; int tentativeGScore = parentGScore + adjacent.Width * adjacent.Height * adjacent.Depth; int previousGScore; if (!visited.TryGetValue(adjacent, out previousGScore) || tentativeGScore < previousGScore) { visited[adjacent] = tentativeGScore; if (parentGScore < radius * radius && this.floorCoordinate.X >= adjacent.X - radius && this.floorCoordinate.X < adjacent.X + adjacent.Width + radius && this.floorCoordinate.Y >= adjacent.Y - radius && this.floorCoordinate.Y < adjacent.Y + adjacent.Height + radius && this.floorCoordinate.Z >= adjacent.Z - radius && this.floorCoordinate.Z < adjacent.Z + adjacent.Depth + radius) { if (adjacent.Type != Voxel.States.Blue && adjacent.Type != Voxel.States.Powered) { // Non-blue block. It's close enough, we can build a floor result = true; break; } else { queue.Enqueue(adjacent); } } } } } if (result) { break; } } } else { result = true; } return(result); }
private static bool filter(Voxel.State state) { return(state != Components.Voxel.States.Empty && !state.Hard); }
public override void Bind(Entity entity, Main main, bool creating = false) { SpotLight light = entity.Create <SpotLight>(); light.Enabled.Value = !main.EditorEnabled; light.FieldOfView.Value = 1.0f; light.Attenuation.Value = 75.0f; Transform transform = entity.GetOrCreate <Transform>("Transform"); light.Add(new Binding <Vector3>(light.Position, transform.Position)); Turret turret = entity.GetOrCreate <Turret>("Turret"); Command die = new Command { Action = delegate() { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_TURRET_DEATH, entity); ParticleSystem shatter = ParticleSystem.Get(main, "InfectedShatter"); Random random = new Random(); 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(transform.Position + offset, offset); } entity.Delete.Execute(); } }; VoxelAttachable attachable = VoxelAttachable.MakeAttachable(entity, main, true, true, die); attachable.Enabled.Value = true; attachable.Offset.Value = 2; PointLight pointLight = entity.GetOrCreate <PointLight>(); pointLight.Serialize = false; pointLight.Add(new Binding <Vector3>(pointLight.Position, transform.Position)); LineDrawer laser = new LineDrawer { Serialize = false }; entity.Add(laser); laser.DrawOrder.Value = 0; AI ai = entity.GetOrCreate <AI>("AI"); ModelAlpha model = entity.Create <ModelAlpha>(); model.Add(new Binding <Matrix>(model.Transform, transform.Matrix)); model.Filename.Value = "AlphaModels\\pyramid"; const float defaultModelScale = 0.75f; model.Scale.Value = new Vector3(defaultModelScale); const float sightDistance = 80.0f; const float hearingDistance = 0.0f; const float operationalRadius = 100.0f; model.Add(new Binding <Vector3, string>(model.Color, delegate(string state) { switch (state) { case "Alert": return(new Vector3(1.0f, 1.0f, 0.25f)); case "Aggressive": return(new Vector3(1.0f, 0.5f, 0.25f)); case "Firing": return(new Vector3(1.0f, 0.0f, 0.0f)); case "Disabled": return(new Vector3(0.0f, 0.0f, 0.0f)); default: return(new Vector3(1.0f, 1.0f, 1.0f)); } }, ai.CurrentState)); laser.Add(new Binding <bool, string>(laser.Enabled, x => x != "Disabled" && x != "Suspended", ai.CurrentState)); light.Add(new Binding <Vector3>(light.Color, model.Color)); pointLight.Add(new Binding <Vector3>(pointLight.Color, model.Color)); Voxel.GlobalRaycastResult rayHit = new Voxel.GlobalRaycastResult(); Vector3 toReticle = Vector3.Zero; AI.Task checkOperationalRadius = new AI.Task { Interval = 2.0f, Action = delegate() { bool shouldBeActive = (transform.Position.Value - main.Camera.Position).Length() < operationalRadius && Water.Get(transform.Position) == null; if (shouldBeActive && ai.CurrentState == "Suspended") { ai.CurrentState.Value = "Idle"; } else if (!shouldBeActive && ai.CurrentState != "Suspended") { ai.CurrentState.Value = "Suspended"; } }, }; turret.Add(new CommandBinding(turret.PowerOn, delegate() { if (ai.CurrentState == "Disabled") { ai.CurrentState.Value = "Suspended"; checkOperationalRadius.Action(); } })); turret.Add(new CommandBinding(turret.PowerOff, delegate() { ai.CurrentState.Value = "Disabled"; })); light.Add(new Binding <Quaternion>(light.Orientation, delegate() { return(Quaternion.CreateFromYawPitchRoll(-(float)Math.Atan2(toReticle.Z, toReticle.X) - (float)Math.PI * 0.5f, (float)Math.Asin(toReticle.Y), 0)); }, transform.Position, turret.Reticle)); AI.Task updateRay = new AI.Task { Action = delegate() { toReticle = Vector3.Normalize(turret.Reticle.Value - transform.Position.Value); rayHit = Voxel.GlobalRaycast(transform.Position, toReticle, operationalRadius); laser.Lines.Clear(); Microsoft.Xna.Framework.Color color = new Microsoft.Xna.Framework.Color(model.Color); laser.Lines.Add(new LineDrawer.Line { A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(transform.Position, color), B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(rayHit.Position, color), }); } }; ai.Add(new AI.AIState { Name = "Disabled", Tasks = new AI.Task[] { }, }); ai.Add(new AI.AIState { Name = "Suspended", Tasks = new[] { checkOperationalRadius, }, }); ai.Add(new AI.AIState { Name = "Idle", Tasks = new[] { checkOperationalRadius, updateRay, 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"; } }, }, }, }); ai.Add(new AI.AIState { Name = "Alert", Tasks = new[] { checkOperationalRadius, updateRay, 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 = "Aggressive"; } } }, }, }, }); 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"; } }, }; float lastSpotted = 0.0f; ai.Add(new AI.AIState { Name = "Aggressive", Tasks = new[] { checkTargetAgent, updateRay, new AI.Task { Action = delegate() { Entity target = ai.TargetAgent.Value.Target; turret.Reticle.Value += (target.Get <Transform>().Position - turret.Reticle.Value) * Math.Min(3.0f * main.ElapsedTime, 1.0f); } }, new AI.Task { Interval = 0.1f, Action = delegate() { if (Agent.Query(transform.Position, sightDistance, hearingDistance, ai.TargetAgent.Value.Target.Get <Agent>())) { lastSpotted = main.TotalTime; } if (ai.TimeInCurrentState.Value > 1.5f) { if (lastSpotted < main.TotalTime - 2.0f) { ai.CurrentState.Value = "Alert"; } else { Vector3 targetPos = ai.TargetAgent.Value.Target.Get <Transform>().Position.Value; Vector3 toTarget = Vector3.Normalize(targetPos - transform.Position.Value); if (Vector3.Dot(toReticle, toTarget) > 0.95f) { ai.CurrentState.Value = "Firing"; } } } } }, } }); ai.Add(new AI.AIState { Name = "Firing", Enter = delegate(AI.AIState last) { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_TURRET_CHARGE, entity); }, Exit = delegate(AI.AIState next) { Voxel.State attachedState = attachable.AttachedVoxel.Value.Target.Get <Voxel>()[attachable.Coord]; if (!attachedState.Permanent && rayHit.Voxel != null && (rayHit.Position - transform.Position).Length() < 8.0f) { return; // Danger close, cease fire! } AkSoundEngine.PostEvent(AK.EVENTS.PLAY_TURRET_FIRE, entity); bool hitVoxel = true; Entity target = ai.TargetAgent.Value.Target; if (target != null && target.Active) { Vector3 targetPos = target.Get <Transform>().Position; Vector3 toTarget = targetPos - transform.Position.Value; if (Vector3.Dot(toReticle, Vector3.Normalize(toTarget)) > 0.2f) { float distance = toTarget.Length(); if (distance < rayHit.Distance) { Sound.PostEvent(AK.EVENTS.PLAY_TURRET_MISS, transform.Position + toReticle * distance); } } BEPUutilities.RayHit physicsHit; if (target.Get <Player>().Character.Body.CollisionInformation.RayCast(new Ray(transform.Position, toReticle), rayHit.Voxel == null ? float.MaxValue : rayHit.Distance, out physicsHit)) { Explosion.Explode(main, targetPos, 6, 8.0f); hitVoxel = false; } } if (hitVoxel && rayHit.Voxel != null) { Explosion.Explode(main, rayHit.Position + rayHit.Voxel.GetAbsoluteVector(rayHit.Normal.GetVector()) * 0.5f, 6, 8.0f); } Vector3 splashPos; Water w = Water.Raycast(transform.Position, toReticle, rayHit.Distance, out splashPos); if (w != null) { Sound.PostEvent(AK.EVENTS.PLAY_WATER_SPLASH, splashPos); Water.SplashParticles(main, splashPos, 3.0f); } }, Tasks = new[] { checkTargetAgent, updateRay, new AI.Task { Action = delegate() { if (ai.TimeInCurrentState.Value > 0.75f) { ai.CurrentState.Value = "Aggressive"; // This actually fires (in the Exit function) } } } } }); this.SetMain(entity, main); entity.Add("On", turret.On); entity.Add("PowerOn", turret.PowerOn); entity.Add("PowerOff", turret.PowerOff); }
public void InternalBind(Entity entity, Main main, bool creating = false, Transform transform = null, bool dataOnly = false) { if (transform == null) { transform = entity.GetOrCreate <Transform>("Transform"); } entity.CannotSuspend = false; Voxel map = entity.Get <Voxel>(); // Apply the position and orientation components to the map if (main.EditorEnabled || map.Scale.Value != 1.0f) { map.Add(new TwoWayBinding <Matrix, Matrix> ( transform.Matrix, x => x * Matrix.CreateScale(1.0f / map.Scale), new IProperty[] { map.Scale }, map.Transform, x => Matrix.CreateScale(map.Scale) * x, new IProperty[] { map.Scale } )); } else { map.Add(new TwoWayBinding <Matrix>(transform.Matrix, map.Transform)); } map.Add(new CommandBinding(map.CompletelyEmptied, delegate() { if (!main.EditorEnabled) { entity.Delete.Execute(); } })); Entity world = main.Get("World").FirstOrDefault(); if (dataOnly && !main.EditorEnabled) { map.EnablePhysics.Value = false; } else { map.CreateModel = delegate(Vector3 min, Vector3 max, Voxel.State state) { if (state.Invisible && !main.EditorEnabled) { return(null); } DynamicModel <Voxel.Vertex> model = new DynamicModel <Voxel.Vertex>(Voxel.Vertex.VertexDeclaration); model.EffectFile.Value = "Effects\\Environment"; model.Lock = new object(); state.ApplyTo(model); if (state.Invisible) { model.Add(new Binding <bool>(model.Enabled, Editor.EditorModelsVisible)); } /* * ModelAlpha debug = new ModelAlpha { Serialize = false }; * debug.Alpha.Value = 0.01f; * debug.DrawOrder.Value = 11; // In front of water * debug.Color.Value = new Vector3(1.0f, 0.8f, 0.6f); * debug.Filename.Value = "AlphaModels\\box"; * debug.CullBoundingBox.Value = false; * debug.DisableCulling.Value = true; * debug.Add(new Binding<Matrix>(debug.Transform, delegate() * { * BoundingBox box = model.BoundingBox; * return Matrix.CreateScale(box.Max - box.Min) * Matrix.CreateTranslation((box.Max + box.Min) * 0.5f) * transform.Matrix; * }, transform.Matrix, model.BoundingBox)); * result.Add(debug); */ if (main.EditorEnabled || map.Scale.Value != 1.0f) { model.Add(new Binding <Matrix>(model.Transform, () => Matrix.CreateScale(map.Scale) * transform.Matrix, transform.Matrix, map.Scale)); } else { model.Add(new Binding <Matrix>(model.Transform, transform.Matrix)); } model.Add(new Binding <Vector3>(model.GetVector3Parameter("Offset"), map.Offset)); Voxel.State s = state; model.Add(new Binding <Matrix>(model.GetMatrixParameter("UVScaleRotation"), delegate() { Matrix m = Matrix.CreateRotationZ(map.UVRotation * (float)Math.PI / 180.0f); float scale = 0.075f * s.Tiling; m.M11 *= scale; m.M12 *= scale; m.M21 *= scale; m.M22 *= scale; return(m); }, map.UVRotation)); model.Add(new Binding <Vector2>(model.GetVector2Parameter("UVOffset"), x => x * 0.075f * s.Tiling, map.UVOffset)); if (!s.ShadowCast) { model.UnsupportedTechniques.Add(Technique.Shadow); } entity.Add(model); // We have to create this binding after adding the model to the entity // Because when the model loads, it automatically calculates a bounding box for it. model.Add(new Binding <BoundingBox, Vector3>(model.BoundingBox, x => new BoundingBox(min - x, max - x), map.Offset)); model.CullBoundingBox.Value = true; return(model); }; } this.SetMain(entity, main); map.Offset.Changed(); }
public virtual Voxel.State Apply(int x, int y, Voxel.State voxel) { return(fillType); }
public void Update(float dt) { // Spawn an editor or a player if needed if (this.main.EditorEnabled) { this.main.Renderer.InternalGamma.Value = 0.0f; this.main.Renderer.Brightness.Value = 0.0f; if (this.editor == null || !this.editor.Active) { this.editor = Factory.Get <EditorFactory>().CreateAndBind(this.main); FPSInput.RecenterMouse(); this.editor.Get <Editor>().Position.Value = this.lastEditorPosition; this.editor.Get <FPSInput>().Mouse.Value = this.lastEditorMouse; this.StartSpawnPoint.Value = this.lastEditorSpawnPoint; this.StartSpawnPointGUID.Value = this.lastEditorSpawnPointGUID; this.main.Add(this.editor); } else { this.lastEditorPosition = this.editor.Get <Editor>().Position; this.lastEditorMouse = this.editor.Get <FPSInput>().Mouse; } } else { if (this.main.MapFile.Value == null || !this.CanSpawn || CameraStop.CinematicActive) { return; } this.editor = null; bool createPlayer = PlayerFactory.Instance == null; if (this.mapJustLoaded) { if (!createPlayer) { // We just loaded a save game this.main.Renderer.InternalGamma.Value = 0.0f; this.main.Renderer.Brightness.Value = 0.0f; this.PlayerSpawned.Execute(); this.respawnTimer = 0; } } else if (createPlayer) { if (this.respawnTimer == 0) { this.main.AddComponent(new Animation(this.FlashAnimation())); } if (this.respawnTimer > this.RespawnInterval) { bool spawnFound = false; RespawnLocation foundSpawnLocation = default(RespawnLocation); Vector3 foundSpawnAbsolutePosition = Vector3.Zero; if (string.IsNullOrEmpty(this.StartSpawnPoint) && this.StartSpawnPointGUID == 0) { // Look for an autosaved spawn point Entity playerData = PlayerDataFactory.Instance; if (playerData != null) { ListProperty <RespawnLocation> respawnLocations = playerData.Get <PlayerData>().RespawnLocations; int supportedLocations = 0; float lowerLimit = Factory.Get <LowerLimitFactory>().GetLowerLimit(); while (respawnLocations.Length > 0) { RespawnLocation respawnLocation = respawnLocations[respawnLocations.Length - 1]; Entity respawnMapEntity = respawnLocation.Map.Target; if (respawnMapEntity != null && respawnMapEntity.Active) { Voxel respawnMap = respawnMapEntity.Get <Voxel>(); Vector3 absolutePos = respawnMap.GetAbsolutePosition(respawnLocation.Coordinate); if (respawnMap.Active && absolutePos.Y > lowerLimit && respawnMap.GetAbsoluteVector(respawnMap.GetRelativeDirection(Direction.PositiveY).GetVector()).Y > 0.5f && Agent.Query(absolutePos, 0.0f, 20.0f) == null && Rift.Query(absolutePos) == null && Zone.CanSpawnAt(absolutePos)) { Voxel.State state = respawnMap[respawnLocation.Coordinate]; if (state != Voxel.States.Empty && state != Voxel.States.Infected && state != Voxel.States.HardInfected && state != Voxel.States.Floater) { supportedLocations++; DynamicVoxel dynamicMap = respawnMap as DynamicVoxel; if (dynamicMap == null || absolutePos.Y > respawnLocation.OriginalPosition.Y - 1.0f) { Voxel.GlobalRaycastResult hit = Voxel.GlobalRaycast(absolutePos + new Vector3(0, 1, 0), Vector3.Up, 2); if (hit.Voxel == null) { // We can spawn here spawnFound = true; foundSpawnLocation = respawnLocation; foundSpawnAbsolutePosition = absolutePos; } } } } } if (supportedLocations >= 40 || (spawnFound && (foundSpawnAbsolutePosition - this.lastPlayerPosition).Length() > this.RespawnDistance)) { if (supportedLocations > 3) // We should try to spawn the player back at least a few steps { break; } } respawnLocations.RemoveAt(respawnLocations.Length - 1); } } } if (spawnFound) { // Spawn at an autosaved location if (createPlayer) { this.spawn(); } Vector3 absolutePos = foundSpawnLocation.Map.Target.Get <Voxel>().GetAbsolutePosition(foundSpawnLocation.Coordinate); PlayerFactory.Instance.Get <Transform>().Position.Value = this.main.Camera.Position.Value = absolutePos + new Vector3(0, spawnHeightOffset, 0); FPSInput.RecenterMouse(); PlayerFactory.Instance.Get <FPSInput>().Mouse.Value = new Vector2(foundSpawnLocation.Rotation, 0); } else { // Spawn at a spawn point PlayerSpawn spawn = null; Entity spawnEntity = null; if (this.StartSpawnPointGUID != 0) { spawnEntity = this.main.GetByGUID(this.StartSpawnPointGUID); if (spawnEntity != null) { spawn = spawnEntity.Get <PlayerSpawn>(); } this.lastEditorSpawnPointGUID = this.StartSpawnPointGUID; this.StartSpawnPointGUID.Value = 0; } else if (!string.IsNullOrEmpty(this.StartSpawnPoint.Value)) { spawnEntity = this.main.GetByID(this.StartSpawnPoint); if (spawnEntity != null) { spawn = spawnEntity.Get <PlayerSpawn>(); } this.lastEditorSpawnPoint = this.StartSpawnPoint; this.StartSpawnPoint.Value = null; } if (spawnEntity == null) { spawn = PlayerSpawn.FirstActive(); spawnEntity = spawn == null ? null : spawn.Entity; } if (spawnEntity != null) { Vector3 pos = spawnEntity.Get <Transform>().Position; main.Camera.Position.Value = pos; WorldFactory.Instance.Get <World>().UpdateZones(); Voxel.GlobalRaycastResult hit = Voxel.GlobalRaycast(pos + new Vector3(0, 2, 0), Vector3.Down, 8, null, false, true); if (hit.Voxel == null) { // There is nowhere to spawn. Reload the map. this.respawnTimer = 0; IO.MapLoader.Load(this.main, this.main.MapFile); return; } else { if (createPlayer) { this.spawn(); } pos = hit.Position + new Vector3(0, spawnHeightOffset, 0); PlayerFactory.Instance.Get <Transform>().Position.Value = this.main.Camera.Position.Value = pos; if (spawn != null) { spawn.IsActivated.Value = true; FPSInput.RecenterMouse(); PlayerFactory.Instance.Get <FPSInput>().Mouse.Value = new Vector2(spawn.Rotation, 0); spawn.OnSpawn.Execute(); } } } } // When the player teleports to a new map, show the number of orbs and notes on that map // If mapJustLoaded is true, we just loaded a save game if (this.main.TotalTime < Spawner.DefaultRespawnInterval * 2 && !this.mapJustLoaded) { WorldFactory.Instance.Add(new Animation ( new Animation.Delay(1.5f), new Animation.Execute(delegate() { int notes = Note.UncollectedCount; if (notes > 0) { this.main.Menu.HideMessage(WorldFactory.Instance, this.main.Menu.ShowMessageFormat(WorldFactory.Instance, notes == 1 ? "\\one note" : "\\note count", notes), 3.0f); } int orbs = Collectible.ActiveCount; if (orbs > 0) { this.main.Menu.HideMessage(WorldFactory.Instance, this.main.Menu.ShowMessageFormat(WorldFactory.Instance, orbs == 1 ? "\\one orb" : "\\orb count", orbs), 3.0f); } }) )); } WorldFactory.Instance.Add(new Animation(this.EndFlashAnimation())); this.respawnTimer = 0; this.PlayerSpawned.Execute(); this.RespawnInterval = Spawner.DefaultRespawnInterval; this.RespawnDistance = Spawner.DefaultRespawnDistance; } else { this.respawnTimer += dt; } } else { this.lastPlayerPosition = PlayerFactory.Instance.Get <Transform>().Position; } } this.mapJustLoaded = false; }
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; })); }
// Function for finding a wall to build for the player public Possibility FindWall(Vector3 position, Vector2 direction) { Voxel shortestMap = null; Voxel.Coord shortestPlayerCoord = new Voxel.Coord(); Direction shortestWallDirection = Direction.None; Direction shortestBuildDirection = Direction.None; int shortestDistance = searchDistance; EffectBlockFactory blockFactory = Factory.Get <EffectBlockFactory>(); foreach (Voxel map in Voxel.ActivePhysicsVoxels) { if (!ignoreTypes.Contains(map.Entity.Type)) { foreach (Direction absoluteWallDir in DirectionExtensions.HorizontalDirections) { Direction relativeWallDir = map.GetRelativeDirection(absoluteWallDir); Vector3 wallVector = map.GetAbsoluteVector(relativeWallDir.GetVector()); float dot = Vector2.Dot(direction, Vector2.Normalize(new Vector2(wallVector.X, wallVector.Z))); if (dot > -0.25f && dot < 0.8f) { Voxel.Coord coord = map.GetCoordinate(position).Move(relativeWallDir, 2); foreach (Direction dir in DirectionExtensions.Directions.Where(x => x.IsPerpendicular(relativeWallDir))) { for (int i = 0; i < shortestDistance; i++) { Voxel.Coord c = coord.Move(dir, i); Voxel.State state = map[c]; if (state == Voxel.States.Empty) { continue; } if (this.canBuild(state) && this.canBuild(map.GetAbsolutePosition(c))) { shortestMap = map; shortestBuildDirection = dir; shortestWallDirection = relativeWallDir; shortestDistance = i; shortestPlayerCoord = coord; } break; } } } } } } if (shortestMap != null) { // Found something to build a wall on. Direction dirU = shortestBuildDirection; Direction dirV = dirU.Cross(shortestWallDirection); Voxel.Coord startCoord = shortestPlayerCoord.Move(dirU, shortestDistance).Move(dirV, additionalWallDistance); Voxel.Coord endCoord = shortestPlayerCoord.Move(dirU, -additionalWallDistance).Move(dirV, -additionalWallDistance).Move(shortestWallDirection); return(new Possibility { Map = shortestMap, StartCoord = new Voxel.Coord { X = Math.Min(startCoord.X, endCoord.X), Y = Math.Min(startCoord.Y, endCoord.Y), Z = Math.Min(startCoord.Z, endCoord.Z) }, EndCoord = new Voxel.Coord { X = Math.Max(startCoord.X, endCoord.X), Y = Math.Max(startCoord.Y, endCoord.Y), Z = Math.Max(startCoord.Z, endCoord.Z) }, }); } return(null); }
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 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 void Go(bool overrideCooldown = false) { if (this.Rolling || this.Kicking || (main.TotalTime - this.LastRollKickEnded < coolDown && !overrideCooldown)) { return; } Matrix rotationMatrix = Matrix.CreateRotationY(this.Rotation); this.forward = -rotationMatrix.Forward; this.right = rotationMatrix.Right; this.shouldBuildFloor = false; bool instantiatedBlockPossibility = false; if (this.EnableCrouch && this.EnableRoll && !this.IsSwimming && (!this.EnableKick || !this.IsSupported || (this.LinearVelocity.Value - this.SupportVelocity.Value).Length() < 4.0f)) { // Try to roll Vector3 playerPos = this.FloorPosition + new Vector3(0, 0.5f, 0); Voxel.GlobalRaycastResult floorRaycast = this.raycastFloor(); bool nearGround = this.LinearVelocity.Value.Y < this.SupportVelocity.Value.Y + 0.1f && floorRaycast.Voxel != null; this.floorCoordinate = new Voxel.Coord(); this.floorMap = null; if (nearGround) { this.floorMap = floorRaycast.Voxel; this.floorCoordinate = floorRaycast.Coordinate.Value; } else { // Check for block possibilities foreach (BlockPredictor.Possibility block in this.Predictor.AllPossibilities) { bool first = true; foreach (Voxel.Coord coord in block.Map.Rasterize(playerPos + Vector3.Up * 2.0f, playerPos + (Vector3.Down * (this.Height + 3.0f)))) { if (coord.Between(block.StartCoord, block.EndCoord)) { if (first) { break; // If the top coord is intersecting the possible block, we're too far down into the block. Need to be at the top. } this.Predictor.InstantiatePossibility(block); instantiatedBlockPossibility = true; this.floorMap = block.Map; this.floorCoordinate = coord; this.Position.Value += new Vector3(0, this.floorMap.GetAbsolutePosition(coord).Y + 2 - this.FloorPosition.Value.Y, 0); this.shouldBuildFloor = true; nearGround = true; break; } first = false; } if (nearGround) { break; } } } if (nearGround) { // We're rolling. this.Rolling.Value = true; Session.Recorder.Event(main, "Roll"); this.DeactivateWallRun.Execute(); this.EnableWalking.Value = false; this.LockRotation.Execute(); this.Footstep.Execute(); // We just landed; play a footstep sound AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_ROLL, this.Entity); this.model.StartClip("Roll", 5, false, AnimatedModel.DefaultBlendTime); Voxel.State floorState = floorRaycast.Voxel == null ? Voxel.States.Empty : floorRaycast.Coordinate.Value.Data; if (this.EnableEnhancedRollSlide && (instantiatedBlockPossibility || (this.IsSupported && floorState != Voxel.States.Slider && floorState != Voxel.States.SliderPowered))) { this.shouldBuildFloor |= this.determineShouldBuildFloor(floorRaycast.Voxel, floorState); } // If the player is not yet supported, that means they're just about to land. // So give them a little speed boost for having such good timing. this.velocity = this.SupportVelocity + this.forward * this.MaxSpeed * (this.IsSupported ? 0.75f : 1.25f); this.LinearVelocity.Value = new Vector3(this.velocity.X, instantiatedBlockPossibility ? 0.0f : this.LinearVelocity.Value.Y, this.velocity.Z); // Crouch this.Crouched.Value = true; this.AllowUncrouch.Value = false; this.rightDir = this.floorMap.GetRelativeDirection(this.right); this.forwardDir = this.floorMap.GetRelativeDirection(this.forward); this.rollKickTime = 0.0f; this.firstTimeBreak = true; this.LastRollStarted.Value = this.main.TotalTime; } } if (!this.Rolling && this.EnableCrouch && this.EnableKick && this.CanKick && !this.Kicking && !this.IsSwimming && Vector3.Dot(this.LinearVelocity.Value - this.SupportVelocity, this.forward) > 0.05f) { // Kick this.Kicking.Value = true; this.CanKick.Value = false; Session.Recorder.Event(main, "Kick"); this.DeactivateWallRun.Execute(); this.EnableWalking.Value = false; this.LockRotation.Execute(); this.Crouched.Value = true; this.AllowUncrouch.Value = false; Vector3 playerPos = this.FloorPosition + new Vector3(0, 0.5f, 0); this.sliding = false; Voxel.GlobalRaycastResult floorRaycast = this.raycastFloor(); this.floorMap = floorRaycast.Voxel; if (instantiatedBlockPossibility) { this.sliding = true; this.shouldBuildFloor = true; } else if (this.floorMap == null) { this.shouldBuildFloor = false; this.sliding = false; this.floorCoordinate = new Voxel.Coord(); } else if (this.LinearVelocity.Value.Y - this.SupportVelocity.Value.Y < 1.0f) { this.floorCoordinate = floorRaycast.Coordinate.Value; if (this.EnableEnhancedRollSlide) { this.shouldBuildFloor |= this.determineShouldBuildFloor(floorRaycast.Voxel, floorRaycast.Coordinate.Value.Data); } this.sliding = true; } float forwardSpeed = Vector3.Dot(this.forward, this.LinearVelocity.Value - this.SupportVelocity); if (forwardSpeed < this.MaxSpeed * 1.1f) { if (this.sliding) { this.velocity = this.LinearVelocity.Value + this.forward * (this.MaxSpeed - forwardSpeed); } else { this.velocity = this.LinearVelocity.Value + this.forward * Math.Max(4.0f, forwardSpeed * 0.4f) + new Vector3(0, this.JumpSpeed * 0.2f, 0); } } else { this.velocity = this.LinearVelocity; } if (this.sliding) { this.velocity.Y = 0.0f; } this.LinearVelocity.Value = this.velocity; this.model.StartClip(this.sliding ? "Slide" : "Kick", 5, false, AnimatedModel.DefaultBlendTime); AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_SLIDE, this.Entity); if (this.sliding) // We're sliding on the floor { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_SLIDE_LOOP, this.Entity); } this.forwardDir = Direction.None; this.rightDir = Direction.None; if (this.floorMap != null) { this.forwardDir = this.floorMap.GetRelativeDirection(this.forward); this.rightDir = this.floorMap.GetRelativeDirection(this.right); } this.rollKickTime = 0.0f; this.firstTimeBreak = true; } }
public override void Initialize(Voxel.State fillType, int radius) { base.Initialize(fillType, radius); sqrRadius = radius * radius; }