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

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


需求分析

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

设计思路

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

实现方案要点

  • 建立Map<Index,Area>空间索引映射关系,作为坐标系管理和查询的基础
  • 可以直接通过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,
    }
    
    /// <summary>
    /// controll target
    /// </summary>
    public RectTransform target;

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

    /// <summary>
    /// pos of potrait sets
    /// </summary>
    private int curPos = 0;

    /// <summary>
    /// pos of potrait sets
    /// </summary>
    private int curIndex = 0;

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

    /// <summary>
    /// move to next available point in availablePoints in default sequence, if cur is not available
    /// </summary>
    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);
    }

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

        int pIndex = 0;

        for (int i = 0; i < bestSortOfPoints.Count; i++)
        {
            if (Potra
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值