Не удается проверить пересечение объекта по коллайдеру с другим объектом
Написал скрипт для генерации комнат и коридоров между ними, но бывает так, что ни пересекаются друг с другом, решил добавить проверку на пересечение с другой комнатой, и если она есть, то просто отмечать возможный выход комнаты как недоступный, что позволит не строить от него комнаты в дальнейшем, по итогу, попробовал разные варианты, но не один не дал того, что мне нужно.
Я решил повесить на префаб комнаты коллайдер, указать isTrigger = true, потом просто проверять через OverlapBox, он берет все коллайдеры, которые есть, поэтому по маске отсеиваю, чтобы взял только верхний коллайдер, который isTrigger = true (у меня на каждый тайл в комнате свой коллайдер, поэтому так).
Я попробовал убрать маску, по итогу у меня всегда одна комната, потому что он пересекается сам с собой, как я понял, я решил поменять проверку, чтобы не учитывать пересечения с дочерними коллайдерами префаба с помощью hits.Any(hit => hit.transform.root != newRoom.transform && hit.isTrigger);, но все равно проблему не решил
Текущий код скрипта:
using Assets.Scipts;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class LevelGenerator : MonoBehaviour
{
public GameObject CrossRoomPrefab;
public GameManager gameManager;
public GameObject AltarRoomPrefab;
public GameObject CorridorPrefab;
public GameObject EmptyRoomPrefab;
public GameObject WallExitPrefab;
public GameObject Player;
public int NumberOfRooms = 5;
public int NumberOfAltarRooms = 2;
private int AlreadyPickupedRunes = 0;
public double RadiusToCheckExistingOfAltars = 15;
public Vector3 StartPosition = Vector3.zero;
public event Action AllRunesCollectedEvent;
public event Action OneRuneCollectedEvent;
private List<GameObject> placedRooms = new List<GameObject>();
private List<RoomInfo> roomInfos = new List<RoomInfo>();
public List<Vector3> AltarRoomPositions = new List<Vector3>();
public void GenerateLevel()
{
GameObject startRoom = Instantiate(EmptyRoomPrefab, StartPosition, Quaternion.identity);
placedRooms.Add(startRoom);
roomInfos.Add(startRoom.GetComponent<RoomInfo>());
PlaceEmptyRooms();
PlaceAltarRooms();
CloseFreeExists();
}
RoomInfo FindFirstRoomWithFreeExit()
{
for (int i = 0; i < roomInfos.Count; i++)
{
if (roomInfos[i].FreeExits.Count > 0)
{
return roomInfos[i];
}
}
return null;
}
void OccupieExit(RoomInfo roomInfo, GameObject objectToOccupie)
{
roomInfo.OccupiedExits.Add(objectToOccupie);
roomInfo.FreeExits.Remove(objectToOccupie);
}
Transform FindFarthestFreeExitFromPoint(Vector3 pos)
{
Transform farthestExit = null;
float maxDistance = float.MinValue;
for (int i = 0; i < roomInfos.Count; i++)
{
for (int j = 0; j < roomInfos[i].FreeExits.Count; j++)
{
Transform freeExitTransform = roomInfos[i].FreeExits[j].transform;
float distance = Vector3.Distance(pos, freeExitTransform.position);
if (distance > maxDistance && !IsPositionTooCloseToAltarRooms(freeExitTransform.position))
{
maxDistance = distance;
farthestExit = roomInfos[i].FreeExits[j].transform;
}
}
}
return farthestExit;
}
bool IsPositionTooCloseToAltarRooms(Vector3 position)
{
foreach (Vector3 altarPosition in AltarRoomPositions)
{
if (Vector3.Distance(position, altarPosition) < RadiusToCheckExistingOfAltars)
{
return true;
}
}
return false;
}
void PlaceEmptyRooms()
{
for (int i = 0; i < NumberOfRooms; i++)
{
Transform oldExit = FindFirstRandomRoomWithFreeExit();
if (oldExit == null)
{
break;
}
Transform corridorExit;
PlaceCorridor(oldExit, out corridorExit);
GameObject newRoom = Instantiate(EmptyRoomPrefab);
Transform newRoomEntrance = newRoom.GetComponent<RoomInfo>().FreeExits.First().transform;
Quaternion roomRotation = Quaternion.FromToRotation(-newRoomEntrance.forward, corridorExit.forward);
newRoom.transform.rotation = roomRotation;
newRoom.transform.position = corridorExit.position - (newRoom.transform.rotation * newRoomEntrance.localPosition);
BoxCollider roomCollider = newRoom.GetComponent<BoxCollider>();
if (roomCollider != null)
{
Bounds bounds = roomCollider.bounds;
Vector3 center = bounds.center;
Vector3 halfExtents = bounds.extents;
LayerMask collisionMask = LayerMask.GetMask("Room");
Collider[] hits = Physics.OverlapBox(center, halfExtents, newRoom.transform.rotation, collisionMask);
bool overlaps = hits.Any(hit => hit.transform.root != newRoom.transform && hit.isTrigger);
if (overlaps)
{
Destroy(newRoom);
OccupieExit(corridorExit.GetComponentInParent<RoomInfo>(), corridorExit.gameObject);
continue;
}
}
RoomInfo newRoomInfo = newRoom.GetComponent<RoomInfo>();
placedRooms.Add(newRoom);
roomInfos.Add(newRoomInfo);
OccupieExit(newRoomInfo, newRoomEntrance.gameObject);
OccupieExit(corridorExit.GetComponentInParent<RoomInfo>(), corridorExit.gameObject);
}
}
void PlaceAltarRooms()
{
for (int i = 0; i < NumberOfAltarRooms; i++)
{
Transform farthestExit = FindFarthestFreeExitFromPoint(Vector3.zero);
if (farthestExit == null)
{
Debug.LogWarning("Нет доступных выходов для размещения комнаты с алтарём.");
break;
}
Transform corridorExit;
PlaceCorridor(farthestExit, out corridorExit);
Transform newRoomEntrance = AltarRoomPrefab.GetComponent<RoomInfo>().FreeExits.First().transform;
Quaternion rotationDifference = Quaternion.FromToRotation(-newRoomEntrance.forward, corridorExit.forward);
Vector3 newPosition = corridorExit.position - (rotationDifference * newRoomEntrance.localPosition);
GameObject newRoom = Instantiate(AltarRoomPrefab, newPosition, rotationDifference * AltarRoomPrefab.transform.rotation);
RoomInfo newRoomInfo = newRoom.GetComponent<RoomInfo>();
placedRooms.Add(newRoom);
roomInfos.Add(newRoomInfo);
AltarRoomPositions.Add(newPosition);
//OccupieExit(newRoomInfo, newRoomEntrance.gameObject);
OccupieExit(newRoomInfo, newRoom.GetComponent<RoomInfo>().FreeExits.First().transform.gameObject);
OccupieExit(corridorExit.GetComponentInParent<RoomInfo>(), corridorExit.gameObject);
}
}
void PlaceCorridor(Transform startPosition, out Transform otherExitFromCorridor)
{
GameObject corridor = Instantiate(CorridorPrefab);
Transform corridorEntrance = corridor.GetComponent<RoomInfo>().FreeExits.First().transform;
Quaternion corridorRotation = Quaternion.FromToRotation(-corridorEntrance.forward, startPosition.forward);
corridor.transform.rotation = corridorRotation;
corridor.transform.position = startPosition.position - (corridor.transform.rotation * corridorEntrance.localPosition);
RoomInfo corridorInfo = corridor.GetComponent<RoomInfo>();
placedRooms.Add(corridor);
roomInfos.Add(corridorInfo);
OccupieExit(corridorInfo, corridorEntrance.gameObject);
OccupieExit(startPosition.GetComponentInParent<RoomInfo>(), startPosition.gameObject);
Transform corridorExit = corridorInfo.FreeExits.First().transform;
otherExitFromCorridor = corridorExit;
}
Transform FindFirstRandomRoomWithFreeExit()
{
List<GameObject> exits = new List<GameObject>();
exits = roomInfos.Where(x => x.FreeExits.Count > 0).SelectMany(x => x.FreeExits).ToList();
if (exits.Count != 0)
{
System.Random rnd = new System.Random();
return exits.ElementAt(rnd.Next(exits.Count)).transform;
}
return null;
}
void CloseFreeExists()
{
List<GameObject> exits = new List<GameObject>();
exits = roomInfos.Where(x => x.FreeExits.Count > 0).SelectMany(x => x.FreeExits).ToList();
for (int i = 0; i < exits.Count; i++)
{
GameObject wall = Instantiate(WallExitPrefab);
Quaternion wallRotation; //= Quaternion.FromToRotation(-wall.transform.forward, exits[i].transform.forward);
wallRotation = Quaternion.LookRotation(-exits[i].transform.forward, Vector3.up);
wall.transform.rotation = wallRotation;
wall.transform.position = exits[i].transform.position;
OccupieExit(exits[i].GetComponentInParent<RoomInfo>(), wall);
}
}
void RuneWasPickuped()
{
AlreadyPickupedRunes++;
OneRuneCollectedEvent?.Invoke();
if (AlreadyPickupedRunes >= NumberOfAltarRooms)
{
AllRunesCollectedEvent?.Invoke();
}
}
public void SubscribeOnPlayer(Movement movement)
{
movement.RunePickuped += RuneWasPickuped;
}
}
Пример неудачной генерации

Префаб комнаты
