Код: Выделить всё
using UnityEngine;
using Unity.AI.Navigation;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
#endif
[ExecuteAlways]
public class MazeGenerator : MonoBehaviour
{
///
/// Defines the generation state of the maze.
///
public enum MazeState
{
NotStarted,
InProgress,
Done
}
[Header("Maze Size")]
public int width = 30;
public int height = 30;
// Read-only properties for external use
public int Width => width;
public int Height => height;
[Header("Prefabs")]
public GameObject wallPrefab;
public GameObject floorPrefab;
public GameObject entranceMarkerPrefab;
public GameObject exitMarkerPrefab;
public GameObject deadEndMarkerPrefab;
[Header("Options")]
public bool generateEntranceAndExit = true;
// Expose this list to other scripts.
public List DeadEndMarkers { get; private set; } = new List();
// Public property to check the current state of the maze generation
public MazeState CurrentState { get; private set; } = MazeState.NotStarted;
#if UNITY_EDITOR
[Tooltip("If true, the maze generated in Play Mode will persist in the editor after stopping Play Mode.")]
public bool persistRuntimeMazeOnStop = false;
#endif
// maze[x,y] == true => wall
// maze[x,y] == false => walkable path
// Add [SerializeField] to ensure this data is saved with the scene!
[SerializeField]
private bool[,] grid;
public bool[,] Grid => grid;
Код: Выделить всё
public void GenerateAndBuildMaze()
{
CurrentState = MazeState.InProgress;
ClearMaze();
ValidateMazeDimensions();
GenerateMaze();
BuildMaze();
CurrentState = MazeState.Done;
}
Код: Выделить всё
public void GenerateMaze()
{
grid = new bool[width, height];
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
grid[x, y] = true;
int startX = 1, startY = 1;
grid[startX, startY] = false;
CarvePath(startX, startY);
if (generateEntranceAndExit)
AddRandomEntranceAndExit();
}
Сценарий редактора:
Код: Выделить всё
using UnityEditor;
using UnityEditor.SceneManagement; // Added this using directive for MarkSceneDirty
using UnityEngine;
[CustomEditor(typeof(MazeGenerator))]
public class MazeGeneratorEditor : Editor
{
public override void OnInspectorGUI()
{
// Draw default inspector fields
DrawDefaultInspector();
MazeGenerator mazeGen = (MazeGenerator)target;
serializedObject.Update();
GUILayout.Space(10);
if (GUILayout.Button("Generate New Maze"))
{
Undo.RecordObject(mazeGen, "Generate New Maze");
mazeGen.GenerateAndBuildMaze();
//
// FIX: Pass the transform of the MazeGenerator object (this is the parent transform)
if (mazeGen.generateEntranceAndExit && mazeGen.Grid != null)
{
// We need to use the transform of the MazeGenerator itself here,
// as that's the parent transform for the visualization in the Editor.
// NOTE: When running the game, MazeGenerator.GenerateNewMaze() passes _currentMaze.transform.
// For Editor visualization, using mazeGen.transform is correct.
MazePathfinder.FindPath(
mazeGen.Grid,
mazeGen.EntranceGridPos,
mazeGen.ExitGridPos,
mazeGen.transform
);
}
//
// The NPC Spawner logic might be redundant if the new MazeGenerator.GenerateNewMaze()
// already handles the NPC, but keeping it here as a placeholder for external spawning:
MarkSceneDirty(mazeGen);
}
if (GUILayout.Button("Clear Maze"))
{
Undo.RecordObject(mazeGen, "Clear Maze");
mazeGen.ClearMaze();
MazePathfinder.LastGeneratedPath.Clear();
MarkSceneDirty(mazeGen);
}
serializedObject.ApplyModifiedProperties();
SceneView.RepaintAll();
}
private void MarkSceneDirty(MazeGenerator mazeGen)
{
if (!Application.isPlaying)
{
EditorUtility.SetDirty(mazeGen);
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(mazeGen.gameObject.scene);
}
}
}
Код: Выделить всё
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NPCMovement : MonoBehaviour
{
[Header("Movement Settings")]
public float MoveSpeed = 5f;
public float RotationSpeed = 720f;
[Header("Automatic Start")]
[Tooltip("If true, the NPC will automatically try to find the maze path and start moving upon scene load.")]
public bool StartMovementOnStart = true;
[Header("Path Visualization")]
[Tooltip("If true, draws a cyan line trail behind the NPC in the Scene View (runtime only).")]
public bool DrawTrailGizmo = true;
private List _path;
private int _pathIndex = 0;
private List _trailHistory = new List();
private bool _isMoving = false;
private Vector3 _targetPosition;
// --- Core Logic: Check for and initiate movement on start ---
private void Start()
{
// 1. Check the control flag set in the Inspector
if (!StartMovementOnStart) return;
// 2. Find the MazeGenerator in the scene
MazeGenerator mazeGen = Object.FindFirstObjectByType();
if (mazeGen == null)
{
Debug.LogError("NPCMovement: Cannot find MazeGenerator in the scene. Movement aborted.");
return;
}
// 3. Ensure the maze grid data is available
if (mazeGen.Grid == null)
{
Debug.LogWarning("NPCMovement: MazeGenerator grid is null. Cannot calculate path at runtime. Please ensure the maze has been generated and persisted in the scene.");
return;
}
я думал, что использую [SerializeField], а затем, как только вы нажмете кнопку для создания нового лабиринта, сетка будет сохранена, и я смогу затем использовать ее в последнем скрипте, и она не будет нулевой.
потому что я сгенерировал в режиме редактора скрипт один раз, а лабиринт существует в редакторе перед запуском игры, я хочу использовать существующий лабиринт и сетка в сценарии движения при запуске игры без создания нового лабиринта.

Подробнее здесь: https://stackoverflow.com/questions/798 ... -maze-with
Мобильная версия