public void Setup(Entity map, Voxel.Coord c, Voxel.t s) { this.TargetVoxel = map; this.Coord = c; this.StateId = s; this.addEntry(); }
public float Sample(Voxel voxel, Voxel.Coord coord, float octave) { coord.X -= voxel.MinX; coord.Y -= voxel.MinY; coord.Z -= voxel.MinZ; return(this.noise3d(new Vector3(coord.X / octave, coord.Y / octave, coord.Z / octave))); }
private static CandidateStatus checkAdjacent(Voxel v, Voxel.Coord coord, Direction up, Direction backward, Direction right) { if (v[coord.Move(backward)] != Voxel.States.Empty || v[coord.Move(up).Move(backward)] != Voxel.States.Empty || v[coord.Move(up, 2).Move(backward)] != Voxel.States.Empty || v[coord.Move(up, 3).Move(backward)] != Voxel.States.Empty || v[coord.Move(up)] != Voxel.States.Empty || v[coord.Move(up, 2)] != Voxel.States.Empty || v[coord.Move(up, 3)] != Voxel.States.Empty) { return(CandidateStatus.Bad); } else if (v[coord.Move(right, -1).Move(up)] != Voxel.States.Empty || v[coord.Move(right, -1).Move(up, 2)] != Voxel.States.Empty || v[coord.Move(right, -1).Move(up, 3)] != Voxel.States.Empty || v[coord.Move(right).Move(up)] != Voxel.States.Empty || v[coord.Move(right).Move(up, 2)] != Voxel.States.Empty || v[coord.Move(right).Move(up, 3)] != Voxel.States.Empty) { return(CandidateStatus.Uneven); } else { return(CandidateStatus.Good); } }
private void populateCoords() { if (this.Coords.Length == 0) { Voxel map = this.Entity.Get <Voxel>(); Entity targetEntity = this.Target.Value.Target; if (targetEntity != null && targetEntity.Active) { Voxel m = targetEntity.Get <Voxel>(); lock (map.MutationLock) { foreach (CoordinateEntry e in map.Chunks.SelectMany(c => c.Boxes.SelectMany(x => x.GetCoords())).Select(delegate(Voxel.Coord y) { Voxel.Coord z = m.GetCoordinate(map.GetAbsolutePosition(y)); z.Data = y.Data; return(new CoordinateEntry { Coord = z, }); })) { this.Coords.Add(e); } } } } }
public static void Consolidate(Main main, DynamicVoxel voxel, float interval = 1.0f) { int maxDistance = 12; Voxel closestVoxel = null; Voxel.Coord closestCoord = new Voxel.Coord(); foreach (Voxel m in Voxel.ActivePhysicsVoxels) { if (m == voxel) { continue; } Voxel.Coord relativeCoord = m.GetCoordinate(voxel.Transform.Value.Translation); Voxel.Coord?closestFilled = m.FindClosestFilledCell(relativeCoord, maxDistance); if (closestFilled != null) { maxDistance = Math.Min(Math.Abs(relativeCoord.X - closestFilled.Value.X), Math.Min(Math.Abs(relativeCoord.Y - closestFilled.Value.Y), Math.Abs(relativeCoord.Z - closestFilled.Value.Z))); closestVoxel = m; closestCoord = closestFilled.Value; } } if (closestVoxel != null) { VoxelRip.Consolidate(main, voxel, closestVoxel, closestCoord, interval); } }
public override void Start() { if (this.Enabled && !this.main.EditorEnabled) { if (this.AttachedVoxel.Value.Target == null) { Vector3 target = Vector3.Transform(new Vector3(0, 0, this.Offset), this.Transform); Entity closestMap = null; float closestFloatDistance = 3.0f; foreach (SceneryBlock block in SceneryBlock.All) { Vector3 pos = block.Entity.Get <Transform>().Position; float distance = (pos - target).Length(); if (distance < closestFloatDistance) { closestFloatDistance = distance; closestMap = block.Entity; } } int closestDistance = (int)Math.Floor(closestFloatDistance); foreach (Voxel m in Voxel.Voxels) { SliderCommon s = m.Entity.Get <SliderCommon>(); Vector3 relativeTarget = Vector3.Transform(target, Matrix.Invert(s != null ? s.OriginalTransform : m.Transform)) + m.Offset; Voxel.Coord targetCoord = m.GetCoordinateFromRelative(relativeTarget); Voxel.Coord? c = m.FindClosestFilledCell(targetCoord, closestDistance); if (c.HasValue) { float distance = (m.GetRelativePosition(c.Value) - m.GetRelativePosition(targetCoord)).Length(); if (distance < closestFloatDistance) { closestFloatDistance = distance; closestDistance = (int)Math.Floor(distance); closestMap = m.Entity; } } } if (closestMap == null) { this.Detach.Execute(); } else { this.AttachedVoxel.Value = closestMap; } } else { this.AttachedVoxel.Reset(); } } }
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 MoveTo(Voxel.Coord coord, Voxel map = null) { this.LastCoord.Value = this.Coord; this.LastVoxel.Value = this.Voxel; if (map != null) { this.Voxel.Value = map.Entity; } this.Coord.Value = coord; this.Blend.Value = 0.0f; }
private bool isInQueue(Entity m, Voxel.Coord c, bool removing) { for (int i = 0; i < this.BlockQueue.Count; i++) { ScheduledBlock b = this.BlockQueue[i]; if (b.Removing == removing && m == b.Voxel.Target && b.Coordinate.Equivalent(c)) { return(true); } } return(false); }
// Search for nearby boxes that meet a filter criteria within a vaguely defined radius public static Voxel.Box BroadphaseSearch(Voxel v, Voxel.Coord coord, int radius, Func <Voxel.Box, bool> filter) { Queue <Voxel.Box> queue = new Queue <Voxel.Box>(); Dictionary <Voxel.Box, int> visited = new Dictionary <Voxel.Box, int>(); Voxel.Box startBox = v.GetBox(coord); if (startBox == null) { return(null); } queue.Enqueue(startBox); visited[startBox] = 0; 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 && coord.X >= adjacent.X - radius && coord.X < adjacent.X + adjacent.Width + radius && coord.Y >= adjacent.Y - radius && coord.Y < adjacent.Y + adjacent.Height + radius && coord.Z >= adjacent.Z - radius && coord.Z < adjacent.Z + adjacent.Depth + radius) { if (filter(adjacent)) { return(adjacent); } else { queue.Enqueue(adjacent); } } } } } } return(null); }
// ========================= // Procedural generation of a voxel environment based on the above noise functions. // ========================= // This is the density function that builds the environment. // We sample the noise function at different octaves and combine them together. // If its value sampled at a certain voxel cell is above a certain threshold, // we fill in that voxel cell. private float density(Voxel.Coord sample) { Vector3 sampleVector = new Vector3(sample.X, sample.Y, sample.Z); // First octave float value = this.noise3d(sampleVector / this.PrimaryOctave1); // Second octave value += this.noise3d(sampleVector / this.PrimaryOctave2) * 0.8f; // Third octave value += this.noise3d(sampleVector / this.PrimaryOctave3) * 0.4f; return(value); }
public override void Awake() { base.Awake(); AkGameObjectTracker.Attach(this.Entity, this.Position); this.particles = ParticleSystem.Get(this.main, "Rift"); this.EnabledInEditMode = false; this.EnabledWhenPaused = false; this.Add(new CommandBinding(this.Enable, delegate() { if (this.Coords.Length == 0) { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_RIFT_OPEN, this.Entity); if (PlayerFactory.Instance != null) { PlayerFactory.Instance.Get <CameraController>().Shake.Execute(this.Position, 30.0f); } Entity voxelEntity = this.Voxel.Value.Target; if (voxelEntity != null && voxelEntity.Active) { Voxel v = voxelEntity.Get <Voxel>(); Voxel.Coord center = this.Coordinate; Vector3 pos = v.GetRelativePosition(center); int radius = this.Radius; List <VoxelFill.CoordinateEntry> coords = Rift.coordSortCache; for (Voxel.Coord x = center.Move(Direction.NegativeX, radius); x.X < center.X + radius; x.X++) { for (Voxel.Coord y = x.Move(Direction.NegativeY, radius); y.Y < center.Y + radius; y.Y++) { for (Voxel.Coord z = y.Move(Direction.NegativeZ, radius); z.Z < center.Z + radius; z.Z++) { float distance = (pos - v.GetRelativePosition(z)).Length(); if (distance <= radius && v[z] != Components.Voxel.States.Empty) { coords.Add(new VoxelFill.CoordinateEntry { Coord = z.Clone(), Distance = distance }); } } } } coords.Sort(new LambdaComparer <VoxelFill.CoordinateEntry>((x, y) => x.Distance.CompareTo(y.Distance))); this.Coords.AddAll(coords.Select(x => x.Coord)); coords.Clear(); } } })); rifts.Add(this); }
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 go() { if (this.Coords.Length == 0) { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_RIFT_OPEN, this.Entity); if (PlayerFactory.Instance != null) { PlayerFactory.Instance.Get <CameraController>().Shake.Execute(this.Position, 30.0f); } Entity voxelEntity = this.Voxel.Value.Target; if (voxelEntity != null && voxelEntity.Active) { Voxel v = voxelEntity.Get <Voxel>(); Voxel.Coord center = this.Coordinate; Vector3 pos = v.GetRelativePosition(center); int radius = this.Radius; List <VoxelFill.CoordinateEntry> coords = Rift.coordSortCache; for (Voxel.Coord x = center.Move(Direction.NegativeX, radius); x.X < center.X + radius; x.X++) { for (Voxel.Coord y = x.Move(Direction.NegativeY, radius); y.Y < center.Y + radius; y.Y++) { for (Voxel.Coord z = y.Move(Direction.NegativeZ, radius); z.Z < center.Z + radius; z.Z++) { float distance = (pos - v.GetRelativePosition(z)).Length(); if (distance <= radius && v[z] != Components.Voxel.States.Empty) { coords.Add(new VoxelFill.CoordinateEntry { Coord = z.Clone(), Distance = distance }); } } } } if (coords.Count == 0) { this.Entity.Delete.Execute(); } else { coords.Sort(new LambdaComparer <VoxelFill.CoordinateEntry>((x, y) => x.Distance.CompareTo(y.Distance))); this.Coords.AddAll(coords.Select(x => x.Coord)); coords.Clear(); } } } }
public void Update(float dt) { if (this.mover != null) { Entity parentEntity = this.Parent.Value.Target; if (parentEntity != null && parentEntity.Active) { Voxel parentMap = parentEntity.Get <Voxel>(); Voxel.Coord coord = this.Coord; this.mover.TargetPosition = parentMap.GetAbsolutePosition(new Vector3(coord.X + 1.0f, coord.Y + 1.0f, coord.Z + 1.0f)); } else { if (this.mover != null && this.mover.Space != null) { this.main.Space.Remove(this.mover); } this.mover = null; } } }
private void updatePower() { Entity v = this.AttachedVoxel.Value.Target; bool powered = false; if (v != null) { Voxel voxel = v.Get <Voxel>(); Voxel.Coord coord = this.Coord; for (int i = 0; i < 6; i++) { Direction dir = DirectionExtensions.Directions[i]; if (voxel[coord.Move(dir)].ID == this.Type) { powered = true; break; } } } this.Powered.Value = powered; }
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 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); }
// Classic 3D perlin noise float noise3d(Vector3 pos) { Voxel.Coord cell = new Voxel.Coord { X = (int)Math.Floor(pos.X) & 255, Y = (int)Math.Floor(pos.Y) & 255, Z = (int)Math.Floor(pos.Z) & 255 }; pos.X = pos.X % 256; pos.Y = pos.Y % 256; pos.Z = pos.Z % 256; Vector3 withinCell = pos - new Vector3(cell.X, cell.Y, cell.Z); // Calculate contribution of gradients from each cell float contribution000 = Vector3.Dot(this.gradientAtCell3d(cell), withinCell); float contribution001 = Vector3.Dot(this.gradientAtCell3d(cell.Move(0, 0, 1)), withinCell - new Vector3(0, 0, 1)); float contribution010 = Vector3.Dot(this.gradientAtCell3d(cell.Move(0, 1, 0)), withinCell - new Vector3(0, 1, 0)); float contribution011 = Vector3.Dot(this.gradientAtCell3d(cell.Move(0, 1, 1)), withinCell - new Vector3(0, 1, 1)); float contribution100 = Vector3.Dot(this.gradientAtCell3d(cell.Move(1, 0, 0)), withinCell - new Vector3(1, 0, 0)); float contribution101 = Vector3.Dot(this.gradientAtCell3d(cell.Move(1, 0, 1)), withinCell - new Vector3(1, 0, 1)); float contribution110 = Vector3.Dot(this.gradientAtCell3d(cell.Move(1, 1, 0)), withinCell - new Vector3(1, 1, 0)); float contribution111 = Vector3.Dot(this.gradientAtCell3d(cell.Move(1, 1, 1)), withinCell - new Vector3(1, 1, 1)); Vector3 blend = new Vector3(blendCurve(withinCell.X), blendCurve(withinCell.Y), blendCurve(withinCell.Z)); // Interpolate along X float contribution00 = lerp(contribution000, contribution100, blend.X); float contribution01 = lerp(contribution001, contribution101, blend.X); float contribution10 = lerp(contribution010, contribution110, blend.X); float contribution11 = lerp(contribution011, contribution111, blend.X); // Interpolate along Y float contribution0 = lerp(contribution00, contribution10, blend.Y); float contribution1 = lerp(contribution01, contribution11, blend.Y); // Interpolate along Z return(lerp(contribution0, contribution1, blend.Z)); }
public static void Consolidate(Main main, DynamicVoxel voxel, float interval = 1.0f) { int maxDistance = 12; Voxel closestVoxel = null; Voxel.Coord closestCoord = new Voxel.Coord(); foreach (Voxel m in Voxel.ActivePhysicsVoxels) { if (m == voxel) continue; Voxel.Coord relativeCoord = m.GetCoordinate(voxel.Transform.Value.Translation); Voxel.Coord? closestFilled = m.FindClosestFilledCell(relativeCoord, maxDistance); if (closestFilled != null) { maxDistance = Math.Min(Math.Abs(relativeCoord.X - closestFilled.Value.X), Math.Min(Math.Abs(relativeCoord.Y - closestFilled.Value.Y), Math.Abs(relativeCoord.Z - closestFilled.Value.Z))); closestVoxel = m; closestCoord = closestFilled.Value; } } if (closestVoxel != null) VoxelRip.Consolidate(main, voxel, closestVoxel, closestCoord, interval); }
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 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 bool Activate(State state, bool checkPossibilities) { if (!this.EnableWallRun) { return(false); } Vector3 playerVelocity = this.LinearVelocity.Value; if (playerVelocity.Y < FallDamage.RollingDamageVelocity) { return(false); } if (this.IsSwimming) { if (state == State.Left || state == State.Right) { return(false); } } wallInstantiationTimer = 0.0f; // Prevent the player from repeatedly wall-running and wall-jumping ad infinitum. bool wallRunDelayPassed = main.TotalTime - this.lastWallRunEnded > wallRunDelay; bool wallRunJumpDelayPassed = main.TotalTime - this.LastWallJump > wallRunDelay; Matrix matrix = Matrix.CreateRotationY(this.Rotation); Vector3 forwardVector = -matrix.Forward; Vector3 wallVector; switch (state) { case State.Straight: wallVector = forwardVector; break; case State.Left: if (!this.EnableWallRunHorizontal) { return(false); } wallVector = -matrix.Left; break; case State.Right: if (!this.EnableWallRunHorizontal) { return(false); } wallVector = -matrix.Right; break; default: wallVector = Vector3.Zero; break; } Vector3 pos = this.Position + new Vector3(0, this.Height * -0.5f, 0); // Attempt to wall-run on an existing map bool addInitialVelocity = false; Voxel closestVoxel = null; Voxel.Coord closestCoord = default(Voxel.Coord); const int maxWallDistance = 4; int closestDistance = maxWallDistance; Direction closestDir = Direction.None; foreach (Voxel voxel in Voxel.ActivePhysicsVoxels) { Vector3 baseVelocity = voxel.LinearVelocity + Vector3.Cross(voxel.AngularVelocity, this.Position - voxel.Transform.Value.Translation); Vector3 v = Vector3.Normalize(playerVelocity - baseVelocity); v.Y = 0.0f; if (Vector3.Dot(forwardVector, v) < -0.3f) { continue; } Voxel.Coord coord = voxel.GetCoordinate(pos); Direction dir = voxel.GetRelativeDirection(wallVector); Direction up = voxel.GetRelativeDirection(Direction.PositiveY); Direction forwardDir = voxel.GetRelativeDirection(forwardVector); for (int i = 1; i < maxWallDistance; i++) { Voxel.Coord wallCoord = coord.Move(dir, i); if (voxel[coord.Move(dir, i - 1)] != Voxel.States.Empty || voxel[coord.Move(dir, i - 1).Move(up, 1)] != Voxel.States.Empty || voxel[coord.Move(dir, i - 1).Move(up, 2)] != Voxel.States.Empty || ((state == State.Left || state == State.Right) && (voxel[coord.Move(forwardDir).Move(dir, i - 1)] != Voxel.States.Empty || voxel[coord.Move(forwardDir).Move(dir, i - 1).Move(up, 1)] != Voxel.States.Empty || voxel[coord.Move(forwardDir).Move(dir, i - 1).Move(up, 2)] != Voxel.States.Empty))) { // Blocked break; } // Need at least two blocks to consider it a wall if (voxel[wallCoord].ID != 0 && voxel[wallCoord.Move(up)].ID != 0) { bool differentWall = voxel != this.LastWallRunMap.Value || dir != this.LastWallDirection.Value; if ((differentWall || wallRunJumpDelayPassed) && i < closestDistance) { closestVoxel = voxel; closestDistance = i; closestCoord = coord; closestDir = dir; addInitialVelocity = differentWall || wallRunDelayPassed; } } else if (checkPossibilities) { // Check block possibilities List <BlockPredictor.Possibility> mapBlockPossibilities = this.Predictor.GetPossibilities(voxel); if (mapBlockPossibilities != null) { foreach (BlockPredictor.Possibility block in mapBlockPossibilities) { if (wallCoord.Between(block.StartCoord, block.EndCoord)) { this.Predictor.InstantiatePossibility(block); this.Predictor.ClearPossibilities(); closestVoxel = voxel; closestDistance = i; closestCoord = coord; closestDir = dir; addInitialVelocity = true; wallInstantiationTimer = 0.25f; break; } } } } } } if (closestVoxel != null) { if (!addInitialVelocity && Vector3.Dot(forwardVector, playerVelocity) < minWallRunSpeed) { return(false); } this.Position.Value = closestVoxel.GetAbsolutePosition(closestCoord.Move(closestDir, closestDistance - 2)) + new Vector3(0, this.Height * 0.5f, 0); this.setup(closestVoxel, closestDir, state, forwardVector, addInitialVelocity); return(true); } return(false); }
// Classic 3D perlin noise float noise3d(Vector3 pos) { Voxel.Coord cell = new Voxel.Coord { X = (int)Math.Floor(pos.X) & 255, Y = (int)Math.Floor(pos.Y) & 255, Z = (int)Math.Floor(pos.Z) & 255 }; pos.X = pos.X % 256; pos.Y = pos.Y % 256; pos.Z = pos.Z % 256; Vector3 withinCell = pos - new Vector3(cell.X, cell.Y, cell.Z); // Calculate contribution of gradients from each cell float contribution000 = Vector3.Dot(this.gradientAtCell3d(cell), withinCell); float contribution001 = Vector3.Dot(this.gradientAtCell3d(cell.Move(0, 0, 1)), withinCell - new Vector3(0, 0, 1)); float contribution010 = Vector3.Dot(this.gradientAtCell3d(cell.Move(0, 1, 0)), withinCell - new Vector3(0, 1, 0)); float contribution011 = Vector3.Dot(this.gradientAtCell3d(cell.Move(0, 1, 1)), withinCell - new Vector3(0, 1, 1)); float contribution100 = Vector3.Dot(this.gradientAtCell3d(cell.Move(1, 0, 0)), withinCell - new Vector3(1, 0, 0)); float contribution101 = Vector3.Dot(this.gradientAtCell3d(cell.Move(1, 0, 1)), withinCell - new Vector3(1, 0, 1)); float contribution110 = Vector3.Dot(this.gradientAtCell3d(cell.Move(1, 1, 0)), withinCell - new Vector3(1, 1, 0)); float contribution111 = Vector3.Dot(this.gradientAtCell3d(cell.Move(1, 1, 1)), withinCell - new Vector3(1, 1, 1)); Vector3 blend = new Vector3(blendCurve(withinCell.X), blendCurve(withinCell.Y), blendCurve(withinCell.Z)); // Interpolate along X float contribution00 = lerp(contribution000, contribution100, blend.X); float contribution01 = lerp(contribution001, contribution101, blend.X); float contribution10 = lerp(contribution010, contribution110, blend.X); float contribution11 = lerp(contribution011, contribution111, blend.X); // Interpolate along Y float contribution0 = lerp(contribution00, contribution10, blend.Y); float contribution1 = lerp(contribution01, contribution11, blend.Y); // Interpolate along Z return lerp(contribution0, contribution1, blend.Z); }
private void setup(Voxel voxel, Direction dir, State state, Vector3 forwardVector, bool addInitialVelocity, bool rotationAlreadyLocked = false) { this.StopKick.Execute(); this.AllowUncrouch.Value = true; this.WallRunVoxel.Value = this.LastWallRunMap.Value = voxel; this.WallDirection.Value = this.LastWallDirection.Value = dir; this.lastWallRunCoord = new Voxel.Coord { X = int.MinValue, Y = int.MinValue, Z = int.MinValue }; Vector3 baseVelocity = voxel.LinearVelocity + Vector3.Cross(voxel.AngularVelocity, this.Position - voxel.Transform.Value.Translation); if (state == State.Straight) { // Determine if we're actually going down if (!this.IsSupported && this.LinearVelocity.Value.Y - baseVelocity.Y < -0.5f) { state = State.Down; } } this.CurrentState.Value = state; Session.Recorder.Event(main, "WallRun", this.CurrentState.Value.ToString()); this.WallRunDirection.Value = state == State.Straight ? voxel.GetRelativeDirection(Vector3.Up) : (state == State.Down ? voxel.GetRelativeDirection(Vector3.Down) : dir.Cross(voxel.GetRelativeDirection(Vector3.Up))); if (state == State.Straight || state == State.Down) { if (state == State.Straight) { Vector3 velocity = this.LinearVelocity.Value; velocity.X = baseVelocity.X; velocity.Z = baseVelocity.Z; if (addInitialVelocity) { velocity.Y = Math.Max(this.JumpSpeed * 1.3f, (this.LinearVelocity.Value.Y * 1.4f) + this.JumpSpeed * 0.5f); } else { velocity.Y = this.LinearVelocity.Value.Y; } this.LinearVelocity.Value = velocity; this.IsSupported.Value = false; this.HasTraction.Value = false; } Vector3 wallVector = this.WallRunVoxel.Value.GetAbsoluteVector(this.WallDirection.Value.GetVector()); // Make sure we lock in the correct rotation value float rotation = (float)Math.Atan2(wallVector.X, wallVector.Z); if (rotationAlreadyLocked) { this.UpdateLockedRotation.Execute(rotation); } else { this.Rotation.Value = rotation; this.LockRotation.Execute(); } } else { this.IsSupported.Value = false; this.HasTraction.Value = false; Vector3 velocity = voxel.GetAbsoluteVector(this.WallRunDirection.Value.GetVector()); if (Vector3.Dot(velocity, forwardVector) < 0.0f) { velocity = -velocity; this.WallRunDirection.Value = this.WallRunDirection.Value.GetReverse(); } float rotation = (float)Math.Atan2(velocity.X, velocity.Z); if (rotationAlreadyLocked) { this.UpdateLockedRotation.Execute(rotation); } else { this.Rotation.Value = rotation; this.LockRotation.Execute(); } if (addInitialVelocity) { velocity.Y = 0; float length = velocity.Length(); if (length > 0) { velocity /= length; Vector3 currentHorizontalVelocity = this.LinearVelocity - baseVelocity; float currentVerticalSpeed = currentHorizontalVelocity.Y; currentHorizontalVelocity.Y = 0.0f; float horizontalSpeed = currentHorizontalVelocity.Length(); velocity *= Math.Min(this.MaxSpeed * 1.4f, Math.Max(horizontalSpeed * 1.1f, 6.0f)); if (Vector3.Dot(velocity - baseVelocity, forwardVector) < minWallRunSpeed + 1.0f) { velocity += forwardVector * ((minWallRunSpeed + 2.0f) - Vector3.Dot(velocity - baseVelocity, forwardVector)); } velocity += baseVelocity; velocity.Y = (currentVerticalSpeed > -10.0f ? Math.Max(currentVerticalSpeed * 0.5f, 0.0f) + velocity.Length() * 0.6f : currentVerticalSpeed * 0.5f + 3.0f); this.LinearVelocity.Value = velocity; this.LastSupportedSpeed.Value = Vector3.Dot(velocity, forwardVector); } } } if (this.CurrentState != State.Straight) { AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PLAYER_SLIDE_LOOP, this.Entity); } }
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; }
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); lock (voxel.MutationLock) { 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; lock (voxel.MutationLock) 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 void Update(float dt) { if (this.Coords.Length == 0) { this.go(); } else if (this.CurrentIndex < this.Coords.Length) { if (this.voxel == null) { Entity v = this.Voxel.Value.Target; if (v != null && v.Active) { this.voxel = v.Get <Voxel>(); } } else if (this.voxel.Active) { this.intervalTimer += dt; if (this.Type == Style.In) { this.particleIntervalTimer += dt; while (this.particleIntervalTimer > particleInterval) { this.particleIntervalTimer -= particleInterval; this.particles.AddParticle(this.Position, Vector3.Zero, -1.0f, this.CurrentRadius * 2.0f); } this.soundIntervalTimer += dt; while (this.soundIntervalTimer > soundInterval) { this.soundIntervalTimer -= soundInterval; AkSoundEngine.PostEvent(AK.EVENTS.PLAY_RIFT, this.Entity); } } bool regenerate = false; if (this.intervalTimer > batchInterval) { for (int i = 0; i < batch && this.CurrentIndex < this.Coords.Length; i++) { Voxel.Coord c = this.Coords[this.CurrentIndex]; if ((c.Data = this.voxel[c]) != Components.Voxel.States.Empty) { regenerate = true; this.removals.Add(c); } this.CurrentIndex.Value++; } } if (regenerate) { this.intervalTimer -= batchInterval; this.voxel.Empty(this.removals, true, true); foreach (Voxel.Coord c in this.removals) { if (this.Type == Style.In) { this.blockFactory.Implode(main, this.voxel, c, c.Data, this.Position); } else { this.blockFactory.BlowAway(main, this.voxel, c, c.Data); } } this.removals.Clear(); this.voxel.Regenerate(); } this.CurrentRadius.Value = (this.voxel.GetRelativePosition(this.Coords[Math.Max(0, this.CurrentIndex - 1)]) - this.voxel.GetRelativePosition(this.Coordinate)).Length(); } else { this.Entity.Delete.Execute(); } } else { this.Entity.Delete.Execute(); } if (this.Type.Value == Style.In) { Entity player = PlayerFactory.Instance; if (player != null && (player.Get <Transform>().Position.Value - this.Position.Value).Length() < this.CurrentRadius) { player.Get <Agent>().Damage.Execute(dt * damageTime); } } }
public static bool Broadphase(Voxel m, Voxel.Box start, Voxel.Coord target, Func <Voxel.State, bool> filter, Stack <Voxel.Box> result, int maxIterations = 50) { BroadphaseEntry closestEntry = null; bool found = false; lock (m.MutationLock) { Vector3 targetPos = m.GetRelativePosition(target); BroadphaseEntry startEntry = new BroadphaseEntry { Parent = null, Box = start, G = 0, F = (targetPos - start.GetCenter()).Length(), BoxSize = Math.Max(start.Width, Math.Max(start.Height, start.Depth)), }; broadphaseQueue.Push(startEntry); broadphaseQueueLookup[start] = startEntry; float closestHeuristic = float.MaxValue; int iterations = 0; while (broadphaseQueue.Count > 0 && iterations < maxIterations) { iterations++; BroadphaseEntry entry = broadphaseQueue.Pop(); if (entry.Box.Contains(target)) { closestEntry = entry; found = true; break; } broadphaseQueueLookup.Remove(entry.Box); broadphaseClosed[entry.Box] = entry.G; lock (entry.Box.Adjacent) { for (int i = 0; i < entry.Box.Adjacent.Count; i++) { Voxel.Box adjacent = entry.Box.Adjacent[i]; if (adjacent == null || !filter(adjacent.Type)) { continue; } int boxSize = (int)((adjacent.Width + adjacent.Height + adjacent.Depth) / 3.0f); int tentativeGScore = entry.G + boxSize; int previousGScore; bool hasPreviousGScore = broadphaseClosed.TryGetValue(adjacent, out previousGScore); if (hasPreviousGScore && tentativeGScore > previousGScore) { continue; } BroadphaseEntry alreadyInQueue; broadphaseQueueLookup.TryGetValue(adjacent, out alreadyInQueue); if (alreadyInQueue == null || tentativeGScore < previousGScore) { BroadphaseEntry newEntry = alreadyInQueue != null ? alreadyInQueue : new BroadphaseEntry(); newEntry.Parent = entry; newEntry.G = tentativeGScore; float heuristic = (targetPos - adjacent.GetCenter()).Length(); newEntry.F = tentativeGScore + heuristic; if (heuristic < closestHeuristic) { closestEntry = newEntry; closestHeuristic = heuristic; } if (alreadyInQueue == null) { newEntry.Box = adjacent; newEntry.BoxSize = boxSize; broadphaseQueue.Push(newEntry); broadphaseQueueLookup[adjacent] = newEntry; } } } } } } broadphaseClosed.Clear(); broadphaseQueue.Clear(); broadphaseQueueLookup.Clear(); if (closestEntry != null) { VoxelAStar.reconstructBroadphasePath(closestEntry, result); } return(found); }
public static void Narrowphase(Voxel m, Voxel.Coord start, Voxel.Box target, Stack <Voxel.Coord> result) { Voxel.Box currentBox = m.GetBox(start); Vector3 targetPos = target.GetCenter(); NarrowphaseEntry startEntry = new NarrowphaseEntry { Parent = null, Coord = start, G = 0, F = (targetPos - m.GetRelativePosition(start)).Length(), }; narrowphaseQueue.Push(startEntry); narrowphaseQueueLookup[start] = startEntry; NarrowphaseEntry closestEntry = null; float closestHeuristic = float.MaxValue; int iterations = 0; while (narrowphaseQueue.Count > 0 && iterations < 80) { iterations++; NarrowphaseEntry entry = narrowphaseQueue.Pop(); if (m.GetBox(entry.Coord) == target) { closestEntry = entry; break; } narrowphaseQueueLookup.Remove(entry.Coord); narrowphaseClosed[entry.Coord] = entry.G; for (int i = 0; i < 6; i++) { Voxel.Coord adjacent = entry.Coord.Move(DirectionExtensions.Directions[i]); if (!currentBox.Contains(adjacent) && !target.Contains(adjacent)) { continue; } int tentativeGScore = entry.G + 1; int previousGScore; bool hasPreviousGScore = narrowphaseClosed.TryGetValue(adjacent, out previousGScore); if (hasPreviousGScore && tentativeGScore > previousGScore) { continue; } NarrowphaseEntry alreadyInQueue; narrowphaseQueueLookup.TryGetValue(adjacent, out alreadyInQueue); if (alreadyInQueue == null || tentativeGScore < previousGScore) { NarrowphaseEntry newEntry = alreadyInQueue != null ? alreadyInQueue : new NarrowphaseEntry(); newEntry.Parent = entry; newEntry.G = tentativeGScore; float heuristic = (targetPos - m.GetRelativePosition(adjacent)).Length(); newEntry.F = tentativeGScore + heuristic; if (heuristic < closestHeuristic) { closestEntry = newEntry; closestHeuristic = heuristic; } if (alreadyInQueue == null) { newEntry.Coord = adjacent; narrowphaseQueue.Push(newEntry); narrowphaseQueueLookup[adjacent] = newEntry; } } } } narrowphaseClosed.Clear(); narrowphaseQueue.Clear(); narrowphaseQueueLookup.Clear(); if (closestEntry != null) { VoxelAStar.reconstructNarrowphasePath(closestEntry, result); } }
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 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; } }
// Get a psuedo-random gradient for the given 3D cell private Vector3 gradientAtCell3d(Voxel.Coord coord) { return(gradients[this.permutations[coord.X + this.permutations[coord.Y + this.permutations[coord.Z]]] % gradients.Length]); }
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); }