376 lines
14 KiB
C#
376 lines
14 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Threading.Tasks;
|
||
using Cysharp.Threading.Tasks;
|
||
using Stary.Evo;
|
||
using UnityEngine;
|
||
|
||
namespace Main
|
||
{
|
||
public interface IZoneSystem
|
||
{
|
||
string CurrentZoneType { get; set; }
|
||
string CurrentPointType { get; set; }
|
||
|
||
/// <summary>
|
||
/// 当进去区域的最后一个小点位的区域范围时,开启下一区域的第一个小点位 和 关闭上一区域的最后一个小点位
|
||
/// </summary>
|
||
public void OpenNextZonePoint(ZoneController zoneController);
|
||
|
||
void HideBigMeshColliderStayUnRegister();
|
||
void OpenDomain(string domainName);
|
||
|
||
/// <summary>
|
||
/// 绑定区域碰撞事件
|
||
/// </summary>
|
||
/// <param name="zoneId">区域名称</param>
|
||
/// <param name="onColliderEnter">进入事件</param>
|
||
/// <param name="onColliderStay">停留事件</param>
|
||
/// <param name="onColliderExit">退出事件</param>
|
||
void AddOnZoneColliderEvent(string zoneId, Action<Collider> onColliderEnter = null,
|
||
Action<Collider> onColliderStay = null, Action<Collider> onColliderExit = null);
|
||
|
||
/// <summary>
|
||
/// 绑定点位碰撞事件
|
||
/// </summary>
|
||
/// <param name="pointId">点位名称</param>
|
||
/// <param name="onColliderEnter">进入事件</param>
|
||
void AddOnPointColliderEvent(string pointId, Action<Collider> onColliderEnter = null);
|
||
}
|
||
|
||
public abstract class ZoneSystemBase : IZoneSystem
|
||
{
|
||
private ZoneController[] zoneControllers;
|
||
private List<PointController> pointControllers = new List<PointController>();
|
||
|
||
/// <summary>
|
||
/// mask遮罩大点位触发区域
|
||
/// </summary>
|
||
private MeshCollider[] _meshBigColliders;
|
||
|
||
|
||
/// <summary>
|
||
/// 当前在的区域范围
|
||
/// </summary>
|
||
public string CurrentZoneType { get; set; }
|
||
|
||
/// <summary>
|
||
/// 当前触发的点位
|
||
/// </summary>
|
||
public string CurrentPointType { get; set; }
|
||
|
||
|
||
/// <summary>
|
||
/// 初始化点位物体
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public abstract Task<GameObject> InitZonePoint();
|
||
|
||
/// <summary>
|
||
/// 初始化区域
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public abstract Task<GameObject> InitZoneMask();
|
||
|
||
/// <summary>
|
||
/// 初始化区域数据
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public abstract Task<PointGatherData> InitZoneData();
|
||
|
||
|
||
public ZoneSystemBase(Transform parent)
|
||
{
|
||
CreatZone(parent);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建zone碰撞盒
|
||
/// </summary>
|
||
private async UniTask CreatZone(Transform parent)
|
||
{
|
||
//检测环境是否正常
|
||
if (!HasValidGameController())
|
||
{
|
||
// 抛出异常或返回空服务
|
||
Debug.LogError(
|
||
$"请检查相机环境 1、是否存在GameController物体 2、是否存在BoxCollider,3、GameController物体的tag是否为GameController");
|
||
}
|
||
|
||
|
||
//读取配置文件
|
||
var pointGatherData = await InitZoneData();
|
||
if (pointGatherData == null)
|
||
{
|
||
Debug.LogError("点位数据为空,请先初始化点位数据");
|
||
}
|
||
|
||
PointCloudService.RegisterService<IZoneData>(new ZoneGatherData(pointGatherData));
|
||
|
||
var zoneDatas = PointCloudService.GetService<IZoneData>().GetZoneDataAll();
|
||
zoneControllers = new ZoneController[zoneDatas.Length];
|
||
//加载遮罩数据
|
||
var zoneMask = await InitZoneMask();
|
||
if (zoneMask == null)
|
||
{
|
||
Debug.LogError("区域遮罩碰撞体为空,请先初始化区域遮罩碰撞体");
|
||
}
|
||
|
||
var zoneMaskTransform = GameObject.Instantiate(zoneMask, parent);
|
||
_meshBigColliders = zoneMaskTransform.transform.Find("AreaDetermination")
|
||
.GetComponentsInChildren<MeshCollider>();
|
||
//初始化点位物体
|
||
var zonePoint = await InitZonePoint();
|
||
if (zonePoint == null)
|
||
{
|
||
Debug.LogError("点位物体为空,请先初始化点位物体");
|
||
}
|
||
|
||
//生成区域
|
||
for (int i = 0; i < zoneDatas.Length; i++)
|
||
{
|
||
var zoneGo = new GameObject(zoneDatas[i].name, typeof(ZoneController));
|
||
zoneGo.Parent(parent);
|
||
// //ip漫游点位数据赋值
|
||
// this.GetSystem<IDigitalHuman>().AddPointData(new DigitalHumanPointData()
|
||
// {
|
||
// pointType = Enum.Parse<PointType>(zoneDatas[i].name),
|
||
// pointTransform = zoneColliderPoint.transform
|
||
// });
|
||
var zoneController = zoneGo.GetComponent<ZoneController>();
|
||
zoneControllers[i] = zoneController;
|
||
await zoneController.Init(zoneDatas[i]);
|
||
|
||
//生成点位
|
||
var pointDatas = zoneDatas[i].pointDatas;
|
||
foreach (var pointData in pointDatas)
|
||
{
|
||
var pointGo = GameObject.Instantiate(zonePoint, zoneGo.transform);
|
||
PointController pointController = pointGo.GetOrAddComponent<PointController>();
|
||
|
||
zoneController.pointControllerEntities.Add(pointController);
|
||
pointControllers.Add(pointController);
|
||
pointController.Init(zoneController, pointData);
|
||
}
|
||
}
|
||
|
||
for (int i = 0; i < zoneControllers.Length; i++)
|
||
{
|
||
var bigMeshCollider = _meshBigColliders[i];
|
||
zoneControllers[i].InitMeshCollider(bigMeshCollider);
|
||
bigMeshCollider.transform.parent.Find("Arrow").gameObject.SetActive(false);
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 当进去区域的最后一个小点位的区域范围时,开启下一区域的第一个小点位 和 关闭上一区域的最后一个小点位
|
||
/// </summary>
|
||
public void OpenNextZonePoint(ZoneController zoneController)
|
||
{
|
||
int currentIndex = 0;
|
||
for (int i = 0; i < zoneControllers.Length; i++)
|
||
{
|
||
if (zoneControllers[i] != zoneController)
|
||
{
|
||
//先关闭所有点位
|
||
zoneControllers[i].ActiveAllPointHideOrShow(false);
|
||
}
|
||
else
|
||
{
|
||
zoneControllers[i].ActiveAllPointHideOrShow(true, false);
|
||
currentIndex = i;
|
||
}
|
||
}
|
||
|
||
int nextIndex = currentIndex + 1;
|
||
if (nextIndex < zoneControllers.Length)
|
||
{
|
||
//开启下一区域的第一个小点位
|
||
zoneControllers[nextIndex]
|
||
.CurrentPointActiveHideOrShow(
|
||
zoneControllers[nextIndex].pointControllerEntities.First(), true);
|
||
}
|
||
|
||
int lastIndex = currentIndex - 1;
|
||
if (lastIndex >= 0)
|
||
{
|
||
//开启上一区域的最后一个小点位
|
||
zoneControllers[lastIndex]
|
||
.CurrentPointActiveHideOrShow(zoneControllers[lastIndex].pointControllerEntities.Last(),
|
||
true);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 进入当前区域时,关闭当前区域时间,打开别的区域事件
|
||
/// </summary>
|
||
public void HideBigMeshColliderStayUnRegister()
|
||
{
|
||
foreach (var zoneController in zoneControllers)
|
||
{
|
||
zoneController._onBigMeshColliderStayUnRegister.UnRegister();
|
||
}
|
||
}
|
||
|
||
|
||
public void OpenDomain(string domainName)
|
||
{
|
||
// if (_entrance != null)
|
||
// {
|
||
// _entrance.OpenDomain(domainName, OpenDomainType.PointCloud);
|
||
InitializeHybridClREntrance(domainName);
|
||
// }
|
||
// else
|
||
// {
|
||
// Debug.LogError("UnityEvo:HybridClREntrance is null");
|
||
// }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 绑定区域碰撞事件
|
||
/// </summary>
|
||
/// <param name="zoneId">区域名称</param>
|
||
/// <param name="onColliderEnter">进入事件</param>
|
||
/// <param name="onColliderStay">停留事件</param>
|
||
/// <param name="onColliderExit">退出事件</param>
|
||
public void AddOnZoneColliderEvent(string zoneId, Action<Collider> onColliderEnter = null,
|
||
Action<Collider> onColliderStay = null, Action<Collider> onColliderExit = null)
|
||
{
|
||
foreach (var zoneController in zoneControllers)
|
||
{
|
||
if (zoneController.name == zoneId)
|
||
{
|
||
if (onColliderEnter != null)
|
||
{
|
||
zoneController.OnColliderEnter += onColliderEnter;
|
||
}
|
||
|
||
if (onColliderStay != null)
|
||
{
|
||
zoneController.OnColliderStay += onColliderStay;
|
||
}
|
||
|
||
if (onColliderExit != null)
|
||
{
|
||
zoneController.OnColliderExit += onColliderExit;
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 绑定点位碰撞事件
|
||
/// </summary>
|
||
/// <param name="pointId">点位名称</param>
|
||
/// <param name="onColliderEnter">进入事件</param>
|
||
public void AddOnPointColliderEvent(string pointId, Action<Collider> onColliderEnter = null)
|
||
{
|
||
foreach (var pointController in pointControllers)
|
||
{
|
||
if (pointController.name == pointId)
|
||
{
|
||
if (onColliderEnter != null)
|
||
{
|
||
pointController.OnColliderEnter += onColliderEnter;
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检测指定Camera下是否存在符合条件的GameController
|
||
/// </summary>
|
||
/// <returns>是否存在符合条件的物体</returns>
|
||
private bool HasValidGameController()
|
||
{
|
||
var targetCamera = Camera.main;
|
||
if (targetCamera == null) return false;
|
||
|
||
// 获取相机下所有子物体(包括 inactive 物体)
|
||
Transform[] allChildren = targetCamera.GetComponentsInChildren<Transform>(true);
|
||
|
||
foreach (Transform child in allChildren)
|
||
{
|
||
// 跳过相机自身
|
||
if (child == targetCamera.transform) continue;
|
||
|
||
GameObject obj = child.gameObject;
|
||
// 检查名称、标签和碰撞体
|
||
if (obj.name == "GameController" &&
|
||
obj.CompareTag("GameController") &&
|
||
obj.TryGetComponent<BoxCollider>(out _))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
private void InitializeHybridClREntrance(string domainName)
|
||
{
|
||
GameObject entrance = GameObject.Find("LoadDll");
|
||
if (entrance == null)
|
||
{
|
||
Debug.LogError("未找到LoadDll物体");
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
// 替换为实际程序集名称和类完整名
|
||
string assemblyName = "stary.hotfixupdate.main"; // 例如:"HybridCLR.Runtime"
|
||
string typeFullName = "Stary.Evo.HybridClREntrance"; // 例如:"HybridCLR.HybridClREntrance"
|
||
|
||
// 加载程序集并获取类型
|
||
Assembly assembly = Assembly.Load(assemblyName);
|
||
// 已加载的程序集(延续之前的assembly变量)
|
||
Type hybridType = assembly.GetType(typeFullName);
|
||
if (hybridType == null)
|
||
{
|
||
Debug.LogError("未找到HybridClREntrance类型");
|
||
return;
|
||
}
|
||
|
||
// 反射调用GameObject.GetComponent方法
|
||
MethodInfo getComponentMethod = typeof(GameObject).GetMethod("GetComponent", Type.EmptyTypes);
|
||
MethodInfo genericMethod = getComponentMethod?.MakeGenericMethod(hybridType);
|
||
var _entrance = genericMethod?.Invoke(entrance, null);
|
||
|
||
if (_entrance == null)
|
||
{
|
||
// 若组件不存在,可反射调用AddComponent添加
|
||
MethodInfo addComponentMethod = typeof(GameObject).GetMethod("AddComponent", Type.EmptyTypes);
|
||
MethodInfo genericAddMethod = addComponentMethod.MakeGenericMethod(hybridType);
|
||
_entrance = genericAddMethod.Invoke(entrance, null);
|
||
}
|
||
|
||
// 步骤2:获取实例类型并调用方法
|
||
Type componentType = _entrance.GetType();
|
||
MethodInfo targetMethod = componentType.GetMethod(
|
||
"OpenDomain", // 替换为实际方法名
|
||
new[] { typeof(string), typeof(string) } // 替换为方法参数类型
|
||
);
|
||
|
||
if (targetMethod == null)
|
||
{
|
||
Debug.LogError($"组件{componentType.Name}中未找到目标方法");
|
||
return;
|
||
}
|
||
|
||
targetMethod.Invoke(_entrance, new[] { domainName, "PointCloud" });
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogError($"反射操作失败: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
} |