예제 #1
0
        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")
                    },
                };
            }
        }