public Map.CellState GetValue(Map map, Map.Coordinate coord) { coord.X -= map.MinX; coord.Y -= map.MinY; coord.Z -= map.MinZ; float value = this.density(coord); if (value > this.PrimaryFillThreshold) { // We are filling in material in this cell // Determine whether to fill in with primary or secondary material Map.CellState state; if (this.density(coord.Move(0, 2, 0)) < this.PrimaryFillThreshold // We're on the top of a ground formation && this.noise3d(new Vector3(coord.X, coord.Y, coord.Z) / this.SecondaryOctave) > this.SecondaryFillThreshold) // Modulate by another noise function state = this.secondaryFillValue; else state = this.primaryFillValue; return state; } return new Map.CellState(); }
private static void explode(Main main, Map map, Map.Coordinate coord, Vector3 pos, int radius, float physicsRadius) { // Kaboom AkSoundEngine.PostEvent("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 (Map m in Map.ActiveMaps.ToList()) { List<Map.Coordinate> removals = new List<Map.Coordinate>(); Map.Coordinate c = m.GetCoordinate(pos); Vector3 relativePos = m.GetRelativePosition(c); Quaternion quat = m.Entity.Get<Transform>().Quaternion; for (Map.Coordinate x = c.Move(Direction.NegativeX, radius - 1); x.X < c.X + radius; x.X++) { for (Map.Coordinate y = x.Move(Direction.NegativeY, radius - 1); y.Y < c.Y + radius; y.Y++) { for (Map.Coordinate z = y.Move(Direction.NegativeZ, radius - 1); z.Z < c.Z + radius; z.Z++) { Map.CellState 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 = quat; s.ApplyToBlock(block); main.Add(block); } } } } } if (removals.Count > 0) { m.Empty(removals); m.Regenerate(); } } // Damage the player if (player != null && player.Active) { float d = (player.Get<Transform>().Position - pos).Length(); if (d < physicsRadius) player.Get<Player>().Health.Value -= minPlayerDamage + (1.0f - (d / physicsRadius)) * playerDamageMultiplier; } // Apply impulse to dynamic maps foreach (Map m in Map.ActiveMaps) { DynamicMap dm = m as DynamicMap; 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.LinearVelocity.Value += fromExplosion * blend * 10.0f / distance; block.AngularVelocity.Value += 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 static void Explode(Main main, Map map, Map.Coordinate coord, int radius = 8, float physicsRadius = 12.0f) { Vector3 pos = map.GetAbsolutePosition(coord); Explosion.explode(main, map, coord, pos, radius, physicsRadius); }
private static void processMap(Map map, IEnumerable<NonAxisAlignedBoundingBox> boxes) { foreach (Map.Chunk chunk in map.Chunks) { BoundingBox absoluteChunkBoundingBox = chunk.RelativeBoundingBox.Transform(map.Transform); bool active = false; foreach (NonAxisAlignedBoundingBox box in boxes) { if (box.BoundingBox.Intersects(absoluteChunkBoundingBox.Transform(box.Transform))) { active = true; break; } } if (chunk.Active && !active) chunk.Deactivate(); else if (!chunk.Active && active) chunk.Activate(); } }
/// <summary> /// If the specified location is currently filled, it is emptied. /// This change will not take effect until Generate() or Regenerate() is called. /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="z"></param> public bool Empty(int x, int y, int z, Map transferringToNewMap = null) { bool modified = false; Map.Coordinate coord = new Coordinate { X = x, Y = y, Z = z, }; lock (this.mutationLock) { Chunk chunk = this.GetChunk(x, y, z, false); if (chunk == null || (!this.main.EditorEnabled && !this.EnablePhysics)) return false; Box box = chunk.Data[x - chunk.X, y - chunk.Y, z - chunk.Z]; if (box != null && (!box.Type.Permanent || this.main.EditorEnabled)) { List<Box> boxAdditions = new List<Box>(); coord.Data = box.Type; this.removalCoords.Add(coord); this.removeBox(box); // Left if (coord.X > box.X) { Box newBox = new Box { X = box.X, Y = box.Y, Z = box.Z, Width = coord.X - box.X, Height = box.Height, Depth = box.Depth, Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } // Right if (box.X + box.Width > coord.X + 1) { Box newBox = new Box { X = coord.X + 1, Y = box.Y, Z = box.Z, Width = box.X + box.Width - (coord.X + 1), Height = box.Height, Depth = box.Depth, Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } // Bottom if (coord.Y > box.Y) { Box newBox = new Box { X = coord.X, Y = box.Y, Z = box.Z, Width = 1, Height = coord.Y - box.Y, Depth = box.Depth, Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } // Top if (box.Y + box.Height > coord.Y + 1) { Box newBox = new Box { X = coord.X, Y = coord.Y + 1, Z = box.Z, Width = 1, Height = box.Y + box.Height - (coord.Y + 1), Depth = box.Depth, Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } // Back if (coord.Z > box.Z) { Box newBox = new Box { X = coord.X, Y = coord.Y, Z = box.Z, Width = 1, Height = 1, Depth = coord.Z - box.Z, Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } // Front if (box.Z + box.Depth > coord.Z + 1) { Box newBox = new Box { X = coord.X, Y = coord.Y, Z = coord.Z + 1, Width = 1, Height = 1, Depth = box.Z + box.Depth - (coord.Z + 1), Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } modified = true; this.calculateAdjacency(boxAdditions.Where(a => a.Active)); } } if (modified) this.notifyEmptied(new Coordinate[] { coord }, transferringToNewMap); return modified; }
public bool Empty(IEnumerable<Coordinate> coords, Map transferringToNewMap = null) { bool modified = false; List<Box> boxAdditions = new List<Box>(); List<Coordinate> removed = new List<Coordinate>(); lock (this.mutationLock) { foreach (Map.Coordinate coord in coords) { Chunk chunk = this.GetChunk(coord.X, coord.Y, coord.Z, false); if (chunk == null || (!this.main.EditorEnabled && !this.EnablePhysics)) continue; Box box = chunk.Data[coord.X - chunk.X, coord.Y - chunk.Y, coord.Z - chunk.Z]; if (box != null && (!box.Type.Permanent || this.main.EditorEnabled)) { this.removalCoords.Add(coord); if (box != null) { this.removeBox(box); // Left if (coord.X > box.X) { Box newBox = new Box { X = box.X, Y = box.Y, Z = box.Z, Width = coord.X - box.X, Height = box.Height, Depth = box.Depth, Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } // Right if (box.X + box.Width > coord.X + 1) { Box newBox = new Box { X = coord.X + 1, Y = box.Y, Z = box.Z, Width = box.X + box.Width - (coord.X + 1), Height = box.Height, Depth = box.Depth, Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } // Bottom if (coord.Y > box.Y) { Box newBox = new Box { X = coord.X, Y = box.Y, Z = box.Z, Width = 1, Height = coord.Y - box.Y, Depth = box.Depth, Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } // Top if (box.Y + box.Height > coord.Y + 1) { Box newBox = new Box { X = coord.X, Y = coord.Y + 1, Z = box.Z, Width = 1, Height = box.Y + box.Height - (coord.Y + 1), Depth = box.Depth, Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } // Back if (coord.Z > box.Z) { Box newBox = new Box { X = coord.X, Y = coord.Y, Z = box.Z, Width = 1, Height = 1, Depth = coord.Z - box.Z, Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } // Front if (box.Z + box.Depth > coord.Z + 1) { Box newBox = new Box { X = coord.X, Y = coord.Y, Z = coord.Z + 1, Width = 1, Height = 1, Depth = box.Z + box.Depth - (coord.Z + 1), Type = box.Type, }; this.addBoxWithoutAdjacency(newBox); boxAdditions.Add(newBox); } removed.Add(new Map.Coordinate { X = coord.X, Y = coord.Y, Z = coord.Z, Data = box.Type }); modified = true; } } } this.calculateAdjacency(boxAdditions.Where(x => x.Active)); } if (modified) this.notifyEmptied(removed, transferringToNewMap); return modified; }
// Get a psuedo-random gradient for the given 3D cell private Vector3 gradientAtCell3d(Map.Coordinate coord) { return gradients[this.permutations[coord.X + this.permutations[coord.Y + this.permutations[coord.Z]]] % gradients.Length]; }
private void restoreMap(Map.Coordinate start, Map.Coordinate end, bool eraseOriginal, int offsetX = 0, int offsetY = 0, int offsetZ = 0) { Map map = this.SelectedEntities[0].Get<Map>(); List<Map.Coordinate> removals = new List<Map.Coordinate>(); for (int x = start.X; x < end.X; x++) { for (int y = start.Y; y < end.Y; y++) { for (int z = start.Z; z < end.Z; z++) { Map.CellState desiredState; if (eraseOriginal && x >= this.originalSelectionStart.X && x < this.originalSelectionEnd.X && y >= this.originalSelectionStart.Y && y < this.originalSelectionEnd.Y && z >= this.originalSelectionStart.Z && z < this.originalSelectionEnd.Z) desiredState = null; else desiredState = this.mapState[new Map.Coordinate { X = x + offsetX, Y = y + offsetY, Z = z + offsetZ }]; if (map[x, y, z] != desiredState) removals.Add(new Map.Coordinate { X = x, Y = y, Z = z }); } } } map.Empty(removals); for (int x = start.X; x < end.X; x++) { for (int y = start.Y; y < end.Y; y++) { for (int z = start.Z; z < end.Z; z++) { Map.CellState desiredState; if (eraseOriginal && x >= this.originalSelectionStart.X && x < this.originalSelectionEnd.X && y >= this.originalSelectionStart.Y && y < this.originalSelectionEnd.Y && z >= this.originalSelectionStart.Z && z < this.originalSelectionEnd.Z) desiredState = null; else desiredState = this.mapState[new Map.Coordinate { X = x + offsetX, Y = y + offsetY, Z = z + offsetZ }]; if (desiredState != null && map[x, y, z] != desiredState) map.Fill(x, y, z, desiredState); } } } map.Regenerate(); }
public bool Empty(Vector3 pos, Map transferringToNewMap = null) { return this.Empty(this.GetCoordinate(pos), transferringToNewMap); }
private void notifyFilled(IEnumerable<Coordinate> coords, Map transferredFromMap) { this.CellsFilled.Execute(coords, transferredFromMap); Map.GlobalCellsFilled.Execute(this, coords, transferredFromMap); }
private void notifyEmptied(IEnumerable<Coordinate> coords, Map transferringToNewMap) { this.CellsEmptied.Execute(coords, transferringToNewMap); Map.GlobalCellsEmptied.Execute(this, coords, transferringToNewMap); bool completelyEmptied = true; if (this.additions.FirstOrDefault(x => x.Active) != null) completelyEmptied = false; else { foreach (Chunk chunk in this.Chunks) { foreach (Box box in chunk.Boxes) { if (box.Active) { completelyEmptied = false; break; } } if (!completelyEmptied) break; } } if (completelyEmptied) this.CompletelyEmptied.Execute(); }
public IEnumerable<Chunk> GetChunksBetween(Map.Coordinate a, Map.Coordinate b) { a.X = Math.Max(this.minX, a.X); b.X = Math.Min(this.maxX - 1, b.X); a.Y = Math.Max(this.minY, a.Y); b.Y = Math.Min(this.maxY - 1, b.Y); a.Z = Math.Max(this.minX, a.Z); b.Z = Math.Min(this.maxX - 1, b.Z); if (b.X > a.X && b.Y > a.Y && b.Z > a.Z) { int chunkX = ((a.X - this.minX) / this.chunkSize), chunkY = ((a.Y - this.minY) / this.chunkSize), chunkZ = ((a.Z - this.minZ) / this.chunkSize); int nextChunkX = ((b.X - this.minX) / this.chunkSize), nextChunkY = ((b.Y - this.minY) / this.chunkSize), nextChunkZ = ((b.Z - this.minZ) / this.chunkSize); int numChunks = this.chunks.GetLength(0); // Same number of chunks in each dimension for (int ix = chunkX; ix <= nextChunkX; ix++) { for (int iy = chunkY; iy <= nextChunkY; iy++) { for (int iz = chunkZ; iz <= nextChunkZ; iz++) { Chunk chunk = this.chunks[ix, iy, iz]; if (chunk != null) yield return chunk; } } } } }
public static Map.Box AStar(Map m, Map.Box start, Vector3 target, out int pathLength) { Dictionary<Map.Box, int> closed = new Dictionary<Map.Box, int>(); PriorityQueue<AStarEntry> queue = new PriorityQueue<AStarEntry>(new LambdaComparer<AStarEntry>((x, y) => x.F.CompareTo(y.F))); Dictionary<Map.Box, AStarEntry> queueLookup = new Dictionary<Map.Box, AStarEntry>(); AStarEntry startEntry = new AStarEntry { Parent = null, Box = start, G = 0, F = (target - start.GetCenter()).Length(), BoxSize = Math.Max(start.Width, Math.Max(start.Height, start.Depth)), PathIndex = 0, }; queue.Push(startEntry); queueLookup[start] = startEntry; const float thresholdFCoefficient = 0.6f; const int iterationLimit = 10; int iteration = 0; while (queue.Count > 0) { AStarEntry entry = queue.Pop(); if (iteration >= iterationLimit || entry.F < entry.BoxSize * thresholdFCoefficient) return VoxelChaseAI.reconstructPath(entry, out pathLength); iteration++; queueLookup.Remove(entry.Box); closed[entry.Box] = entry.G; foreach (Map.Box adjacent in entry.Box.Adjacent.ToList()) { if (adjacent == null) continue; int boxSize = Math.Max(adjacent.Width, Math.Max(adjacent.Height, adjacent.Depth)); int tentativeGScore = entry.G + boxSize; int previousGScore; bool hasPreviousGScore = closed.TryGetValue(adjacent, out previousGScore); if (hasPreviousGScore && tentativeGScore > previousGScore) continue; AStarEntry alreadyInQueue; bool throwaway = queueLookup.TryGetValue(adjacent, out alreadyInQueue); if (alreadyInQueue == null || tentativeGScore < previousGScore) { AStarEntry newEntry = alreadyInQueue != null ? alreadyInQueue : new AStarEntry(); newEntry.Parent = entry; newEntry.G = tentativeGScore; newEntry.F = tentativeGScore + (target - adjacent.GetCenter()).Length(); newEntry.PathIndex = entry.PathIndex + 1; if (alreadyInQueue == null) { newEntry.Box = adjacent; newEntry.BoxSize = boxSize; queue.Push(newEntry); queueLookup[adjacent] = newEntry; } } } } pathLength = 0; return null; }
private static Cell filter(Map.CellState state) { return state.ID == 0 ? Cell.Empty : Cell.Filled; }
protected void brushStroke(Map map, Map.Coordinate center, int brushSize, Func<Map.Coordinate, Map.CellState> function, bool fill = true, bool empty = true) { Vector3 pos = map.GetRelativePosition(center); List<Map.Coordinate> coords = new List<Map.Coordinate>(); for (Map.Coordinate x = center.Move(Direction.NegativeX, this.BrushSize - 1); x.X < center.X + this.BrushSize; x.X++) { for (Map.Coordinate y = x.Move(Direction.NegativeY, this.BrushSize - 1); y.Y < center.Y + this.BrushSize; y.Y++) { for (Map.Coordinate z = y.Move(Direction.NegativeZ, this.BrushSize - 1); z.Z < center.Z + this.BrushSize; z.Z++) { if ((pos - map.GetRelativePosition(z)).Length() <= this.BrushSize) coords.Add(new Map.Coordinate { X = z.X, Y = z.Y, Z = z.Z, Data = function(z) }); } } } if (empty) map.Empty(coords.Where(x => x.Data.ID == 0)); if (fill) { foreach (Map.Coordinate coord in coords) map.Fill(coord, coord.Data); } }
public bool Empty(Coordinate coord, Map transferringToNewMap = null) { return this.Empty(coord.X, coord.Y, coord.Z, transferringToNewMap); }
protected void brushStroke(Map map, Map.Coordinate center, int brushSize, Map.CellState state) { Vector3 pos = map.GetRelativePosition(center); List<Map.Coordinate> coords = new List<Map.Coordinate>(); for (Map.Coordinate x = center.Move(Direction.NegativeX, this.BrushSize - 1); x.X < center.X + this.BrushSize; x.X++) { for (Map.Coordinate y = x.Move(Direction.NegativeY, this.BrushSize - 1); y.Y < center.Y + this.BrushSize; y.Y++) { for (Map.Coordinate z = y.Move(Direction.NegativeZ, this.BrushSize - 1); z.Z < center.Z + this.BrushSize; z.Z++) { if ((pos - map.GetRelativePosition(z)).Length() <= this.BrushSize) coords.Add(z); } } } if (state.ID == 0) map.Empty(coords); else { foreach (Map.Coordinate coord in coords) map.Fill(coord, state); } }
public bool Empty(Coordinate a, Coordinate b, Map transferringToNewMap = null) { int minY = Math.Min(a.Y, b.Y); int minZ = Math.Min(a.Z, b.Z); int maxX = Math.Max(a.X, b.X); int maxY = Math.Max(a.Y, b.Y); int maxZ = Math.Max(a.Z, b.Z); List<Map.Coordinate> coords = new List<Coordinate>(); for (int x = Math.Min(a.X, b.X); x < maxX; x++) { for (int y = minY; y < maxY; y++) { for (int z = minZ; z < maxZ; z++) { coords.Add(new Map.Coordinate { X = x, Y = y, Z = z }); } } } return this.Empty(coords, transferringToNewMap); }
public void Setup(Entity result, Entity m, Map.Coordinate c, int s) { Property<Entity.Handle> map = result.GetProperty<Entity.Handle>("TargetMap"); Property<Map.Coordinate> coord = result.GetProperty<Map.Coordinate>("TargetCoord"); Property<int> stateId = result.GetProperty<int>("TargetCellStateID"); map.InternalValue = m; coord.InternalValue = c; stateId.InternalValue = s; stateId.Changed(); }
// ========================= // 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(Map.Coordinate 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; }