该效果实现需要解决两点问题:
1.检测人物是否处于门前
2.相对于人物开合,即人物在门外开门则门往里开,在里则往外开,关门亦然。
1.检测人物是否处于门前
我目前想到的有两种方法:
1.利用射线检测
2.利用触发器检测
利用射线检测需要注意的是控制射线发出的长短,或是计算人物与门的距离,反正要确保只能在门前进行开门关门。这里我主要是讲述第二种利用触发器检测的方法。
我们需要为门添加两个Collider组件,一个用作碰撞体,一个用作触发器(记得要把Is Trigger勾上)。然后调整Collider大小。
2.相对于人物开合
我采取的是利用向量的点乘来计算是人物是在门外还是门里,如果人物的前方向向量与门的前方向向量之间的夹角大于90°,就说明人物在门外,反之小于90°,就说明在门里。总而言之,就是使用向量之间的夹角(cos𝜃)大于1还是小于1来判断,cos90° = 0,即两向量垂直。
由于两者的大小我们并不需要关注,只需要知道cos的大小即可,所以我们需要把这两个方向向量归一化。
代码如下:
private void OnTriggerStay(Collider other)
{
if(other.gameObject.tag == "Player")
{
if (Input.GetKeyDown(KeyCode.F))
{
//由于关门时与开门时的旋转是向反的,所以我们需要一个bool来记录门的开关状态
//如果IsOpen为true,就说明门是开的,这时再按F就会变为false,然后向里旋转。
IsOpen = !IsOpen;
//点乘计算人物与门之间的夹角
float dis = Vector3.Dot(other.transform.forward.normalized,this.transform.right.normalized);
if (dis < Mathf.Cos(120) && IsOpen)
{
//Space.Self是已pivot为轴心旋转,默认是以Center为轴心
this.transform.Rotate(Vector3.up, 90f, Space.Self);
}
else if (dis > Mathf.Cos(60) && IsOpen)
{
this.transform.Rotate(Vector3.up, -90f, Space.Self);
}
}
}
}