[绕物体一周][算法]绕物体一周算法

绕物体一周实现

需求

上周开发U3D的时候,遇到一个需求
场景中,有一个玩家,为了训练玩家,需要让玩家绕着给定物体一周
看似简单的需求,细想一下却没那么容易

首先拆分下具体需求与环境:

  1. 玩家进入绕物体的初始位置不确定
  2. 玩家绕物体的方向不确定(顺时针or逆时针)
  3. 玩家绕物体的路径理论上是无数条
  4. 玩家具有完全控制(也就是说玩家可能先顺时针转半圈然后逆时针转半圈)
  5. 必须包容上述所有条件精确的对玩家进行判断


所以想要实现还是有那么一点点难度
起初的想法是获取玩家的路径,然后判断是否为类圆
想了一会果断pass掉
因为获取玩家路径实在太浪费性能了,上述需求中说过,玩家路径几乎是无数条,
当然指定路径除外,况且玩家行走如龟速或者路径复杂怎么办,
比如某个调皮的玩家走两步退一步,秧歌式走法就很头疼了
你也不能说明他没绕着走一圈。

思路

pass掉上边的方法后,想到了角度
我如果能判断他的角度就行了
事实是可以的,我获取到玩家位置和物体位置,
用反三角函数就可以获得他们相对于坐标轴的角度
得到了角度,我只要判断玩家和物体完成了360°的旋转就能判断是否绕物体一周
但是中间还有一些特殊细节:

  1. 360°判断不可能是连续的,不然是无穷大,所以必须有一个捕捉精度
  2. 由于0°和360°是重叠的,这里会有一些处理
  3. 正因为第二条,所以如果玩家初始角度在0到L或360-L到360之间(L为捕捉精度),他的判断会有所不同,所以这两个特殊范围得特殊处理

基本上就上面三条问题
我直接忽略掉y轴,只关心平面。

流程图:

在这里插入图片描述

WPS画流程图比Visio方便,但功能不强大,所以流程图稍显复杂

下面的C#代码有几处和流程图不一样,但不影响整个算法

U3D C#代码

    private float currentAngle;             // 当前触发角度
    private float precisionAngle = 36.0f;   // 触发精度
    private int progressAngle = 0;          // 完成进度
    private int fullProgress;               // 总进度
		if (Mathf.Abs(progressAngle) >= fullProgress)
        {
        	// 这里是判断是否完成进度,若完成执行下面函数
            Node1Finish();
        }

		//定义当前角度和偏移角度
        float nowAngle = GetAngle(), offsetAngle;
        if (currentAngle < precisionAngle
            && nowAngle >= (360.0f - (2 * precisionAngle) + currentAngle))
        {
            offsetAngle = currentAngle - 360.0f + nowAngle;
        }
        else if (currentAngle > (360.0f - precisionAngle)
            && nowAngle < ((2 * precisionAngle) - 360.0f + currentAngle))
        {
            offsetAngle = 360.0f - currentAngle + nowAngle;
        }
        else
        {
            offsetAngle = nowAngle - currentAngle;
        }

        if (Mathf.Abs(offsetAngle) < precisionAngle
            || Mathf.Abs(offsetAngle) > 2 * precisionAngle)
        {
            return;
        }

        if (offsetAngle > 0.0f)
        {
            ++progressAngle;
            currentAngle += precisionAngle;
            if (currentAngle >= 360.0f)
            {
                currentAngle -= 360.0f;
            }
        }
        else
        {
            --progressAngle;
            currentAngle -= precisionAngle;
            if (currentAngle < 0)
            {
                currentAngle = 360.0f + currentAngle;
            }
        }

这里的代码要放在Update或Update间接调用的函数内,
Fixed也可,只要是实时执行的就行。
执行前,应该先初始化当前触发角度,它应该是人物要进行绕物体时的角度

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值