private void Initialise() { rootState = new StateMachineBuilder() .State("Select") .Enter(evt => selectedToolIndex = 0) .Update((state, dt) => { EditorUtilities.ShowHelpBox("Select", "Pick a hex tile to manually edit its properties."); HexTileData currentTile; if (hexMap.SelectedTile != null && hexMap.TryGetTile(hexMap.SelectedTile, out currentTile)) { // Tile info GUILayout.Label("Tile position", EditorStyles.boldLabel); EditorUtilities.ShowReadonlyIntField("Column", hexMap.SelectedTile.Q); EditorUtilities.ShowReadonlyIntField("Row", hexMap.SelectedTile.R); EditorUtilities.ShowReadonlyFloatField("Elevation", currentTile.Position.Elevation); // Tile settings GUILayout.Label("Settings", EditorStyles.boldLabel); var currentMaterial = currentTile.Material; var newMaterial = (Material)EditorGUILayout.ObjectField("Material", currentMaterial, typeof(Material), false); if (currentMaterial != newMaterial) { hexMap.ReplaceMaterialOnTile(currentTile.Position.Coordinates, newMaterial); MarkSceneDirty(); } } }) .Event <SceneClickedEventArgs>("SceneClicked", (state, eventArgs) => { if (eventArgs.Button == 0) { var tile = TryFindTileForMousePosition(eventArgs.Position); if (tile != null) { hexMap.SelectedTile = tile.Coordinates; } } }) .End() .State <PaintState>("Paint tiles") .Enter(state => { selectedToolIndex = 1; }) .Update((state, dt) => { EditorUtilities.ShowHelpBox("Paint tiles", "Click and drag to add hex tiles at the specified height."); bool sceneNeedsRepaint = false; var newBrushSize = EditorGUILayout.IntSlider("Brush size", brushSize, 1, 10); if (newBrushSize != brushSize) { brushSize = newBrushSize; sceneNeedsRepaint = true; } var paintHeight = EditorGUILayout.FloatField("Paint height", state.PaintHeight); if (paintHeight != state.PaintHeight) { state.PaintHeight = paintHeight; foreach (var tile in highlightedTiles) { tile.Elevation = paintHeight; } sceneNeedsRepaint = true; } var paintOffsetHeight = EditorGUILayout.FloatField("Height offset", state.PaintOffset); if (paintOffsetHeight != state.PaintOffset) { state.PaintOffset = paintOffsetHeight; foreach (var tile in nextTilePositions) { tile.Elevation = paintHeight + paintOffsetHeight; } sceneNeedsRepaint = true; } hexMap.CurrentMaterial = (Material)EditorGUILayout.ObjectField("Material", hexMap.CurrentMaterial, typeof(Material), false); if (sceneNeedsRepaint) { if (centerSelectedTileCoords != null) { UpdateHighlightedTiles(centerSelectedTileCoords.CoordinateRange(brushSize - 1), state.PaintHeight, state.PaintOffset); } SceneView.RepaintAll(); } }) .Event("MouseMove", state => { var highlightedPosition = EditorUtilities.GetWorldPositionForMouse(Event.current.mousePosition, state.PaintHeight); if (highlightedPosition != null) { centerSelectedTileCoords = hexMap.QuantizeVector3ToHexCoords(highlightedPosition.GetValueOrDefault()); UpdateHighlightedTiles(centerSelectedTileCoords.CoordinateRange(brushSize - 1), state.PaintHeight, state.PaintOffset); } Event.current.Use(); }) .Event <SceneClickedEventArgs>("SceneClicked", (state, eventArgs) => { if (eventArgs.Button == 0) { var position = EditorUtilities.GetWorldPositionForMouse(eventArgs.Position, state.PaintHeight); if (position != null) { // Select the tile that was clicked on. centerSelectedTileCoords = hexMap.QuantizeVector3ToHexCoords(position.GetValueOrDefault()); var coords = centerSelectedTileCoords.CoordinateRange(brushSize - 1); foreach (var hex in coords) { // Keep track of which chunks we've modified so that // we only record undo actions for each once. var oldChunk = hexMap.FindChunkForCoordinates(hex); if (oldChunk != null && !state.ModifiedChunks.Contains(oldChunk)) { RecordChunkModifiedUndo(oldChunk); state.ModifiedChunks.Add(oldChunk); } var newChunk = hexMap.FindChunkForCoordinatesAndMaterial(hex, hexMap.CurrentMaterial); if (newChunk != null && newChunk != oldChunk && !state.ModifiedChunks.Contains(newChunk)) { RecordChunkModifiedUndo(newChunk); state.ModifiedChunks.Add(newChunk); } // TODO: add feature for disabling wireframe again. var paintHeight = state.PaintHeight + state.PaintOffset; var action = hexMap.CreateAndAddTile( new HexPosition(hex, paintHeight), hexMap.CurrentMaterial); if (action.Operation == ModifiedTileInfo.ChunkOperation.Added) { RecordChunkAddedUndo(action.Chunk); } } hexMap.SelectedTile = centerSelectedTileCoords; MarkSceneDirty(); } } }) .Event("MouseUp", state => { // Flush list of modified chunks so that they are not included in // the next undo action. state.ModifiedChunks.Clear(); }) .Exit(state => { highlightedTiles = Enumerable.Empty <HexPosition>(); nextTilePositions = Enumerable.Empty <HexPosition>(); hexMap.NextTilePositions = null; }) .End() .State <ChunkEditingState>("Material paint") .Enter(state => { selectedToolIndex = 2; }) .Update((state, dt) => { bool sceneNeedsRepaint = false; EditorUtilities.ShowHelpBox("Material paint", "Paint over existing tiles to change their material."); var newBrushSize = EditorGUILayout.IntSlider("Brush size", brushSize, 1, 10); if (newBrushSize != brushSize) { brushSize = newBrushSize; sceneNeedsRepaint = true; } hexMap.CurrentMaterial = (Material)EditorGUILayout.ObjectField("Material", hexMap.CurrentMaterial, typeof(Material), false); EditorGUILayout.Space(); if (GUILayout.Button("Apply to all tiles")) { ApplyCurrentMaterialToAllTiles(); MarkSceneDirty(); sceneNeedsRepaint = true; } if (sceneNeedsRepaint) { SceneView.RepaintAll(); } }) .Event("MouseMove", state => { HighlightTilesUnderMousePosition(); Event.current.Use(); }) .Event <SceneClickedEventArgs>("SceneClicked", (state, eventArgs) => { if (eventArgs.Button == 0) { var tilePosition = TryFindTileForMousePosition(eventArgs.Position); if (tilePosition != null && hexMap.ContainsTile(tilePosition.Coordinates)) { // Select that the tile that was clicked on. hexMap.SelectedTile = tilePosition.Coordinates; // Change the material on the tile var tilesUnderBrush = tilePosition.Coordinates.CoordinateRange(brushSize - 1) .Where(coords => hexMap.ContainsTile(coords)); foreach (var coords in tilesUnderBrush) { ReplaceMaterialOnTile(coords, state.ModifiedChunks); } } Event.current.Use(); } }) .Event("MouseUp", state => { // Flush list of modified chunks so that they are not included in // the next undo action. state.ModifiedChunks.Clear(); }) .End() .State <ChunkEditingState>("Erase") .Enter(evt => selectedToolIndex = 3) .Update((state, dt) => { EditorUtilities.ShowHelpBox("Erase", "Click and drag on existing hex tiles to remove them."); var newBrushSize = EditorGUILayout.IntSlider("Brush size", brushSize, 1, 10); if (newBrushSize != brushSize) { brushSize = newBrushSize; SceneView.RepaintAll(); } }) .Event("MouseMove", state => { HighlightTilesUnderMousePosition(); Event.current.Use(); }) .Event <SceneClickedEventArgs>("SceneClicked", (state, eventArgs) => { if (eventArgs.Button == 0) { bool removedTile = false; var centerTile = TryFindTileForMousePosition(eventArgs.Position); if (centerTile != null) { foreach (var tile in centerTile.Coordinates.CoordinateRange(brushSize - 1)) { var chunk = hexMap.FindChunkForCoordinates(tile); if (chunk != null && !state.ModifiedChunks.Contains(chunk)) { RecordChunkModifiedUndo(chunk); state.ModifiedChunks.Add(chunk); } // Destroy tile removedTile |= hexMap.TryRemovingTile(tile); } } if (removedTile) { MarkSceneDirty(); } } }) .Event("MouseUp", state => { // Flush list of modified chunks so that they are not included in // the next undo action. state.ModifiedChunks.Clear(); }) .End() .State <SettingsState>("Settings") .Enter(state => { selectedToolIndex = 4; state.HexSize = hexMap.tileDiameter; state.ChunkSize = hexMap.ChunkSize; showTileCoordinateFormat.value = hexMap.DrawHexPositionHandles; }) .Update((state, dt) => { EditorUtilities.ShowHelpBox("Settings", "Configure options for the whole tile map."); var shouldDrawPositionHandles = EditorGUILayout.Toggle("Show tile positions", hexMap.DrawHexPositionHandles); if (shouldDrawPositionHandles != hexMap.DrawHexPositionHandles) { hexMap.DrawHexPositionHandles = shouldDrawPositionHandles; SceneView.RepaintAll(); MarkSceneDirty(); showTileCoordinateFormat.target = shouldDrawPositionHandles; } if (EditorGUILayout.BeginFadeGroup(showTileCoordinateFormat.faded)) { var newHandleFormat = (HexTileMap.HexCoordinateFormat) EditorGUILayout.EnumPopup("Tile coordinate format", hexMap.HexPositionHandleFormat); if (newHandleFormat != hexMap.HexPositionHandleFormat) { hexMap.HexPositionHandleFormat = newHandleFormat; SceneView.RepaintAll(); } } EditorGUILayout.EndFadeGroup(); state.HexSize = EditorGUILayout.FloatField("Tile size", state.HexSize); if (state.HexSize != hexMap.tileDiameter) { state.Dirty = true; } var newChunkSize = EditorGUILayout.IntField("Chunk size", state.ChunkSize); if (state.ChunkSize != newChunkSize) { state.ChunkSize = newChunkSize; state.Dirty = true; } if (GUILayout.Button("Re-generate all tile geometry")) { hexMap.RegenerateAllTiles(); MarkSceneDirty(); } if (GUILayout.Button("Clear all tiles")) { if (EditorUtility.DisplayDialog("Clear all tiles", "Are you sure you want to delete all tiles in this hex tile map?", "Clear", "Cancel")) { hexMap.ClearAllTiles(); MarkSceneDirty(); } } EditorGUILayout.Space(); GUI.enabled = state.Dirty; EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Apply", GUILayout.Width(160))) { Debug.Log("Saving settings"); hexMap.tileDiameter = state.HexSize; hexMap.ChunkSize = state.ChunkSize; hexMap.RegenerateAllTiles(); MarkSceneDirty(); state.Dirty = false; } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); GUI.enabled = true; }) .End() .Build(); rootState.ChangeState("Select"); if (EditorGUIUtility.isProSkin) { toolIcons = new ButtonIcon[] { new ButtonIcon { NormalIcon = LoadImage("mouse-pointer_44_pro"), SelectedIcon = LoadImage("mouse-pointer_44_selected") }, new ButtonIcon { NormalIcon = LoadImage("add-hex_44_pro"), SelectedIcon = LoadImage("add-hex_44_selected") }, new ButtonIcon { NormalIcon = LoadImage("paint-brush_44_pro"), SelectedIcon = LoadImage("paint-brush_44_selected") }, new ButtonIcon { NormalIcon = LoadImage("eraser_44_pro"), SelectedIcon = LoadImage("eraser_44_selected") }, new ButtonIcon { NormalIcon = LoadImage("cog_44_pro"), SelectedIcon = LoadImage("cog_44_selected") }, }; } else { toolIcons = new ButtonIcon[] { new ButtonIcon { NormalIcon = LoadImage("mouse-pointer_44"), SelectedIcon = LoadImage("mouse-pointer_44_selected") }, new ButtonIcon { NormalIcon = LoadImage("add-hex_44"), SelectedIcon = LoadImage("add-hex_44_selected") }, new ButtonIcon { NormalIcon = LoadImage("paint-brush_44"), SelectedIcon = LoadImage("paint-brush_44_selected") }, new ButtonIcon { NormalIcon = LoadImage("eraser_44"), SelectedIcon = LoadImage("eraser_44_selected") }, new ButtonIcon { NormalIcon = LoadImage("cog_44"), SelectedIcon = LoadImage("cog_44_selected") }, }; } }