| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795 |
- using UnityEngine;
- using System.Collections.Generic;
- /// <summary>
- /// Generates 3D meshes for maze walls and floors instead of using tilemaps
- /// Much more efficient for large mazes and allows for better performance
- /// </summary>
- public class MeshMazeRenderer : MonoBehaviour
- {
- [Header("Maze Setup")]
- [SerializeField] private MazeController mazeController;
- [Header("Materials")]
- [SerializeField] private Material floorMaterial;
- [SerializeField] private Material wallMaterial;
- [Header("Start/End Markers")]
- [SerializeField] private GameObject startMarkerPrefab;
- [SerializeField] private GameObject exitMarkerPrefab;
- [SerializeField] private Color startMarkerColor = new Color(0f, 1f, 0f, 0.65f);
- [SerializeField] private Color exitMarkerColor = new Color(1f, 0f, 0f, 0.65f);
- [SerializeField] private float markerSize = 3f;
- [SerializeField] private bool showStartEndRoomHighlights = true;
- [SerializeField] private Color startRoomHighlightColor = new Color(0f, 1f, 0f, 0.25f);
- [SerializeField] private Color exitRoomHighlightColor = new Color(1f, 0f, 0f, 0.25f);
- [Header("Fog of War")]
- [SerializeField] private bool showFogOfWar = true;
- [SerializeField] private MazeFogOfWar fogOfWar;
- [SerializeField] private Color fogColor = new Color(0f, 0f, 0f, 0.6f);
- [Header("Mesh Settings")]
- [SerializeField] private float wallHeight = 2f;
- [SerializeField] private float tileSize = 1f;
- [SerializeField] private bool generateFloor = true;
- [SerializeField] private bool generateWalls = true;
- [SerializeField] private bool twoSidedWalls = true;
- [SerializeField] private bool wallCaps = true;
- [Header("Optimization")]
- [SerializeField] private int chunkSize = 32;
- [SerializeField] private int renderDistance = 2;
- private Dictionary<Vector2Int, GameObject> chunkObjects = new();
- private Transform cameraTransform;
- private GameObject markerContainer;
- private GameObject fogOfWarContainer;
- private bool lastFogVisible;
- void OnEnable()
- {
- if (mazeController == null)
- {
- mazeController = GetComponent<MazeController>();
- }
- }
- void Start()
- {
- cameraTransform = Camera.main?.transform;
- lastFogVisible = showFogOfWar;
- if (mazeController != null && mazeController.GetCurrentMaze() != null)
- {
- GenerateMazeMesh();
- }
- }
- void Update()
- {
- if (cameraTransform != null)
- {
- UpdateVisibleChunks();
- }
- if (showFogOfWar != lastFogVisible)
- {
- UpdateFogVisibility();
- }
- else if (fogOfWarContainer == null && showFogOfWar && fogOfWar != null)
- {
- UpdateFogVisibility();
- }
- }
- /// <summary>
- /// Generates the complete maze mesh
- /// </summary>
- public void GenerateMazeMesh()
- {
- if (mazeController == null)
- {
- mazeController = GetComponent<MazeController>();
- }
- if (mazeController == null)
- {
- Debug.LogError("MeshMazeRenderer requires a MazeController reference.");
- return;
- }
- if (fogOfWar == null)
- {
- fogOfWar = GetComponent<MazeFogOfWar>() ?? FindAnyObjectByType<MazeFogOfWar>();
- }
- ClearChunks();
- ClearMarkers();
- ClearFogOfWar();
- var maze = mazeController.GetCurrentMaze();
- if (maze == null)
- {
- Debug.LogWarning("No maze to render yet. Generate the maze first, then refresh the mesh.");
- return;
- }
- Debug.Log($"MeshMazeRenderer: rendering maze {maze.Width}x{maze.Height} with {maze.Rooms.Count} rooms");
- // For very large mazes, use chunked generation
- if (maze.Width > chunkSize || maze.Height > chunkSize)
- {
- GenerateChunkedMesh(maze);
- }
- else
- {
- GenerateSingleMesh(maze);
- }
- RenderStartExitMarkers(maze);
- if (showFogOfWar && fogOfWar != null)
- {
- RenderFogOfWar(maze);
- }
- }
- /// <summary>
- /// Generates a single mesh for smaller mazes
- /// </summary>
- private void GenerateSingleMesh(MazeData maze)
- {
- GameObject chunkObj = new GameObject("MazeMesh");
- chunkObj.transform.parent = transform;
- chunkObj.transform.localPosition = Vector3.zero;
- MeshFilter meshFilter = chunkObj.AddComponent<MeshFilter>();
- MeshRenderer meshRenderer = chunkObj.AddComponent<MeshRenderer>();
- Mesh mesh = CreateMazeMesh(maze, 0, 0, maze.Width, maze.Height);
- meshFilter.mesh = mesh;
- // Assign materials
- Material[] materials = new Material[generateFloor && generateWalls ? 2 : 1];
- int matIndex = 0;
- if (generateFloor) materials[matIndex++] = floorMaterial;
- if (generateWalls) materials[matIndex++] = wallMaterial;
- meshRenderer.materials = materials;
- chunkObjects[new Vector2Int(0, 0)] = chunkObj;
- }
- /// <summary>
- /// Generates chunked meshes for large mazes
- /// </summary>
- private void GenerateChunkedMesh(MazeData maze)
- {
- int chunksX = Mathf.CeilToInt((float)maze.Width / chunkSize);
- int chunksY = Mathf.CeilToInt((float)maze.Height / chunkSize);
- for (int cx = 0; cx < chunksX; cx++)
- {
- for (int cy = 0; cy < chunksY; cy++)
- {
- Vector2Int chunkPos = new Vector2Int(cx, cy);
- CreateChunkMesh(maze, chunkPos);
- }
- }
- }
- /// <summary>
- /// Creates a mesh for a single chunk
- /// </summary>
- private void CreateChunkMesh(MazeData maze, Vector2Int chunkPos)
- {
- int startX = chunkPos.x * chunkSize;
- int startY = chunkPos.y * chunkSize;
- int endX = Mathf.Min(startX + chunkSize, maze.Width);
- int endY = Mathf.Min(startY + chunkSize, maze.Height);
- GameObject chunkObj = new GameObject($"Chunk_{chunkPos.x}_{chunkPos.y}");
- chunkObj.transform.parent = transform;
- chunkObj.transform.localPosition = new Vector3(startX * tileSize, 0, startY * tileSize);
- MeshFilter meshFilter = chunkObj.AddComponent<MeshFilter>();
- MeshRenderer meshRenderer = chunkObj.AddComponent<MeshRenderer>();
- Mesh mesh = CreateMazeMesh(maze, startX, startY, endX - startX, endY - startY);
- meshFilter.mesh = mesh;
- // Assign materials
- Material[] materials = new Material[generateFloor && generateWalls ? 2 : 1];
- int matIndex = 0;
- if (generateFloor) materials[matIndex++] = floorMaterial;
- if (generateWalls) materials[matIndex++] = wallMaterial;
- meshRenderer.materials = materials;
- chunkObjects[chunkPos] = chunkObj;
- }
- private void RenderStartExitMarkers(MazeData maze)
- {
- if (markerContainer != null)
- {
- Destroy(markerContainer);
- }
- markerContainer = new GameObject("MazeMarkers");
- markerContainer.transform.parent = transform;
- markerContainer.transform.localPosition = Vector3.zero;
- markerContainer.transform.localRotation = Quaternion.identity;
- foreach (var start in maze.StartPoints)
- {
- CreateMarker(maze, start, startMarkerPrefab, startMarkerColor, "StartMarker", startRoomHighlightColor);
- }
- foreach (var exit in maze.ExitPoints)
- {
- CreateMarker(maze, exit, exitMarkerPrefab, exitMarkerColor, "ExitMarker", exitRoomHighlightColor);
- }
- }
- private void CreateMarker(MazeData maze, Vector2Int tilePos, GameObject prefab, Color color, string namePrefix, Color roomHighlight)
- {
- Vector3 markerPos = new Vector3(tilePos.x * tileSize + tileSize * 0.5f, 0.1f, tilePos.y * tileSize + tileSize * 0.5f);
- GameObject marker = prefab != null ? Instantiate(prefab, markerContainer.transform) : null;
- if (marker == null)
- {
- marker = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
- marker.transform.parent = markerContainer.transform;
- marker.transform.localPosition = markerPos;
- marker.transform.localScale = new Vector3(markerSize, markerSize * 0.2f, markerSize);
- DestroyImmediate(marker.GetComponent<Collider>());
- var renderer = marker.GetComponent<MeshRenderer>();
- renderer.material = CreateURPUnlitColorMaterial(color, true);
- renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
- renderer.receiveShadows = false;
- }
- else
- {
- marker.transform.parent = markerContainer.transform;
- marker.transform.localPosition = markerPos;
- marker.transform.localRotation = Quaternion.identity;
- marker.transform.localScale = Vector3.one * markerSize;
- var renderer = marker.GetComponent<MeshRenderer>();
- if (renderer != null)
- {
- renderer.material = CreateURPUnlitColorMaterial(color, true);
- renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
- renderer.receiveShadows = false;
- }
- }
- marker.name = namePrefix + "_" + tilePos.x + "_" + tilePos.y;
- if (showStartEndRoomHighlights)
- {
- var room = maze.GetRoomAtTile(tilePos.x, tilePos.y);
- if (room != null)
- {
- CreateRoomHighlight(room, roomHighlight);
- }
- }
- }
- private void CreateRoomHighlight(MazeRoom room, Color highlightColor)
- {
- if (room == null) return;
- GameObject highlight = new GameObject("RoomHighlight_" + room.Id);
- highlight.transform.parent = markerContainer.transform;
- highlight.transform.localPosition = Vector3.zero;
- var meshFilter = highlight.AddComponent<MeshFilter>();
- var meshRenderer = highlight.AddComponent<MeshRenderer>();
- meshRenderer.material = CreateURPUnlitColorMaterial(highlightColor, true);
- meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
- meshRenderer.receiveShadows = false;
- Mesh mesh = new Mesh();
- float minX = room.MinX * tileSize;
- float maxX = (room.MaxX + 1) * tileSize;
- float minZ = room.MinY * tileSize;
- float maxZ = (room.MaxY + 1) * tileSize;
- float y = 0.15f;
- mesh.vertices = new Vector3[] {
- new Vector3(minX, y, minZ),
- new Vector3(maxX, y, minZ),
- new Vector3(maxX, y, maxZ),
- new Vector3(minX, y, maxZ)
- };
- mesh.uv = new Vector2[] {
- new Vector2(0,0),
- new Vector2(1,0),
- new Vector2(1,1),
- new Vector2(0,1)
- };
- mesh.triangles = new int[] { 0, 1, 2, 0, 2, 3 };
- mesh.RecalculateNormals();
- meshFilter.mesh = mesh;
- }
- private void ClearMarkers()
- {
- if (markerContainer != null)
- {
- Destroy(markerContainer);
- markerContainer = null;
- }
- }
- private void ClearFogOfWar()
- {
- if (fogOfWarContainer != null)
- {
- Destroy(fogOfWarContainer);
- fogOfWarContainer = null;
- }
- }
- /// <summary>
- /// Toggles fog of war visibility
- /// </summary>
- public void ToggleFogOfWar()
- {
- showFogOfWar = !showFogOfWar;
- UpdateFogVisibility();
- }
- /// <summary>
- /// Sets fog of war visibility
- /// </summary>
- public void SetFogOfWarVisible(bool visible)
- {
- showFogOfWar = visible;
- UpdateFogVisibility();
- }
- /// <summary>
- /// Refreshes the fog of war display (call this when entity vision changes)
- /// </summary>
- public void RefreshFogOfWar()
- {
- var maze = mazeController?.GetCurrentMaze();
- if (maze != null && showFogOfWar && fogOfWar != null)
- {
- ClearFogOfWar();
- RenderFogOfWar(maze);
- }
- }
- private void UpdateFogVisibility()
- {
- if (showFogOfWar && fogOfWar != null)
- {
- if (fogOfWarContainer == null)
- {
- var maze = mazeController?.GetCurrentMaze();
- if (maze != null)
- {
- RenderFogOfWar(maze);
- }
- }
- else if (!fogOfWarContainer.activeSelf)
- {
- fogOfWarContainer.SetActive(true);
- }
- }
- else if (fogOfWarContainer != null)
- {
- fogOfWarContainer.SetActive(false);
- }
- lastFogVisible = showFogOfWar;
- }
- /// <summary>
- /// Creates a URP-compatible unlit material for color overlays.
- /// </summary>
- private Material CreateURPUnlitColorMaterial(Color color, bool transparent)
- {
- Shader shader = Shader.Find("Universal Render Pipeline/Unlit");
- if (shader == null)
- {
- shader = Shader.Find("Unlit/Color");
- }
- Material material = new Material(shader);
- // Always set base color with alpha
- if (material.HasProperty("_BaseColor"))
- {
- material.SetColor("_BaseColor", color);
- }
- else if (material.HasProperty("_Color"))
- {
- material.SetColor("_Color", color);
- }
- else
- {
- material.color = color;
- }
- if (transparent)
- {
- // Enable alpha blending for transparency
- material.SetFloat("_AlphaClip", 0);
- if (material.HasProperty("_Surface"))
- {
- material.SetFloat("_Surface", 1f);
- }
- if (material.HasProperty("_Blend"))
- {
- material.SetFloat("_Blend", 0f);
- }
- if (material.HasProperty("_Cull"))
- {
- material.SetFloat("_Cull", 0f);
- }
- material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
- material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
- material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
- material.SetInt("_ZWrite", 0);
- material.EnableKeyword("_ALPHABLEND_ON");
- }
- else if (material.HasProperty("_Cull"))
- {
- material.SetFloat("_Cull", 0f);
- }
- return material;
- }
- /// <summary>
- /// Renders the fog of war overlay
- /// </summary>
- private void RenderFogOfWar(MazeData maze)
- {
- if (fogOfWarContainer != null)
- {
- Destroy(fogOfWarContainer);
- }
- fogOfWarContainer = new GameObject("FogOfWar");
- fogOfWarContainer.transform.parent = transform;
- fogOfWarContainer.transform.localPosition = Vector3.zero;
- fogOfWarContainer.transform.localRotation = Quaternion.identity;
- fogOfWarContainer.SetActive(showFogOfWar);
- var fogMesh = new Mesh();
- var vertices = new List<Vector3>();
- var uvs = new List<Vector2>();
- var triangles = new List<int>();
- Material fogMaterial = CreateURPUnlitColorMaterial(fogColor, true);
- HashSet<Vector2Int> exploredTiles = fogOfWar.GetExploredTiles();
- int vertexIndex = 0;
- for (int x = 0; x < maze.Width; x++)
- {
- for (int y = 0; y < maze.Height; y++)
- {
- Vector2Int tilePos = new Vector2Int(x, y);
- if (!exploredTiles.Contains(tilePos))
- {
- float posX = x * tileSize;
- float posZ = y * tileSize;
- vertices.Add(new Vector3(posX, 0.08f, posZ));
- vertices.Add(new Vector3(posX + tileSize, 0.08f, posZ));
- vertices.Add(new Vector3(posX + tileSize, 0.08f, posZ + tileSize));
- vertices.Add(new Vector3(posX, 0.08f, posZ + tileSize));
- uvs.Add(new Vector2(0, 0));
- uvs.Add(new Vector2(1, 0));
- uvs.Add(new Vector2(1, 1));
- uvs.Add(new Vector2(0, 1));
- triangles.Add(vertexIndex);
- triangles.Add(vertexIndex + 1);
- triangles.Add(vertexIndex + 2);
- triangles.Add(vertexIndex);
- triangles.Add(vertexIndex + 2);
- triangles.Add(vertexIndex + 3);
- vertexIndex += 4;
- }
- }
- }
- fogMesh.SetVertices(vertices);
- fogMesh.SetUVs(0, uvs);
- fogMesh.SetTriangles(triangles, 0);
- fogMesh.RecalculateNormals();
- fogMesh.RecalculateBounds();
- GameObject fogOverlay = new GameObject("FogOverlay");
- fogOverlay.transform.parent = fogOfWarContainer.transform;
- fogOverlay.transform.localPosition = Vector3.zero;
- fogOverlay.transform.localRotation = Quaternion.identity;
- var fogFilter = fogOverlay.AddComponent<MeshFilter>();
- var fogRenderer = fogOverlay.AddComponent<MeshRenderer>();
- fogFilter.mesh = fogMesh;
- fogRenderer.material = fogMaterial;
- fogRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
- fogRenderer.receiveShadows = false;
- }
- /// <summary>
- /// Creates the actual mesh data for a maze section
- /// </summary>
- private Mesh CreateMazeMesh(MazeData maze, int offsetX, int offsetY, int width, int height)
- {
- Mesh mesh = new Mesh();
- List<Vector3> vertices = new List<Vector3>();
- List<Vector2> uvs = new List<Vector2>();
- List<int> floorTriangles = new List<int>();
- List<int> wallTriangles = new List<int>();
- // Generate floor and walls
- for (int x = 0; x < width; x++)
- {
- for (int y = 0; y < height; y++)
- {
- int worldX = offsetX + x;
- int worldY = offsetY + y;
- var tile = maze.GetTile(worldX, worldY);
- if (tile == null) continue;
- float posX = x * tileSize;
- float posZ = y * tileSize;
- if (generateFloor && tile.IsWalkable())
- {
- // Floor quad
- int vertStart = vertices.Count;
- vertices.Add(new Vector3(posX, 0, posZ));
- vertices.Add(new Vector3(posX + tileSize, 0, posZ));
- vertices.Add(new Vector3(posX + tileSize, 0, posZ + tileSize));
- vertices.Add(new Vector3(posX, 0, posZ + tileSize));
- // UVs for floor
- uvs.Add(new Vector2(0, 0));
- uvs.Add(new Vector2(1, 0));
- uvs.Add(new Vector2(1, 1));
- uvs.Add(new Vector2(0, 1));
- // Floor triangles
- floorTriangles.Add(vertStart);
- floorTriangles.Add(vertStart + 1);
- floorTriangles.Add(vertStart + 2);
- floorTriangles.Add(vertStart);
- floorTriangles.Add(vertStart + 2);
- floorTriangles.Add(vertStart + 3);
- }
- if (generateWalls && tile.Type == MazeTile.TileType.Wall)
- {
- // Wall quads for each side that's exposed
- CreateWallQuads(vertices, uvs, wallTriangles, posX, posZ, tileSize, wallHeight,
- maze, worldX, worldY);
- // Add a top cap so walls remain visible in direct top-down view
- if (wallCaps)
- {
- CreateWallTop(vertices, uvs, wallTriangles, posX, posZ, tileSize, wallHeight);
- }
- }
- }
- }
- mesh.vertices = vertices.ToArray();
- mesh.uv = uvs.ToArray();
- // Combine submeshes
- mesh.subMeshCount = (generateFloor ? 1 : 0) + (generateWalls ? 1 : 0);
- int submeshIndex = 0;
- if (generateFloor)
- {
- mesh.SetTriangles(floorTriangles.ToArray(), submeshIndex++);
- }
- if (generateWalls)
- {
- mesh.SetTriangles(wallTriangles.ToArray(), submeshIndex);
- }
- mesh.RecalculateNormals();
- mesh.RecalculateBounds();
- return mesh;
- }
- /// <summary>
- /// Creates wall quads for exposed sides
- /// </summary>
- private void CreateWallQuads(List<Vector3> vertices, List<Vector2> uvs, List<int> triangles,
- float posX, float posZ, float size, float height,
- MazeData maze, int worldX, int worldY)
- {
- // Check each direction for exposed walls
- Vector2Int[] directions = {
- new Vector2Int(0, 1), // North
- new Vector2Int(1, 0), // East
- new Vector2Int(0, -1), // South
- new Vector2Int(-1, 0) // West
- };
- foreach (var dir in directions)
- {
- int checkX = worldX + dir.x;
- int checkY = worldY + dir.y;
- // If neighbor is not a wall or is out of bounds, create wall face
- if (!maze.IsInBounds(checkX, checkY) || maze.GetTile(checkX, checkY).Type != MazeTile.TileType.Wall)
- {
- CreateWallQuad(vertices, uvs, triangles, posX, posZ, size, height, dir);
- }
- }
- }
- /// <summary>
- /// Creates a single wall quad
- /// </summary>
- private void CreateWallQuad(List<Vector3> vertices, List<Vector2> uvs, List<int> triangles,
- float posX, float posZ, float size, float height, Vector2Int direction)
- {
- int vertStart = vertices.Count;
- // Determine quad vertices based on direction
- Vector3 v0, v1, v2, v3;
- if (direction == Vector2Int.up) // North face
- {
- v0 = new Vector3(posX, 0, posZ + size);
- v1 = new Vector3(posX + size, 0, posZ + size);
- v2 = new Vector3(posX + size, height, posZ + size);
- v3 = new Vector3(posX, height, posZ + size);
- }
- else if (direction == Vector2Int.right) // East face
- {
- v0 = new Vector3(posX + size, 0, posZ);
- v1 = new Vector3(posX + size, 0, posZ + size);
- v2 = new Vector3(posX + size, height, posZ + size);
- v3 = new Vector3(posX + size, height, posZ);
- }
- else if (direction == Vector2Int.down) // South face
- {
- v0 = new Vector3(posX + size, 0, posZ);
- v1 = new Vector3(posX, 0, posZ);
- v2 = new Vector3(posX, height, posZ);
- v3 = new Vector3(posX + size, height, posZ);
- }
- else // West face
- {
- v0 = new Vector3(posX, 0, posZ + size);
- v1 = new Vector3(posX, 0, posZ);
- v2 = new Vector3(posX, height, posZ);
- v3 = new Vector3(posX, height, posZ + size);
- }
- vertices.Add(v0);
- vertices.Add(v1);
- vertices.Add(v2);
- vertices.Add(v3);
- // UVs
- uvs.Add(new Vector2(0, 0));
- uvs.Add(new Vector2(1, 0));
- uvs.Add(new Vector2(1, 1));
- uvs.Add(new Vector2(0, 1));
- // Front-facing triangles
- triangles.Add(vertStart);
- triangles.Add(vertStart + 1);
- triangles.Add(vertStart + 2);
- triangles.Add(vertStart);
- triangles.Add(vertStart + 2);
- triangles.Add(vertStart + 3);
- // Optionally duplicate the face for the opposite side
- if (twoSidedWalls)
- {
- triangles.Add(vertStart + 2);
- triangles.Add(vertStart + 1);
- triangles.Add(vertStart);
- triangles.Add(vertStart + 3);
- triangles.Add(vertStart + 2);
- triangles.Add(vertStart + 0);
- }
- }
- /// <summary>
- /// Creates a top cap for a wall tile so it remains visible from above
- /// </summary>
- private void CreateWallTop(List<Vector3> vertices, List<Vector2> uvs, List<int> triangles,
- float posX, float posZ, float size, float height)
- {
- int vertStart = vertices.Count;
- vertices.Add(new Vector3(posX, height, posZ));
- vertices.Add(new Vector3(posX + size, height, posZ));
- vertices.Add(new Vector3(posX + size, height, posZ + size));
- vertices.Add(new Vector3(posX, height, posZ + size));
- uvs.Add(new Vector2(0, 0));
- uvs.Add(new Vector2(1, 0));
- uvs.Add(new Vector2(1, 1));
- uvs.Add(new Vector2(0, 1));
- triangles.Add(vertStart);
- triangles.Add(vertStart + 1);
- triangles.Add(vertStart + 2);
- triangles.Add(vertStart);
- triangles.Add(vertStart + 2);
- triangles.Add(vertStart + 3);
- if (twoSidedWalls)
- {
- triangles.Add(vertStart + 2);
- triangles.Add(vertStart + 1);
- triangles.Add(vertStart);
- triangles.Add(vertStart + 3);
- triangles.Add(vertStart + 2);
- triangles.Add(vertStart + 0);
- }
- }
- /// <summary>
- /// Updates which chunks are visible
- /// </summary>
- private void UpdateVisibleChunks()
- {
- if (chunkObjects.Count <= 1) return; // No chunking used
- Vector2Int cameraChunk = WorldToChunk(cameraTransform.position);
- foreach (var chunk in chunkObjects)
- {
- Vector2Int chunkPos = chunk.Key;
- bool isVisible = Mathf.Abs(chunkPos.x - cameraChunk.x) <= renderDistance &&
- Mathf.Abs(chunkPos.y - cameraChunk.y) <= renderDistance;
- chunk.Value.SetActive(isVisible);
- }
- }
- /// <summary>
- /// Converts world position to chunk coordinates
- /// </summary>
- private Vector2Int WorldToChunk(Vector3 worldPos)
- {
- return new Vector2Int(
- Mathf.FloorToInt(worldPos.x / (chunkSize * tileSize)),
- Mathf.FloorToInt(worldPos.z / (chunkSize * tileSize))
- );
- }
- /// <summary>
- /// Clears all chunk objects
- /// </summary>
- private void ClearChunks()
- {
- foreach (var chunk in chunkObjects.Values)
- {
- Destroy(chunk);
- }
- chunkObjects.Clear();
- }
- /// <summary>
- /// Regenerates the mesh
- /// </summary>
- public void RefreshMesh()
- {
- GenerateMazeMesh();
- }
- }
|