黄金民的个人文档

黄金民的个人文档


默认页面

<h2>移动组件-简介</h2> <p>为了增强元器件移动能力,方便实验操作,新移动组件能够支持近距离靠近、爬升和层叠。</p> <p>近距离靠近:被拖拽元器件在靠近(视觉靠近)其它元器件时,自动去爬升当前元器件。</p> <p>爬升:被拖拽元器件能够沿着鼠标路径,爬升到其它元器件表面,如当前鼠标点无可爬升元器件则沿着桌面移动。</p> <p>层叠:被拖拽元器件在释放时,会做下落检测,判断是否能够叠在其它元器件之上。如果能层叠,则它就与这个元器件建立了层叠关系。</p> <p>层叠状态下,可以随意拖动层叠链中的元器件,但其上元器件不跟随一起拖动。当被拖拽元器件之上的元器件已经脱离它时,其上的元器件都会掉落,依次掉落在其它元器件上或桌面上。</p> <p>设计案如下:<a href="http://cube.nd.com.cn/svn/prototype/VirtualLab/New_Design/common/index.html#g=1&p=%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95">http://cube.nd.com.cn/svn/prototype/VirtualLab/New_Design/common/index.html#g=1&p=%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95</a></p> <h2>移动组件-原理</h2> <p>移动组件的爬升和层叠判断,依赖于Unity的物理投射能力/接口。投射判断基本思路:从指定位置(摄像机位置/元器件位置),向指定方向(屏幕鼠标方向/垂直向下方向)投射被拖拽元器件的包围盒,检测投射到的元器件和投射点坐标,依据这两项信息来做爬升和层叠判断。</p> <p>摄像机位置 -&gt; 屏幕鼠标方向 =&gt; 爬升信息</p> <p>元器件位置 -&gt; 垂直向下方向 =&gt; 层叠信息</p> <1> 元器件包围盒 根据元器件各部位的Collider位置和大小,计算得到元器件整体的包围盒,如下所示: ![](https://wiki.doc.101.com/images/4/40/Vlab-newdragger-bounds.png) 1 ![](https://wiki.doc.101.com/images/thumb/8/8a/Vlab-newdragger-drop-element.png/400px-Vlab-newdragger-drop-element.png) <2> 投射原理 下面是爬升投射示意图: [![](https://wiki.doc.101.com/images/4/40/vlab-newdragger-raycast-element.png|400px]] 注:从摄像机位置向鼠标方向投射包围盒(被拖拽元器件),与其最近的相交对象为元器件A,同时依据投射距离能够计算出被拖拽元器件在元器件A上的爬升坐标。 如无可爬升对象,则被拖拽元器件沿着桌面移动。 下面是掉落投射示意图: [![](https://wiki.doc.101.com/images/4/40/vlab-newdragger-drop-element.png|400px]] 注:从被拖拽元器件当前位置,向下投射包围盒(被拖拽元器件),与其最近的相交对象为元器件A,同事依据投射距离能够计算出被拖拽元器件的掉落高度,并得到其层叠关系。 如无可层叠对象,则被拖拽元器件掉落在桌面上。 ## 移动组件-投射接口 ## 针对元器件投射能力,抽象出来两个投射类,方便在其他情况下使用。 <1> ObjectRaycaster ```c /// <summary> /// 投射获取相交的元器件以及投射距离 /// </summary> /// <param name="castObject">投射对象</param> /// <param name="castCenter">投射中心</param> /// <param name="castExtends">投射包围盒尺寸</param> /// <param name="castRotation">投射包围盒角度</param> /// <param name="castDirection">投射方向</param> /// <param name="raycastDistance">命中距离(out)</param> /// <returns></returns> public LabBaseObject RaycastElement(LabBaseObject castObject, Vector3 castCenter, Vector3 castExtends, Quaternion castRotation, Vector3 castDirection, out float raycastDistance) /// <summary> /// 下落检测,计算得到层叠元器件和投射距离 /// </summary> /// <param name="castObject">投射对象</param> /// <param name="dropOffsetY">下落起点偏移(往上抬高)</param> /// <param name="castExtends">投射包围盒尺寸</param> /// <param name="castRotation">投射包围盒角度</param> /// <param name="layerMask">检测层掩码</param> /// <param name="dropDistance">命中距离(out)</param> /// <returns></returns> public LabBaseObject DropElement(LabBaseObject castObject, float dropOffsetY, Vector3 castExtends, Quaternion castRotation, int layerMask, out float dropDistance) ``` <2> TableRaycaster ```c /// <summary> /// 桌面移动,与当前位置的offset值 /// </summary> /// <param name="eventData">鼠标点信息</param> /// <param name="transform">拖拽对象</param> /// <param name="rayHitObjPosY">拖拽点偏移高度</param> /// <param name="rayHitObjOffset">拖拽对象中心点与拖拽点的偏移</param> /// <returns></returns> public Vector3 RaycastOnTable(PointerEventData eventData, Transform transform, float rayHitObjPosY, Vector3 rayHitObjOffset) /// <summary> /// 判断元器件/部件是否在桌面范围 /// </summary> /// <param name="labTransform"></param> /// <returns></returns> public bool IsOnTable(Transform labTransform) /// <summary> /// 检查元器件是不是在桌面上(避免在桌面下) /// </summary> /// <param name="dragObject"></param> public static void CheckObjectOnTable(LabBaseObject dragObject) ``` ## 移动组件-元器件规范 ## 移动组件对元器件制作有一些规范要求: <1> 元器件中心点需要位于底部中心点,注意是所有部件的底部中心。对于可改变部件样式的元器件(如干簧管演示盒),在改变样式之后也需要保证中心点位于底部中心。 <2> 避免元器件部件碰撞器缺失,同时注意尽量少使用Mesh Collider。 <3> 元器件部件的碰撞器尽量反映部件大小,特别是轮廓部件。 ## 移动组件-自定义部分 ## <1> 元器件自定义 元器件移动计算,按照通用规则:将元器件内的所有Collider计算得到包围盒,所有元器件都可被爬升,投射距离以包围盒相接触为准。 同时也提供元器件可自定义部分,以适配不同的元器件。 对于不参与爬升的部件,可将其Tag设置为"IgnoreCascade"。 ```c /// <summary> /// 检测包围盒,元器件可自定义自身包围盒 /// </summary> public virtual Bounds DetectBounds /// <summary> /// 包围盒与中心点的偏移 /// </summary> public virtual Vector3 BoundsOffset /// <summary> /// 检测包围盒角度 /// </summary> public virtual Quaternion DetectRotation /// <summary> /// 是否支持爬升,如连接中的导线不支持爬升 /// </summary> /// <param name="dragObject">正在拖拽对象</param> /// <returns></returns> public virtual bool CanBeClimbed(LabBaseObject dragObject) /// <summary> /// 爬升时表面间隙(负代表嵌入),方便元器件间交互 /// </summary> /// <returns></returns> public virtual float EmbedDepth() ``` <2> 移动组件自定义 移动组件LabDragMove(LabObjDragMove & LabObjPartDragMove),提供拖拽事件监听和优先级处理。 LabObjDragMove:用于元器件做整体移动的组件,挂载元器件根节点,支持靠近、爬升、层叠。 LabObjPartDragMove:用于元器件部件做靠近、爬升操作,方便元器件部件进行更好的交互,但不提供层叠和更多的自定义行为。 下面是针对拖拽提供的可监听事件: ```c /// <summary> /// 拖拽开始事件 /// </summary> public DragMoveBeginEvent onDragMoveBegin /// <summary> /// 拖拽中事件 /// </summary> public DragMoveEvent onDragMove /// <summary> /// 拖拽结束事件 /// </summary> public DragMoveEndEvent onDragMoveEnd ``` 移动组件同时在拖动中和拖动结束,提供优先级判断方法: ```c /// <summary> /// 拖拽优先级判断(元器件/部件是否接管) /// </summary> public Func<bool> OnDragMoveFunc; /// <summary> /// 拖拽结束优先判断(元器件/部件是否接管) /// </summary> public Func<bool> OnEndDragFunc; ``` 注:上述两个优先级判断委托,如果返回true则交由元器件/部件处理,移动组件不做爬升和下落判断;如果返回false则由移动组件做爬升和下落判断。 <3> 元器件操作自适应 针对改变元器件位置和方向(元器件旋转、影响其他元器件层叠状态的旋转/平移)的操作,需要元器件进行自适应,因为无法逐个元器件频繁去更新层叠关系(消耗非常大)。 LabBaseObject基类提供两个刷新层叠关系的函数,提供给元器件主动来调用。 ```c /// <summary> /// 更新层叠关系(通知其上所有元器件) /// </summary> /// <param name="offsetY">自身高度变化,需要掉落测试的偏移高度(默认抬高1cm)</param> public void UpdateCascading(float offsetY = 0.01f) /// <summary> /// 更新层叠关系(通知自身刷新层叠关系) /// </summary> public void UpdateSelfCascading() ``` 注:仅在必要时(需要刷新层叠关系)调用,切不可在帧回调里调用。[[Category:组件]]

页面列表

ITEM_HTML