Files
BABA_YAGA/Assets/Scripts/GameSetup/Maze/Maze.cs

182 lines
6.0 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Fusion;
using OnlyScove.Scripts.GameSetup.Maze;
public class MapLocation
{
public int x;
public int z;
public MapLocation(int _x, int _z)
{
x = _x;
z = _z;
}
}
public class Maze : NetworkBehaviour
{
public List<MapLocation> directions = new List<MapLocation>() {
new MapLocation(1,0),
new MapLocation(0,1),
new MapLocation(-1,0),
new MapLocation(0,-1) };
public int width = 30; //x length
public int depth = 30; //z length
public byte[,] map;
public int scale = 6;
public Transform _mapParentObjet;
[Header("Sync & Materials")]
[Networked] public int MazeSeed { get; set; }
public Material wallMaterial;
public Material floorMaterial;
[Header("Win Condition")]
public GameObject goalPrefab;
public override void Spawned()
{
if (Object.HasStateAuthority)
{
// Nếu chưa có seed thì tạo mới
if (MazeSeed == 0) MazeSeed = Random.Range(1, 99999);
}
GenerateMazeWithSeed(MazeSeed);
}
public void GenerateMazeWithSeed(int seed)
{
if (_mapParentObjet != null)
{
// Dùng list để tránh lỗi modify collection khi đang duyệt
List<GameObject> children = new List<GameObject>();
foreach (Transform child in _mapParentObjet) children.Add(child.gameObject);
foreach (GameObject child in children) Destroy(child);
}
Random.InitState(seed);
InitialiseMap();
Generate();
// Ép ô (1,1) là đường đi cho player spawn
map[1, 1] = 0;
PlaceExit();
DrawMap();
}
public Vector3 GetPlayerSpawnPoint()
{
// Trả về vị trí tại ô (1,1). y = 1.0f cục bộ
return transform.TransformPoint(new Vector3(1 * scale, 1.0f, 1 * scale));
}
void InitialiseMap()
{
map = new byte[width,depth];
for (int z = 0; z < depth; z++)
for (int x = 0; x < width; x++)
{
map[x, z] = 1; //1 = wall 0 = corridor
}
}
public virtual void Generate()
{
for (int z = 0; z < depth; z++)
for (int x = 0; x < width; x++)
{
if(Random.Range(0,100) < 50)
map[x, z] = 0; //1 = wall 0 = corridor
}
}
public virtual void PlaceExit()
{
int x = width - 2;
int z = depth - 2;
map[x, z] = 2;
if (CountSquareNeighbours(x, z) == 0) map[x - 1, z] = 0;
}
void DrawMap()
{
if (_mapParentObjet == null) _mapParentObjet = this.transform;
// Tạo sàn chống rơi và Z-fighting
GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Plane);
floor.name = "Floor";
floor.transform.SetParent(_mapParentObjet);
floor.transform.localPosition = new Vector3((width - 1) * scale / 2f, -0.05f, (depth - 1) * scale / 2f);
floor.transform.localScale = new Vector3(width * scale / 10f, 1, depth * scale / 10f);
if (floorMaterial != null) floor.GetComponent<Renderer>().material = floorMaterial;
for (int z = 0; z < depth; z++)
for (int x = 0; x < width; x++)
{
Vector3 pos = new Vector3(x * scale, scale / 2f, z * scale);
if (map[x, z] == 1)
{
GameObject wall = GameObject.CreatePrimitive(PrimitiveType.Cube);
wall.name = $"Wall_{x}_{z}";
wall.transform.localScale = new Vector3(scale, scale, scale);
wall.transform.SetParent(_mapParentObjet);
wall.transform.localPosition = pos;
if (wallMaterial != null) wall.GetComponent<Renderer>().material = wallMaterial;
}
else if (map[x, z] == 2)
{
GameObject goalObj;
if (goalPrefab != null)
goalObj = Instantiate(goalPrefab, transform.TransformPoint(pos), Quaternion.identity);
else
{
goalObj = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
goalObj.GetComponent<Renderer>().material.color = Color.yellow;
goalObj.transform.localScale = new Vector3(scale * 0.5f, scale * 0.5f, scale * 0.5f);
}
goalObj.name = "Goal_WinSpot";
goalObj.transform.SetParent(_mapParentObjet);
goalObj.transform.localPosition = pos;
Collider col = goalObj.GetComponent<Collider>();
if (col == null) col = goalObj.AddComponent<CapsuleCollider>();
col.isTrigger = true;
if (goalObj.GetComponent<GoalSpot>() == null) goalObj.AddComponent<GoalSpot>();
}
}
}
public int CountSquareNeighbours(int x, int z)
{
int count = 0;
if (x <= 0 || x >= width - 1 || z <= 0 || z >= depth - 1) return 5;
if (map[x - 1, z] == 0) count++;
if (map[x + 1, z] == 0) count++;
if (map[x, z + 1] == 0) count++;
if (map[x, z - 1] == 0) count++;
return count;
}
public int CountDiagonalNeighbours(int x, int z)
{
int count = 0;
if (x <= 0 || x >= width - 1 || z <= 0 || z >= depth - 1) return 5;
if (map[x - 1, z - 1] == 0) count++;
if (map[x + 1, z + 1] == 0) count++;
if (map[x - 1, z + 1] == 0) count++;
if (map[x + 1, z - 1] == 0) count++;
return count;
}
public int CountAllNeighbours(int x, int z)
{
return CountSquareNeighbours(x,z) + CountDiagonalNeighbours(x,z);
}
}