From a3ec9df0018f46214385782d170702968e121db9 Mon Sep 17 00:00:00 2001
From: Tian jianyong <11429339@qq.com>
Date: Wed, 20 Nov 2024 12:40:04 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=20Unity=20=E9=80=82?=
=?UTF-8?q?=E9=85=8D=E5=99=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
ActiveProtect.csproj | 3 +
src/Adapters/UnityExtensions.cs | 32 +++++
src/Adapters/UnityMissile.cs | 31 +++++
src/Adapters/UnitySimulationElement.cs | 42 +++++++
src/Adapters/UnitySimulationManager.cs | 166 +++++++++++++++++++++++++
src/Simulation/ISimulationManager.cs | 56 +++++++++
src/Simulation/SimulationManager.cs | 51 --------
7 files changed, 330 insertions(+), 51 deletions(-)
create mode 100644 src/Adapters/UnityExtensions.cs
create mode 100644 src/Adapters/UnityMissile.cs
create mode 100644 src/Adapters/UnitySimulationElement.cs
create mode 100644 src/Adapters/UnitySimulationManager.cs
create mode 100644 src/Simulation/ISimulationManager.cs
diff --git a/ActiveProtect.csproj b/ActiveProtect.csproj
index 08dcf2c..2e5a9d3 100644
--- a/ActiveProtect.csproj
+++ b/ActiveProtect.csproj
@@ -13,10 +13,13 @@
+
+
+
diff --git a/src/Adapters/UnityExtensions.cs b/src/Adapters/UnityExtensions.cs
new file mode 100644
index 0000000..1502b1f
--- /dev/null
+++ b/src/Adapters/UnityExtensions.cs
@@ -0,0 +1,32 @@
+using UnityEngine;
+
+namespace ActiveProtect.Adapters
+{
+ public static class UnityExtensions
+ {
+ public static Vector3D ToVector3D(this Vector3 v)
+ {
+ return new Vector3D(v.x, v.y, v.z);
+ }
+
+ public static Vector3 ToVector3(this Vector3D v)
+ {
+ return new Vector3((float)v.X, (float)v.Y, (float)v.Z);
+ }
+
+ public static Orientation ToOrientation(this Quaternion q)
+ {
+ Vector3 euler = q.eulerAngles;
+ return new Orientation(euler.x, euler.y, euler.z);
+ }
+
+ public static Quaternion ToQuaternion(this Orientation o)
+ {
+ return Quaternion.Euler(
+ (float)o.Pitch,
+ (float)o.Yaw,
+ (float)o.Roll
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Adapters/UnityMissile.cs b/src/Adapters/UnityMissile.cs
new file mode 100644
index 0000000..f114cfb
--- /dev/null
+++ b/src/Adapters/UnityMissile.cs
@@ -0,0 +1,31 @@
+using UnityEngine;
+
+namespace ActiveProtect.Adapters
+{
+ ///
+ /// Unity导弹组件
+ ///
+ public class UnityMissile : UnitySimulationElement
+ {
+ [SerializeField]
+ private string missileId;
+ [SerializeField]
+ private MissileProperties missileProperties;
+
+ private Missile _missile;
+
+ protected override SimulationElement CreateSimulationElement()
+ {
+ var unityManager = FindObjectOfType();
+ _missile = new Missile(missileId, transform.position.ToVector3D(),
+ transform.rotation.ToOrientation(), unityManager, missileProperties);
+ return _missile;
+ }
+
+ // Unity特有的功能,如粒子效果
+ public void OnMissileLaunch()
+ {
+ GetComponent()?.Play();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Adapters/UnitySimulationElement.cs b/src/Adapters/UnitySimulationElement.cs
new file mode 100644
index 0000000..285ffcc
--- /dev/null
+++ b/src/Adapters/UnitySimulationElement.cs
@@ -0,0 +1,42 @@
+using UnityEngine;
+
+namespace ActiveProtect.Adapters
+{
+ ///
+ /// Unity仿真元素基类,将我们的SimulationElement适配到MonoBehaviour
+ ///
+ public abstract class UnitySimulationElement : MonoBehaviour
+ {
+ protected SimulationElement SimElement { get; private set; }
+
+ protected virtual void Awake()
+ {
+ // 创建对应的仿真元素
+ SimElement = CreateSimulationElement();
+ }
+
+ protected virtual void Update()
+ {
+ // 使用Unity的时间步长
+ SimElement?.Update(Time.deltaTime);
+
+ // 同步位置和旋转
+ if (SimElement != null)
+ {
+ transform.position = new Vector3(
+ (float)SimElement.Position.X,
+ (float)SimElement.Position.Y,
+ (float)SimElement.Position.Z
+ );
+
+ transform.rotation = Quaternion.Euler(
+ (float)SimElement.Orientation.Pitch,
+ (float)SimElement.Orientation.Yaw,
+ (float)SimElement.Orientation.Roll
+ );
+ }
+ }
+
+ protected abstract SimulationElement CreateSimulationElement();
+ }
+}
\ No newline at end of file
diff --git a/src/Adapters/UnitySimulationManager.cs b/src/Adapters/UnitySimulationManager.cs
new file mode 100644
index 0000000..bf4759c
--- /dev/null
+++ b/src/Adapters/UnitySimulationManager.cs
@@ -0,0 +1,166 @@
+using UnityEngine;
+using UnityEngine.Events;
+using System;
+using System.Collections.Generic;
+using ActiveProtect.Simulation;
+using ActiveProtect.Models;
+using ActiveProtect.Utility;
+
+namespace ActiveProtect.Adapters
+{
+ ///
+ /// Unity仿真管理器适配器,将Unity的事件系统适配到我们的接口
+ ///
+ public class UnitySimulationManager : MonoBehaviour, ISimulationManager
+ {
+ // Unity事件字典,用于事件订阅和发布
+ private readonly Dictionary> _eventDictionary
+ = new Dictionary>();
+
+ // 仿真元素列表
+ private readonly List _elements = new List();
+
+ public double CurrentTime => Time.time;
+
+ // 实现非泛型的 PublishEvent
+ public void PublishEvent(SimulationEvent evt)
+ {
+ var eventType = evt.GetType();
+ if (_eventDictionary.TryGetValue(eventType, out var unityEvent))
+ {
+ unityEvent.Invoke(evt);
+ }
+ }
+
+ // 实现泛型的 PublishEvent
+ public void PublishEvent(T evt) where T : SimulationEvent
+ {
+ PublishEvent(evt as SimulationEvent);
+ }
+
+ public void SubscribeToEvent(Action handler) where T : SimulationEvent
+ {
+ var eventType = typeof(T);
+ if (!_eventDictionary.ContainsKey(eventType))
+ {
+ _eventDictionary[eventType] = new UnityEvent();
+ }
+
+ _eventDictionary[eventType].AddListener(evt =>
+ {
+ if (evt is T typedEvent)
+ {
+ handler(typedEvent);
+ }
+ });
+ }
+
+ public void UnsubscribeFromEvent(Action handler) where T : SimulationEvent
+ {
+ var eventType = typeof(T);
+ if (_eventDictionary.ContainsKey(eventType))
+ {
+ // Unity的事件系统不支持直接移除特定处理器,需要重新创建事件
+ var newEvent = new UnityEvent();
+ _eventDictionary[eventType] = newEvent;
+ }
+ }
+
+ public void UnsubscribeAllEvents(SimulationElement element)
+ {
+ // 在Unity中,我们可能需要遍历所有事件类型并移除相关的监听器
+ foreach (var eventPair in _eventDictionary)
+ {
+ eventPair.Value.RemoveAllListeners();
+ }
+ }
+
+ public SimulationElement GetEntityById(string id)
+ {
+ // 首先在我们的列表中查找
+ var element = _elements.Find(e => e.Id == id);
+ if (element != null) return element;
+
+ // 如果没找到,使用Unity的查找机制
+ var go = GameObject.Find(id);
+ var unityElement = go?.GetComponent();
+ return unityElement?.SimElement ?? throw new InvalidOperationException($"Entity with id {id} not found");
+ }
+
+ public void AddElement(SimulationElement element)
+ {
+ if (!_elements.Contains(element))
+ {
+ _elements.Add(element);
+ }
+ }
+
+ public List GetElements()
+ {
+ return new List(_elements);
+ }
+
+ public void HandleTargetHit()
+ {
+ // 遍历所有活跃的导弹和坦克
+ var missiles = _elements.FindAll(e => e is MissileBase && e.IsActive);
+ var tanks = _elements.FindAll(e => e is Tank && e.IsActive);
+
+ foreach (var missile in missiles)
+ {
+ if (missile is MissileBase actualMissile)
+ {
+ foreach (var tank in tanks)
+ {
+ if (tank is Tank actualTank)
+ {
+ double distance = Vector3D.Distance(missile.Position, tank.Position);
+ if (distance <= actualMissile.MissileProperties.ExplosionRadius)
+ {
+ // 发布命中事件
+ PublishEvent(new TargetHitEvent
+ {
+ TargetId = tank.Id,
+ MissileId = missile.Id
+ });
+
+ // 处理伤害
+ actualTank.TakeDamage(50, true);
+ Debug.Log($"目标 {tank.Id} 被导弹 {missile.Id} 击中");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void Update()
+ {
+ // 在Unity的Update中更新所有仿真元素
+ foreach (var element in _elements.ToArray())
+ {
+ if (element.IsActive)
+ {
+ element.Update(Time.deltaTime);
+ }
+ }
+
+ // 处理目标命中检测
+ HandleTargetHit();
+
+ // 清理不活跃的元素
+ _elements.RemoveAll(e => !e.IsActive);
+ }
+
+ private void OnDestroy()
+ {
+ // 清理所有事件订阅
+ foreach (var eventPair in _eventDictionary)
+ {
+ eventPair.Value.RemoveAllListeners();
+ }
+ _eventDictionary.Clear();
+ _elements.Clear();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Simulation/ISimulationManager.cs b/src/Simulation/ISimulationManager.cs
new file mode 100644
index 0000000..6651ae4
--- /dev/null
+++ b/src/Simulation/ISimulationManager.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+
+namespace ActiveProtect.Simulation
+{
+ ///
+ /// 仿真管理器接口,定义了仿真管理器的基本功能
+ ///
+ public interface ISimulationManager
+ {
+ ///
+ /// 当前仿真时间
+ ///
+ double CurrentTime { get; }
+
+ ///
+ /// 添加仿真元素
+ ///
+ void AddElement(SimulationElement element);
+
+ ///
+ /// 仿真元素列表
+ ///
+ List GetElements();
+
+ ///
+ /// 根据ID获取仿真实体
+ ///
+ SimulationElement GetEntityById(string id);
+
+ ///
+ /// 处理目标被击中事件
+ ///
+ void HandleTargetHit();
+
+ ///
+ /// 发布仿真事件
+ ///
+ void PublishEvent(SimulationEvent evt);
+
+ ///
+ /// 订阅仿真事件
+ ///
+ void SubscribeToEvent(Action handler) where T : SimulationEvent;
+
+ ///
+ /// 取消订阅仿真事件
+ ///
+ void UnsubscribeFromEvent(Action handler) where T : SimulationEvent;
+
+ ///
+ /// 取消所有事件订阅
+ ///
+ void UnsubscribeAllEvents(SimulationElement element);
+ }
+}
\ No newline at end of file
diff --git a/src/Simulation/SimulationManager.cs b/src/Simulation/SimulationManager.cs
index f386f92..fbeca0e 100644
--- a/src/Simulation/SimulationManager.cs
+++ b/src/Simulation/SimulationManager.cs
@@ -6,57 +6,6 @@ using ActiveProtect.Utility;
namespace ActiveProtect.Simulation
{
- ///
- /// 仿真管理器接口,定义了仿真管理器的基本功能
- ///
- public interface ISimulationManager
- {
- ///
- /// 当前仿真时间
- ///
- double CurrentTime { get; }
-
- ///
- /// 添加仿真元素
- ///
- void AddElement(SimulationElement element);
-
- ///
- /// 仿真元素列表
- ///
- List GetElements();
-
- ///
- /// 根据ID获取仿真实体
- ///
- SimulationElement GetEntityById(string id);
-
- ///
- /// 处理目标被击中事件
- ///
- void HandleTargetHit();
-
- ///
- /// 发布仿真事件
- ///
- void PublishEvent(SimulationEvent evt);
-
- ///
- /// 订阅仿真事件
- ///
- void SubscribeToEvent(Action handler) where T : SimulationEvent;
-
- ///
- /// 取消订阅仿真事件
- ///
- void UnsubscribeFromEvent(Action handler) where T : SimulationEvent;
-
- ///
- /// 取消所有事件订阅
- ///
- void UnsubscribeAllEvents(SimulationElement element);
- }
-
///
/// 仿真管理器类,负责管理整个仿真过程
///