public void Update(float elapsedTime) { Vector3 movementDir = new Vector3(); if (this.MovementEnabled) { Vector2 controller = this.main.Camera.GetWorldSpaceControllerCoordinates(this.Movement); movementDir = new Vector3(controller.X, 0, controller.Y); if (this.Up) movementDir = movementDir.SetComponent(Direction.PositiveY, 1.0f); else if (this.Down) movementDir = movementDir.SetComponent(Direction.NegativeY, 1.0f); if (this.MapEditMode) { bool moving = movementDir.LengthSquared() > 0.0f; // When the user lets go of the key, reset the timer // That way they can hit the key faster than the 0.1 sec interval if (!moving) this.movementInterval = 0.5f; if (this.movementInterval > (this.SpeedMode ? 0.05f : 0.1f)) { if (moving) this.movementInterval = 0.0f; if (movementDir.LengthSquared() > 0.0f) { Map map = this.SelectedEntities[0].Get<Map>(); Direction relativeDir = map.GetRelativeDirection(movementDir); this.coord = this.coord.Move(relativeDir); if (this.EditSelection) { this.VoxelSelectionStart.Value = new Map.Coordinate { X = Math.Min(this.selectionStart.X, this.coord.X), Y = Math.Min(this.selectionStart.Y, this.coord.Y), Z = Math.Min(this.selectionStart.Z, this.coord.Z), }; this.VoxelSelectionEnd.Value = new Map.Coordinate { X = Math.Max(this.selectionStart.X, this.coord.X) + 1, Y = Math.Max(this.selectionStart.Y, this.coord.Y) + 1, Z = Math.Max(this.selectionStart.Z, this.coord.Z) + 1, }; } else if (this.TransformMode.Value == TransformModes.Translate) { this.NeedsSave.Value = true; this.restoreMap(this.VoxelSelectionStart, this.VoxelSelectionEnd, !this.voxelDuplicate); Map.Coordinate newSelectionStart = this.VoxelSelectionStart.Value.Move(relativeDir); this.VoxelSelectionStart.Value = newSelectionStart; this.VoxelSelectionEnd.Value = this.VoxelSelectionEnd.Value.Move(relativeDir); this.mapState.Add(map.GetChunksBetween(this.VoxelSelectionStart, this.VoxelSelectionEnd)); Map.Coordinate offset = this.originalSelectionStart.Minus(newSelectionStart); this.restoreMap(newSelectionStart, this.VoxelSelectionEnd, false, offset.X, offset.Y, offset.Z); } this.Position.Value = map.GetAbsolutePosition(this.coord); } } this.movementInterval += elapsedTime; } else this.Position.Value = this.Position.Value + movementDir * (this.SpeedMode ? 50.0f : 25.0f) * elapsedTime; } if (this.MapEditMode) { if (!this.Fill && !this.Empty) this.justCommitedOrRevertedVoxelOperation = false; Map map = this.SelectedEntities[0].Get<Map>(); Map.Coordinate coord = map.GetCoordinate(this.Position); if (this.TransformMode.Value == TransformModes.None && (this.Fill || this.Empty || this.Extend) && !this.justCommitedOrRevertedVoxelOperation) { this.NeedsSave.Value = true; if (this.Brush == "[Procedural]") { ProceduralGenerator generator = this.Entity.Get<ProceduralGenerator>(); if (this.Fill) { if (this.VoxelSelectionActive) { foreach (Map.Coordinate c in this.VoxelSelectionStart.Value.CoordinatesBetween(this.VoxelSelectionEnd)) map.Fill(c, generator.GetValue(map, c)); } else this.brushStroke(map, coord, this.BrushSize, x => generator.GetValue(map, x), true, false); } else if (this.Empty) { if (this.VoxelSelectionActive) map.Empty(this.VoxelSelectionStart.Value.CoordinatesBetween(this.VoxelSelectionEnd).Where(x => generator.GetValue(map, x).ID == 0)); else this.brushStroke(map, coord, this.BrushSize, x => generator.GetValue(map, x), false, true); } } else { if (this.Fill) { Map.CellState material; if (WorldFactory.StatesByName.TryGetValue(this.Brush, out material)) { if (this.VoxelSelectionActive) map.Fill(this.VoxelSelectionStart, this.VoxelSelectionEnd, material); else this.brushStroke(map, coord, this.BrushSize, material); } } else if (this.Empty) { if (this.VoxelSelectionActive) map.Empty(this.VoxelSelectionStart, this.VoxelSelectionEnd); else this.brushStroke(map, coord, this.BrushSize, new Map.CellState()); } } if (this.Extend && !this.coord.Equivalent(this.lastCoord)) { Direction dir = DirectionExtensions.GetDirectionFromVector(Vector3.TransformNormal(movementDir, Matrix.Invert(map.Transform))); Map.Box box = map.GetBox(this.lastCoord); bool grow = map.GetBox(this.coord) != box; if (box != null) { List<Map.Coordinate> removals = new List<Map.Coordinate>(); if (dir.IsParallel(Direction.PositiveX)) { for (int y = box.Y; y < box.Y + box.Height; y++) { for (int z = box.Z; z < box.Z + box.Depth; z++) { if (grow) map.Fill(this.coord.X, y, z, box.Type); else removals.Add(map.GetCoordinate(this.lastCoord.X, y, z)); } } } if (dir.IsParallel(Direction.PositiveY)) { for (int x = box.X; x < box.X + box.Width; x++) { for (int z = box.Z; z < box.Z + box.Depth; z++) { if (grow) map.Fill(x, this.coord.Y, z, box.Type); else removals.Add(map.GetCoordinate(x, this.lastCoord.Y, z)); } } } if (dir.IsParallel(Direction.PositiveZ)) { for (int x = box.X; x < box.X + box.Width; x++) { for (int y = box.Y; y < box.Y + box.Height; y++) { if (grow) map.Fill(x, y, this.coord.Z, box.Type); else removals.Add(map.GetCoordinate(x, y, this.lastCoord.Z)); } } } map.Empty(removals); } } map.Regenerate(); } this.lastCoord = this.coord; } else if (this.TransformMode.Value == TransformModes.Translate) { // Translate entities this.NeedsSave.Value = true; float rayLength = (this.transformCenter - this.main.Camera.Position.Value).Length(); Vector2 mouseOffset = this.Mouse - this.originalTransformMouse; Vector3 offset = ((this.main.Camera.Right.Value * mouseOffset.X * rayLength) + (this.main.Camera.Up.Value * -mouseOffset.Y * rayLength)) * 0.0025f; switch (this.TransformAxis.Value) { case TransformAxes.X: offset.Y = offset.Z = 0.0f; break; case TransformAxes.Y: offset.X = offset.Z = 0.0f; break; case TransformAxes.Z: offset.X = offset.Y = 0.0f; break; } if (this.SelectedTransform.Value != null) this.SelectedTransform.Value.Position.Value = this.offsetTransforms[0].Translation + offset; else { int i = 0; foreach (Entity entity in this.SelectedEntities) { Transform transform = entity.Get<Transform>(); if (transform != null) { Matrix originalTransform = this.offsetTransforms[i]; transform.Position.Value = originalTransform.Translation + offset; i++; } } } } else if (this.TransformMode.Value == TransformModes.Rotate) { // Rotate entities this.NeedsSave.Value = true; Vector3 screenSpaceCenter = this.main.GraphicsDevice.Viewport.Project(this.transformCenter, this.main.Camera.Projection, this.main.Camera.View, Matrix.Identity); Vector2 originalOffset = new Vector2(this.originalTransformMouse.X - screenSpaceCenter.X, this.originalTransformMouse.Y - screenSpaceCenter.Y); float originalAngle = (float)Math.Atan2(originalOffset.Y, originalOffset.X); Vector2 newOffset = new Vector2(this.Mouse.Value.X - screenSpaceCenter.X, this.Mouse.Value.Y - screenSpaceCenter.Y); float newAngle = (float)Math.Atan2(newOffset.Y, newOffset.X); Vector3 axis = this.main.Camera.Forward; switch (this.TransformAxis.Value) { case TransformAxes.X: axis = Vector3.Right; break; case TransformAxes.Y: axis = Vector3.Up; break; case TransformAxes.Z: axis = Vector3.Forward; break; } if (this.SelectedTransform.Value != null) { Matrix originalTransform = this.offsetTransforms[0]; originalTransform.Translation -= this.transformCenter; originalTransform *= Matrix.CreateFromAxisAngle(axis, newAngle - originalAngle); originalTransform.Translation += this.transformCenter; this.SelectedTransform.Value.Matrix.Value = originalTransform; } else { int i = 0; foreach (Entity entity in this.SelectedEntities) { Transform transform = entity.Get<Transform>(); if (transform != null) { Matrix originalTransform = this.offsetTransforms[i]; originalTransform.Translation -= this.transformCenter; originalTransform *= Matrix.CreateFromAxisAngle(axis, newAngle - originalAngle); originalTransform.Translation += this.transformCenter; transform.Matrix.Value = originalTransform; i++; } } } } }
public override void Bind(Entity result, Main main, bool creating = false) { PointLight light = result.GetOrCreate<PointLight>("PointLight"); light.Serialize = false; const float defaultLightAttenuation = 15.0f; light.Attenuation.Value = defaultLightAttenuation; Transform transform = result.GetOrCreate<Transform>("Transform"); light.Add(new Binding<Vector3>(light.Position, transform.Position)); VoxelChaseAI chase = result.GetOrCreate<VoxelChaseAI>("VoxelChaseAI"); chase.Filter = delegate(Map.CellState state) { return state.ID == 0 ? VoxelChaseAI.Cell.Empty : VoxelChaseAI.Cell.Filled; }; chase.Add(new TwoWayBinding<Vector3>(transform.Position, chase.Position)); result.Add(new CommandBinding(chase.Delete, result.Delete)); Sound sound = result.GetOrCreate<Sound>("LoopSound"); sound.Serialize = false; sound.Cue.Value = "Orb Loop"; sound.Is3D.Value = true; sound.IsPlaying.Value = true; sound.Add(new Binding<Vector3>(sound.Position, chase.Position)); Property<float> volume = sound.GetProperty("Volume"); Property<float> pitch = sound.GetProperty("Pitch"); const float defaultVolume = 0.5f; volume.Value = defaultVolume; AI ai = result.GetOrCreate<AI>(); Model model = result.GetOrCreate<Model>(); model.Add(new Binding<Matrix>(model.Transform, transform.Matrix)); model.Filename.Value = "Models\\sphere"; model.Editable = false; model.Serialize = false; const float defaultModelScale = 0.25f; model.Scale.Value = new Vector3(defaultModelScale); model.Add(new Binding<Vector3, string>(model.Color, delegate(string state) { switch (state) { case "Alert": return new Vector3(1.5f, 1.5f, 0.5f); case "Chase": return new Vector3(1.5f, 0.5f, 0.5f); case "Levitating": return new Vector3(2.0f, 1.0f, 0.5f); case "Idle": return new Vector3(1.0f, 1.0f, 1.0f); default: return new Vector3(0.0f, 0.0f, 0.0f); } }, ai.CurrentState)); Random random = new Random(); result.Add(new Updater { delegate(float dt) { float source = ((float)random.NextDouble() - 0.5f) * 2.0f; model.Scale.Value = new Vector3(defaultModelScale * (1.0f + (source * 0.5f))); light.Attenuation.Value = defaultLightAttenuation * (1.0f + (source * 0.05f)); } }); model.Add(new Binding<bool, string>(model.Enabled, x => x != "Exploding", ai.CurrentState)); light.Add(new Binding<Vector3>(light.Color, model.Color)); Agent agent = result.GetOrCreate<Agent>(); agent.Add(new Binding<Vector3>(agent.Position, chase.Position)); Property<int> operationalRadius = result.GetOrMakeProperty<int>("OperationalRadius", true, 100); AI.Task checkOperationalRadius = new AI.Task { Interval = 2.0f, Action = delegate() { bool shouldBeActive = (chase.Position.Value - main.Camera.Position).Length() < operationalRadius; if (shouldBeActive && ai.CurrentState == "Suspended") ai.CurrentState.Value = "Idle"; else if (!shouldBeActive && ai.CurrentState != "Suspended") ai.CurrentState.Value = "Suspended"; }, }; const float sightDistance = 30.0f; const float hearingDistance = 15.0f; ai.Add(new AI.State { Name = "Idle", Enter = delegate(AI.State previous) { chase.Speed.Value = 3.0f; }, Tasks = new[] { checkOperationalRadius, new AI.Task { Interval = 1.0f, Action = delegate() { Agent a = Agent.Query(chase.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player"); if (a != null) ai.CurrentState.Value = "Alert"; }, }, }, }); Property<Entity.Handle> targetAgent = result.GetOrMakeProperty<Entity.Handle>("TargetAgent"); ai.Add(new AI.State { Name = "Alert", Enter = delegate(AI.State previous) { chase.Enabled.Value = false; }, Exit = delegate(AI.State next) { chase.Enabled.Value = true; }, Tasks = new[] { checkOperationalRadius, new AI.Task { Interval = 1.0f, Action = delegate() { if (ai.TimeInCurrentState > 3.0f) ai.CurrentState.Value = "Idle"; else { Agent a = Agent.Query(chase.Position, sightDistance, hearingDistance, x => x.Entity.Type == "Player"); if (a != null) { targetAgent.Value = a.Entity; ai.CurrentState.Value = "Chase"; } } }, }, }, }); AI.Task checkTargetAgent = new AI.Task { Action = delegate() { Entity target = targetAgent.Value.Target; if (target == null || !target.Active) { targetAgent.Value = null; ai.CurrentState.Value = "Idle"; } }, }; // Levitate Property<Entity.Handle> levitatingMap = result.GetOrMakeProperty<Entity.Handle>("LevitatingMap"); Property<Map.Coordinate> grabCoord = result.GetOrMakeProperty<Map.Coordinate>("GrabCoord"); const int levitateRipRadius = 4; Func<bool> tryLevitate = delegate() { Map map = chase.Map.Value.Target.Get<Map>(); Map.Coordinate? candidate = map.FindClosestFilledCell(chase.Coord, 3); if (!candidate.HasValue) return false; Map.Coordinate center = candidate.Value; if (!map[center].Permanent) { // Break off a chunk of this map into a new DynamicMap. List<Map.Coordinate> edges = new List<Map.Coordinate>(); Map.Coordinate ripStart = center.Move(-levitateRipRadius, -levitateRipRadius, -levitateRipRadius); Map.Coordinate ripEnd = center.Move(levitateRipRadius, levitateRipRadius, levitateRipRadius); Dictionary<Map.Box, bool> permanentBoxes = new Dictionary<Map.Box, bool>(); foreach (Map.Coordinate c in ripStart.CoordinatesBetween(ripEnd)) { Map.Box box = map.GetBox(c); if (box != null && box.Type.Permanent) permanentBoxes[box] = true; } foreach (Map.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++) { Map.Coordinate coord = new Map.Coordinate { X = x, Y = b.Y + b.Height, Z = z }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); coord = new Map.Coordinate { 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++) { Map.Coordinate coord = new Map.Coordinate { X = b.X - 1, Y = y, Z = z }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); coord = new Map.Coordinate { 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++) { Map.Coordinate coord = new Map.Coordinate { X = x, Y = y, Z = b.Z - 1 }; if (coord.Between(ripStart, ripEnd)) edges.Add(coord); coord = new Map.Coordinate { 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++) { edges.Add(new Map.Coordinate { X = x, Y = ripStart.Y, Z = z }); edges.Add(new Map.Coordinate { X = x, Y = ripEnd.Y, Z = z }); } } // Sides for (int y = ripStart.Y + 1; y <= ripEnd.Y - 1; y++) { // Left and right for (int z = ripStart.Z; z <= ripEnd.Z; z++) { edges.Add(new Map.Coordinate { X = ripStart.X, Y = y, Z = z }); edges.Add(new Map.Coordinate { X = ripEnd.X, Y = y, Z = z }); } // Backward and forward for (int x = ripStart.X; x <= ripEnd.X; x++) { edges.Add(new Map.Coordinate { X = x, Y = y, Z = ripStart.Z }); edges.Add(new Map.Coordinate { X = x, Y = y, Z = ripEnd.Z }); } } map.Empty(edges); map.Regenerate(delegate(List<DynamicMap> spawnedMaps) { foreach (DynamicMap spawnedMap in spawnedMaps) { if (spawnedMap[center].ID != 0) { levitatingMap.Value = spawnedMap.Entity; break; } } }); grabCoord.Value = center; return true; } return false; }; Action delevitateMap = delegate() { Entity levitatingMapEntity = levitatingMap.Value.Target; if (levitatingMapEntity == null || !levitatingMapEntity.Active) return; DynamicMap dynamicMap = levitatingMapEntity.Get<DynamicMap>(); int maxDistance = levitateRipRadius + 7; Map closestMap = null; Map.Coordinate closestCoord = new Map.Coordinate(); foreach (Map m in Map.ActivePhysicsMaps) { if (m == dynamicMap) continue; Map.Coordinate relativeCoord = m.GetCoordinate(dynamicMap.Transform.Value.Translation); Map.Coordinate? 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))); closestMap = m; closestCoord = closestFilled.Value; } } if (closestMap != null) { // Combine this map with the other one Direction x = closestMap.GetRelativeDirection(dynamicMap.GetAbsoluteVector(Vector3.Right)); Direction y = closestMap.GetRelativeDirection(dynamicMap.GetAbsoluteVector(Vector3.Up)); Direction z = closestMap.GetRelativeDirection(dynamicMap.GetAbsoluteVector(Vector3.Backward)); if (x.IsParallel(y)) x = y.Cross(z); else if (y.IsParallel(z)) y = x.Cross(z); Map.Coordinate offset = new Map.Coordinate(); float closestCoordDistance = float.MaxValue; Vector3 closestCoordPosition = closestMap.GetAbsolutePosition(closestCoord); foreach (Map.Coordinate c in dynamicMap.Chunks.SelectMany(c => c.Boxes).SelectMany(b => b.GetCoords())) { float distance = (dynamicMap.GetAbsolutePosition(c) - closestCoordPosition).LengthSquared(); if (distance < closestCoordDistance) { closestCoordDistance = distance; offset = c; } } Vector3 toLevitatingMap = dynamicMap.Transform.Value.Translation - closestMap.GetAbsolutePosition(closestCoord); offset = offset.Move(dynamicMap.GetRelativeDirection(-toLevitatingMap)); Matrix orientation = dynamicMap.Transform.Value; orientation.Translation = Vector3.Zero; EffectBlockFactory blockFactory = Factory.Get<EffectBlockFactory>(); int index = 0; foreach (Map.Coordinate c in dynamicMap.Chunks.SelectMany(c => c.Boxes).SelectMany(b => b.GetCoords()).OrderBy(c2 => new Vector3(c2.X - offset.X, c2.Y - offset.Y, c2.Z - offset.Z).LengthSquared())) { Map.Coordinate offsetFromCenter = c.Move(-offset.X, -offset.Y, -offset.Z); Map.Coordinate targetCoord = new Map.Coordinate(); targetCoord.SetComponent(x, offsetFromCenter.GetComponent(Direction.PositiveX)); targetCoord.SetComponent(y, offsetFromCenter.GetComponent(Direction.PositiveY)); targetCoord.SetComponent(z, offsetFromCenter.GetComponent(Direction.PositiveZ)); targetCoord = targetCoord.Move(closestCoord.X, closestCoord.Y, closestCoord.Z); if (closestMap[targetCoord].ID == 0) { Entity block = blockFactory.CreateAndBind(main); c.Data.ApplyToEffectBlock(block.Get<ModelInstance>()); block.GetProperty<Vector3>("Offset").Value = closestMap.GetRelativePosition(targetCoord); block.GetProperty<bool>("Scale").Value = false; block.GetProperty<Vector3>("StartPosition").Value = dynamicMap.GetAbsolutePosition(c); block.GetProperty<Matrix>("StartOrientation").Value = orientation; block.GetProperty<float>("TotalLifetime").Value = 0.05f + (index * 0.0075f); blockFactory.Setup(block, closestMap.Entity, targetCoord, c.Data.ID); main.Add(block); index++; } } // Delete the map levitatingMapEntity.Delete.Execute(); } }; // Chase AI state ai.Add(new AI.State { Name = "Chase", Enter = delegate(AI.State previous) { chase.Speed.Value = 10.0f; chase.TargetActive.Value = true; }, Exit = delegate(AI.State next) { chase.TargetActive.Value = false; }, Tasks = new[] { checkOperationalRadius, checkTargetAgent, new AI.Task { Interval = 0.1f, Action = delegate() { Entity target = targetAgent.Value.Target; Vector3 targetPosition = target.Get<Transform>().Position; chase.Target.Value = targetPosition; Entity levitatingMapEntity = levitatingMap.Value.Target; if ((targetPosition - chase.Position).Length() < 10.0f && (levitatingMapEntity == null || !levitatingMapEntity.Active)) { if (tryLevitate()) ai.CurrentState.Value = "Levitating"; } } } }, }); Property<Vector3> lastPosition = result.GetOrMakeProperty<Vector3>("LastPosition"); Property<Vector3> nextPosition = result.GetOrMakeProperty<Vector3>("NextPosition"); Property<float> positionBlend = result.GetOrMakeProperty<float>("PositionBlend"); Action findNextPosition = delegate() { lastPosition.Value = chase.Position.Value; nextPosition.Value = targetAgent.Value.Target.Get<Transform>().Position + new Vector3((float)random.NextDouble() - 0.5f, (float)random.NextDouble(), (float)random.NextDouble() - 0.5f) * 5.0f; positionBlend.Value = 0.0f; }; ai.Add(new AI.State { Name = "Levitating", Enter = delegate(AI.State previous) { chase.Enabled.Value = false; findNextPosition(); }, Exit = delegate(AI.State next) { delevitateMap(); levitatingMap.Value = null; Map map = chase.Map.Value.Target.Get<Map>(); Map.Coordinate currentCoord = map.GetCoordinate(chase.Position); Map.Coordinate? closest = map.FindClosestFilledCell(currentCoord, 10); if (closest.HasValue) { chase.LastCoord.Value = currentCoord; chase.Coord.Value = closest.Value; chase.Blend.Value = 0.0f; } chase.Enabled.Value = true; volume.Value = defaultVolume; pitch.Value = 0.0f; }, Tasks = new[] { checkTargetAgent, new AI.Task { Action = delegate() { volume.Value = 1.0f; pitch.Value = 1.0f; Entity levitatingMapEntity = levitatingMap.Value.Target; if (!levitatingMapEntity.Active || ai.TimeInCurrentState.Value > 8.0f) { ai.CurrentState.Value = "Alert"; return; } DynamicMap dynamicMap = levitatingMapEntity.Get<DynamicMap>(); positionBlend.Value += (main.ElapsedTime.Value / 1.0f); if (positionBlend > 1.0f) findNextPosition(); chase.Position.Value = Vector3.Lerp(lastPosition, nextPosition, positionBlend); Vector3 grabPoint = dynamicMap.GetAbsolutePosition(grabCoord); Vector3 diff = chase.Position.Value - grabPoint; if (diff.Length() > 15.0f) { ai.CurrentState.Value = "Chase"; return; } diff *= (float)Math.Sqrt(dynamicMap.PhysicsEntity.Mass) * 0.5f; dynamicMap.PhysicsEntity.ApplyImpulse(ref grabPoint, ref diff); }, }, }, }); this.SetMain(result, main); }
public override void InitializeProperties() { this.Spawn.Action = delegate(string type) { if (Factory.Get(type) != null) { Entity entity = Factory.CreateAndBind(this.main, type); Transform position = entity.Get<Transform>(); if (position != null) position.Position.Value = this.Position; this.NeedsSave.Value = true; this.main.Add(entity); this.SelectedEntities.Clear(); this.SelectedEntities.Add(entity); this.StartTranslation.Execute(); } }; this.Save.Action = delegate() { IO.MapLoader.Save(this.main, null, this.main.MapFile); this.NeedsSave.Value = false; }; this.Duplicate.Action = delegate() { this.NeedsSave.Value = true; if (this.TransformMode.Value != TransformModes.None) this.CommitTransform.Execute(); IEnumerable<Entity> entities = this.SelectedEntities.ToList(); this.SelectedEntities.Clear(); foreach (Entity entity in entities) { Entity copy = Factory.Duplicate(this.main, entity); this.main.Add(copy); this.SelectedEntities.Add(copy); } this.StartTranslation.Execute(); }; this.Brush.Value = "[Procedural]"; this.MapEditMode.Set = delegate(bool value) { bool oldValue = this.MapEditMode.InternalValue; this.MapEditMode.InternalValue = value; if (value && !oldValue) { this.Orientation.Value = this.SelectedEntities[0].Get<Transform>().Orientation; this.lastCoord = this.coord = this.SelectedEntities[0].Get<Map>().GetCoordinate(this.Position); } else if (!value && oldValue) this.Orientation.Value = Matrix.Identity; }; this.SelectedEntities.ItemAdded += delegate(int index, Entity t) { Property<bool> selected = t.GetProperty<bool>("EditorSelected"); if (selected != null) selected.Value = true; this.VoxelSelectionEnd.Value = this.VoxelSelectionStart.Value; this.SelectedTransform.Value = null; }; this.SelectedEntities.ItemRemoved += delegate(int index, Entity t) { Property<bool> selected = t.GetProperty<bool>("EditorSelected"); if (selected != null) selected.Value = false; this.VoxelSelectionEnd.Value = this.VoxelSelectionStart.Value; this.SelectedTransform.Value = null; }; this.SelectedEntities.Clearing += delegate() { foreach (Entity e in this.SelectedEntities) { Property<bool> selected = e.GetProperty<bool>("EditorSelected"); if (selected != null) selected.Value = false; } this.VoxelSelectionEnd.Value = this.VoxelSelectionStart.Value; this.SelectedTransform.Value = null; }; this.EditSelection.Set = delegate(bool value) { if (value && !this.EditSelection.InternalValue) { this.selectionStart = this.coord; this.VoxelSelectionStart.Value = this.coord; this.VoxelSelectionEnd.Value = this.coord.Move(1, 1, 1); } else if (!value && this.EditSelection.InternalValue) { if (this.VoxelSelectionEnd.Value.Equivalent(this.VoxelSelectionStart.Value.Move(1, 1, 1))) this.VoxelSelectionEnd.Value = this.VoxelSelectionStart.Value; } this.EditSelection.InternalValue = value; }; this.VoxelCopy.Action = delegate() { if (this.MapEditMode && this.VoxelSelectionActive) { Map m = this.SelectedEntities[0].Get<Map>(); this.originalSelectionStart = this.VoxelSelectionStart; this.originalSelectionEnd = this.VoxelSelectionEnd; this.originalSelectionCoord = this.coord; this.mapState = new Map.MapState(m.GetChunksBetween(this.originalSelectionStart, this.originalSelectionEnd)); this.voxelDuplicate = false; } }; this.VoxelPaste.Action = delegate() { if (this.MapEditMode && this.mapState != null) { Map m = this.SelectedEntities[0].Get<Map>(); Map.Coordinate newSelectionStart = this.coord.Plus(this.originalSelectionStart.Minus(this.originalSelectionCoord)); this.VoxelSelectionStart.Value = newSelectionStart; this.VoxelSelectionEnd.Value = this.coord.Plus(this.originalSelectionEnd.Minus(this.originalSelectionCoord)); this.mapState.Add(m.GetChunksBetween(this.VoxelSelectionStart, this.VoxelSelectionEnd)); Map.Coordinate offset = this.originalSelectionStart.Minus(newSelectionStart); this.restoreMap(newSelectionStart, this.VoxelSelectionEnd, false, offset.X, offset.Y, offset.Z); } }; this.StartVoxelTranslation.Action = delegate() { if (this.MapEditMode && this.VoxelSelectionActive) { this.VoxelCopy.Execute(); this.TransformMode.Value = TransformModes.Translate; } }; this.VoxelDuplicate.Action = delegate() { if (this.MapEditMode && this.VoxelSelectionActive) { this.StartVoxelTranslation.Execute(); this.voxelDuplicate = true; } }; this.PropagateMaterial.Action = delegate() { if (!this.MapEditMode) return; Map m = this.SelectedEntities[0].Get<Map>(); Map.Box selectedBox = m.GetBox(this.coord); if (selectedBox == null) return; Map.Coordinate startSelection = this.VoxelSelectionStart; Map.Coordinate endSelection = this.VoxelSelectionEnd; bool selectionActive = this.VoxelSelectionActive; Map.CellState material; if (WorldFactory.StatesByName.TryGetValue(this.Brush, out material)) { IEnumerable<Map.Coordinate> coordEnumerable; if (selectionActive) coordEnumerable = m.GetContiguousByType(new Map.Box[] { selectedBox }).SelectMany(x => x.GetCoords().Where(y => y.Between(startSelection, endSelection))); else coordEnumerable = m.GetContiguousByType(new Map.Box[] { selectedBox }).SelectMany(x => x.GetCoords()); List<Map.Coordinate> coords = coordEnumerable.ToList(); m.Empty(coords); foreach (Map.Coordinate c in coords) m.Fill(c, material); m.Regenerate(); } }; this.SampleMaterial.Action = delegate() { if (!this.MapEditMode) return; Map m = this.SelectedEntities[0].Get<Map>(); Map.Box selectedBox = m.GetBox(this.coord); if (selectedBox == null) return; this.Brush.Value = selectedBox.Type.Name; }; this.DeleteMaterial.Action = delegate() { if (!this.MapEditMode) return; Map m = this.SelectedEntities[0].Get<Map>(); Map.Box selectedBox = m.GetBox(this.coord); if (selectedBox == null) return; Map.Coordinate startSelection = this.VoxelSelectionStart; Map.Coordinate endSelection = this.VoxelSelectionEnd; bool selectionActive = this.VoxelSelectionActive; Map.CellState material; if (WorldFactory.StatesByName.TryGetValue(this.Brush, out material)) { IEnumerable<Map.Coordinate> coordEnumerable; if (selectionActive) coordEnumerable = m.GetContiguousByType(new Map.Box[] { selectedBox }).SelectMany(x => x.GetCoords().Where(y => y.Between(startSelection, endSelection))); else coordEnumerable = m.GetContiguousByType(new Map.Box[] { selectedBox }).SelectMany(x => x.GetCoords()); List<Map.Coordinate> coords = coordEnumerable.ToList(); m.Empty(coords); m.Regenerate(); } }; Action<TransformModes> startTransform = delegate(TransformModes mode) { this.TransformMode.Value = mode; this.TransformAxis.Value = TransformAxes.All; this.originalTransformMouse = this.Mouse; this.offsetTransforms.Clear(); this.transformCenter = Vector3.Zero; if (this.SelectedTransform.Value != null) { this.offsetTransforms.Add(this.SelectedTransform.Value.Matrix); this.transformCenter = this.SelectedTransform.Value.Position; } else { int entityCount = 0; foreach (Entity entity in this.SelectedEntities) { Transform transform = entity.Get<Transform>(); if (transform != null) { this.offsetTransforms.Add(transform.Matrix); this.transformCenter += transform.Position; entityCount++; } } this.transformCenter /= (float)entityCount; } }; this.StartTranslation.Action = delegate() { startTransform(TransformModes.Translate); }; this.StartRotation.Action = delegate() { startTransform(TransformModes.Rotate); }; this.CommitTransform.Action = delegate() { this.NeedsSave.Value = true; this.TransformMode.Value = TransformModes.None; this.TransformAxis.Value = TransformAxes.All; if (this.MapEditMode) this.justCommitedOrRevertedVoxelOperation = true; this.offsetTransforms.Clear(); }; this.RevertTransform.Action = delegate() { this.TransformMode.Value = TransformModes.None; if (this.MapEditMode) { this.restoreMap(this.VoxelSelectionStart, this.VoxelSelectionEnd, false); this.VoxelSelectionStart.Value = this.originalSelectionStart; this.VoxelSelectionEnd.Value = this.originalSelectionEnd; this.restoreMap(this.VoxelSelectionStart, this.VoxelSelectionEnd, false); this.justCommitedOrRevertedVoxelOperation = true; } else { this.TransformAxis.Value = TransformAxes.All; if (this.SelectedTransform.Value != null) this.SelectedTransform.Value.Matrix.Value = this.offsetTransforms[0]; else { int i = 0; foreach (Entity entity in this.SelectedEntities) { Transform transform = entity.Get<Transform>(); if (transform != null) { transform.Matrix.Value = this.offsetTransforms[i]; i++; } } } this.offsetTransforms.Clear(); } }; this.DeleteSelected.Action = delegate() { this.NeedsSave.Value = true; this.TransformMode.Value = TransformModes.None; this.TransformAxis.Value = TransformAxes.All; this.offsetTransforms.Clear(); foreach (Entity entity in this.SelectedEntities) entity.Delete.Execute(); this.SelectedEntities.Clear(); }; this.Add(new Binding<bool>(this.VoxelSelectionActive, delegate() { if (!this.MapEditMode) return false; Map.Coordinate start = this.VoxelSelectionStart, end = this.VoxelSelectionEnd; return start.X != end.X && start.Y != end.Y && start.Z != end.Z; }, this.MapEditMode, this.VoxelSelectionStart, this.VoxelSelectionEnd)); }
// Classic 3D perlin noise float noise3d(Vector3 pos) { Map.Coordinate cell = new Map.Coordinate { X = (int)Math.Floor(pos.X) & 255, Y = (int)Math.Floor(pos.Y) & 255, Z = (int)Math.Floor(pos.Z) & 255 }; 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); }