点乘求角度,叉乘求方向
比如敌人再附近,点乘可以求出玩家面朝方向和敌人方向的夹角,叉乘可以得出左转还是右转更好的转向敌人
Part 1 点乘:
数学上的 点乘为 a * b = |a| * |b| * cos(Θ)
Unity中的点乘也是如此 点乘结果为 float 是投影长度
点乘的主要作用就是,点乘求角度。 Θ = Arcos( a * b / |a| * |b|)
代码实现:
float tmpNormalized = Vector3.Dot(attacked.right.normalized, tmpDistance.normalized); //计算出在攻击方向的单位向量上的投影
float tmpRadian = Mathf.Acos(tmpNormalized); //计算出弧度
float tmpAngle = Mathf.Rad2Deg * tmpRadian; //弧度转换为角度
点乘的方法是
Vector3.Dot(向量A,向量B); 得到的结果是数 即 B在A上的投影长度
例如:
tmpDistanceX = Vector3.Dot(attacker.right, tmpDis); //即tmpDis 在 attacker.right向量上的投影长度
点乘的简单应用A:设置矩形体区域
/// <summary>
/// 以攻击点为中心,长为 2 * distance 宽为 2 * half 高为2 * height的矩形体范围
/// </summary>
/// <param name="attacker">生成范围的中心点的位置</param>
/// <param name="attacked">目标物体的位置</param>
/// <param name="half">中心点到两侧的宽度,实际宽度为2倍长度</param>
/// <param name="distance">中心点到最远攻击点的距离</param>
/// <param name="height">中心点到最高的距离</param>
/// <returns></returns>
private bool RectAttack(Transform attacker, Transform attacked, float half, float distance, float height) //生成一个矩形体范围的碰撞区域
{
Vector3 tmpDis = attacked.position - attacker.position; //算出攻击者和被攻击者之间的向量差
float tmpDistanceX, tmpDistanceY, tmpDistanceZ;
tmpDistanceX = Vector3.Dot(attacker.right, tmpDis); //算出向量差在 攻击方向上的投影,设攻击方向为 right
Debug.Log("tmpDistance.X = " + tmpDistanceX);
//float tmpDistance = Vector3.Distance(attacker.position, attacked.position); //实际距离
//Debug.Log("tmpDistance = " + tmpDistance);
if (tmpDistanceX >= 0 && tmpDistanceX <= distance) //判断投影是在 攻击方向正面,且在攻击范围内
//排除了目标在攻击点背后的情况
{
tmpDistanceZ = Mathf.Abs(Vector3.Dot(attacker.forward, tmpDis)); //计算向量差在 攻击范围横轴上的距离
tmpDistanceY = Mathf.Abs(Vector3.Dot(attacker.up, tmpDis)); //计算向量差在 攻击范围横轴上的距离
if (tmpDistanceZ <= half && tmpDistanceY <= height) //在范围内则进行攻击
{
Debug.Log("Attacked!!!");
return true;
}
}
return true;
}
点乘的简单应用B:设置扇形体区域
/// <summary>
/// 以攻击点为中心,到任一点夹角为45°,且长度为radius的扇形体区域
/// 扇形所指的为 以攻击点为固定点,长度为radius,角度为 2 * angle的覆盖区域
/// </summary>
/// <param name="attacker">攻击者的位置</param>
/// <param name="attacked">被攻击者的位置</param>
/// <param name="angle">攻击点到其中一侧的夹角,即整个扇形角度为 2 * angle</param>
/// <param name="radius"></param>
/// <returns></returns>
private bool UmbrallaAttack(Transform attacker, Transform attacked, float angle, float radius) //生成一个扇形体范围的碰撞区域
{
Vector3 tmpDistance = attacked.position - attacker.position; //算出攻击者和被攻击者之间的向量差
//取值范围 [-1, 1]
float tmpNormalized = Vector3.Dot(attacked.right.normalized, tmpDistance.normalized); //计算出在攻击方向的单位向量上的投影
float tmpRadian = Mathf.Acos(tmpNormalized); //计算出弧度
float tmpAngle = Mathf.Rad2Deg * tmpRadian;
float tmpDis = tmpDistance.magnitude; //已知向量,求tmpDistance的距离长度
//float tmpDis2 = Vector3.Distance(attacker.position, attacked.position); //求两点间的距离长度
//Debug.Log("tmpAngle == " + tmpAngle + "tmpDis == " + tmpDis + "tmpDis2 == " + tmpDis2);
if(tmpAngle <= angle && tmpDis <= radius)
{
Debug.Log("Attack!!!");
return true;
}
return false;
}
Part 2 叉乘:
数学上的叉乘 使用右手定则 确认 结果向量方向
Unity中的叉乘 使用左手定则 确认结果向量方向
叉乘方法
Vector3.Cross(tmpA, tmpB) 叉乘结果是一个向量
**叉乘的主要应用是:**求方向
在同一平面内, 结果 > 0 表示 B在A的逆时针方向, 结果 <0 表示B在A的顺式针方向, 结果 = 0表示B与A同向
左手定则:
Vector3.Cross(tmpA, tmpB) tmpA为大拇指,食指为tmpB, 其余三指自然弯曲90°即为叉乘结果
叉乘简单应用:判断方向
private void CrossTest(Vector3 tmpA, Vector3 tmpB)
{
Vector3 result = Vector3.Cross(tmpA, tmpB);
if(result.y> 0){
Debug.Log("tmpB在tmpA的顺时针方向");
}
if (result.y == 0){
Debug.Log("tmpB在tmpA同向");
}
if (result.y < 0) {
Debug.Log("tmpB在tmpA的逆时针方向");
}
}
void Update() {
Vector3 tmpA = attacked.position - transform.position;
Vector3 tmpB = newAttacked.position - transform.position;
CrossTest(tmpB, tmpA);
}
测试结果:
Part 3 点乘和叉乘的综合应用:
点乘求出相差角度,叉乘求出转向
让AI朝玩家方向自动移动,转向
void Update()
{
Vector3 tmpVector = Player.transform.position - transform.position;
float tmpDistance = tmpVector.magnitude; //计算AI到Player之间的距离
//Debug.Log("Distance == " + tmpDistance);
if (tmpDistance <= 7)
{
TimeCount += 0.1f;
if (TimeCount >= 0)
{
Debug.Log("Attack!!!");
BulletParent.GetComponent<BulletGen>().GenBullet(); //调用子弹实例化脚本方法
TimeCount = 0;
}
//transform.LookAt(Player);
}
else
{
Vector3 tmpCross = Vector3.Cross(transform.forward, tmpVector); //叉乘计算书 玩家在AI的哪一侧
if(tmpCross.y >= 0)
{
transform.Rotate(Vector3.up, 0.5f);
}
if (tmpCross.y < 0)
{
transform.Rotate(Vector3.up, -0.5f);
}
transform.Translate(Vector3.forward* 0.02f, Space.Self);
}
}
}