Unity开发-SLG实时战斗头像自适应算法

目前参与一款在研SLG研发,目前在开发实时战斗部分的表现,今天要分享的是实时战斗头像自动排布算法的实现。


需求分析

  1. 部队头像的自动跟随、
  2. 自动监测碰撞以避免头像重叠、
  3. 需要满足一定性能要求,不能产生过多的DrawCall和其他CPU开销、
  4. 参考效果为万国觉醒实时战斗表现,当前方案基本实现相同效果。

设计思路

  1. 建立Root Canvas空间下的屏幕空间映射,进行虚拟网格拆分,作为基础Map,和单个头像图标的坐标系。
  2. 提供1所建立的坐标系的注册和反注册,用来记录改空间内网格的占用信息。
  3. 周期性进行Available检测,不满足则进行头像位置变换。
  4. Available算法基于对象和Root的Relative Bounds 进行索引变换,查询Area占用情况。
  5. 每个对象内置固定个数的Available Points,运行时根据部队朝向进行最优排序,周期选取最优点为对象跟随点。

实现方案要点

  • 建立Map空间索引映射关系,作为坐标系管理和查询的基础
  • 可以直接通过Bounds和AreaSize计算对应坐标,近似Hash算法的查询复杂度
  • 周期性的Available检测,避免高并发的运算
  • Vector.Dot对AvailablePoints进行排序
  • 使用缓存变量避免GC Alloc

PotraitBoard 可以放在UI任意节点,指定好控制参数,即可在Enable Disable时自动注册和反注册

PotraitManager挂载于场景常驻节点

PotraitManager._root需要为UI节点下AnchorPreset为Strench/Strench(铺满全屏)

PotraitManager.areasCount为屏幕空间拆分的行列数

代码略长,不过注释充分,直接贴上了……

 

using System.Collections.Generic;
using System.Text;
using DG.Tweening;
using UnityEngine;
using XLua;

public class PotraitBoard : MonoBehaviour
{
    [LuaCallCSharp]
    public enum DefaultPos
    {
        Left = 1,
        Right = 2,
    }
    
    /// 
    /// controll target
    /// 
    public RectTransform target;

    /// 
    /// available points
    /// 
    public List availablePoints = new List();
    
    /// 
    /// best sort of points
    /// 
    public List bestSortOfPoints = new List();
    
    /// 
    /// position illegle check duration
    /// 
    private float checkDuration = 2f;

    /// 
    /// pos of potrait sets
    /// 
    private int curPos = 0;

    /// 
    /// pos of potrait sets
    /// 
    private int curIndex = 0;

    /// 
    /// troop`s direction
    /// 
    private Vector2 direction = Vector2.left;
    
    /// 
    /// move to next pos
    /// 
    /// 
    private void MoveToNext(int nextPos)
    {
        target.DOLocalMove(availablePoints[nextPos].localPosition, 0.5f).SetEase(Ease.OutQuad);
    }

    /// 
    /// move to next available point in availablePoints in default sequence, if cur is not available
    /// 
    private void MoveToNextIfNotAvailable()
    {
        if (PotraitBoardManager.Instance.IsPointAvailable(availablePoints[curPos]))
            return;
        
        int sign = curPos;
        while (!PotraitBoardManager.Instance.IsPointAvailable(availablePoints[curPos]))
        {
            curPos++;
            curPos = curPos % availablePoints.Count;
            if (sign == curPos)
                return;
        }

        //Debug.Log("PotraitBoard MoveToNextIfNotAvailable Move From [" + sign + "] To Pos: [" + curPos + "]");
        
        PotraitBoardManager.Instance.UnRegisterPotrait(curIndex,availablePoints[sign]);
        curIndex = PotraitBoardManager.Instance.RegisterPotrait(availablePoints[curPos]);
        
        MoveToNext(curPos);
    }

    /// 
    /// move to next best point available
    /// 
    private void MoveToNextBestAvailable()
    {
        if (bestSortOfPoints.Count <= 0)
            ReSortPoints();

        int pIndex = 0;

        for (int i = 0; i < bestSortOfPoints.Count; i++)
        {
            if (Potra

你可能感兴趣的:(UGUI,优化相关,Unity,Engine)