在我的游戏中,玩家的两只手操控中,不想让他们的手围着自己在一个圆形范围内随便乱跑,左手只想让他在左上角,右手在右上角范围活动。所以我制作这样一个算法来实现。
首先用Dot函数划分出4个区域,然后根据区域计算修正后的位置。
先上代码:
hero就是图中蓝色胶囊,hand是黄色的球,红色的newhand是最后修正的位置。如果两个球重叠表示不需要修正,如果修正了红色就是真实算法位置。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class testRange : MonoBehaviour
{
public Transform hero; //角色位置
public Transform hand; //模型手
public Transform newhand; //修正后的位置
public float maxDis = 0.6f;
protected void Update()
{
Vector3 dir;
//让左手在第二象限。dot是0-1,dot2是-1~0
Vector3 atHero = hero.position;
Vector3 atHand = hand.position;
atHero.y = atHand.y;
dir = (atHand - atHero).normalized;
float dot = Vector3.Dot(hero.forward, dir);
float dot2 = Vector3.Dot(hero.right, dir);
Debug.Log(dot + "," + dot2);
Vector3 nowat = hand.position;
if (dot < 0f)
{
//hand超过身后
nowat = GetIntersectWithLineAndPlane(nowat, hero.forward, hero.forward, hero.position);
}
if (dot2 > 0f)
{
//hand超过右边
nowat = GetIntersectWithLineAndPlane(nowat, hero.right, hero.right, hero.position);
}
//只能围绕身边
Vector3 heroat = hero.position;
heroat.y = nowat.y;
float dis = Vector3.Distance(nowat, heroat);
if (dis < maxDis)
{
Vector3 todir = (nowat - heroat).normalized;
if (!todir.Equals(Vector3.zero))
nowat = heroat + todir * maxDis;
else
{
todir = (heroat - hand.position).normalized;
nowat = heroat + todir * maxDis;
}
}
newhand.position = nowat;
}
/// <summary>
/// 计算直线与平面的交点
/// </summary>
/// <param name="point">直线上某一点</param>
/// <param name="direct">直线的方向</param>
/// <param name="planeNormal">垂直于平面的的向量</param>
/// <param name="planePoint">平面上的任意一点</param>
/// <returns></returns>
private Vector3 GetIntersectWithLineAndPlane(Vector3 point, Vector3 direct, Vector3 planeNormal, Vector3 planePoint)
{
float d = Vector3.Dot(planePoint - point, planeNormal) / Vector3.Dot(direct.normalized, planeNormal);
return d * direct.normalized + point;
}
}
上面的代码就是计算hand在第二象限的限制,首先我们观察到dot 在第二象限是 0 ~ 1 的范围,dot2是 -1 ~ 0 ,当超过这个范围了,我们可以通过GetIntersectWithLineAndPlane函数来计算超过这个结界的碰撞点,防止出界。
最后我们可能不希望他跑到玩家某型里面了,我们给一个半径范围maxDis ,让他不要和玩家重叠。
看看效果图。
当我们移动到背后的时候,小球最多和我们平行,当小球移动到右边的时候那么最多知道面前,而且不会进入玩家模型范围。
相交算法链接来自