测试工程:
链接:https://pan.baidu.com/s/1pkbETe_7vVWtYu5jXx-GOw
提取码:tybh
1、需求:右侧圆柱体会在Z轴上进行旋转,以及在Y轴方向移动,需要检测到左侧小球所在位置水平方向上与圆柱体相交的点(圆柱体内部中间);
2、方法:将圆柱体的CapsuleCollider.Radius,使射线碰撞检测是时RaycastHit.point刚好在圆柱体内部;
3、在点击“角度”或者“位置”(圆柱非竖直时有效)时,先进行角度或者位置变化,然后进行射线碰撞检测,记录下来射线检测碰撞点,并且开启Update中的射线检测;在Update中进行碰撞检测,第一帧碰撞位置与后面帧(设置运行1秒后关闭)打印位置不同,也存在滞后一帧的情况;
最后问题:
请问下,物体旋转或者位置发生改变时,相关顶点的位置更新时在下一帧进行?还是说Physics.Raycast中的碰撞检测也是在下一帧执行,只是执行时间早于位置顶点的更新?或者其他什么原因导致碰撞点滞后一帧?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Manager : MonoBehaviour
{
public Transform cylinder;
public Transform physicsRaycast;
Vector3 initPosition;
Vector3 initRotation;
public Button angle;
public Button position;
public Button reset;
/// <summary>
/// 点击时,只执行射线碰撞检测,不进行角度和位置的变化;
/// </summary>
public Button rePhysicsRaycast;
/// <summary>
/// 射线碰撞到的点
/// </summary>
Vector3 hitPosition = Vector3.zero;
/// <summary>
/// 在Update中是否开始打印
/// </summary>
bool isDebugMessage = false;
/// <summary>
/// Update中开启打印时间,默认打印1s数据后停止打印
/// </summary>
float time = 1;
// Start is called before the first frame update
void Start()
{
initPosition = cylinder.position;
initRotation = cylinder.localEulerAngles;
angle.onClick.AddListener(AngleClick);
position.onClick.AddListener(PositionClick);
reset.onClick.AddListener(ResetClinder);
rePhysicsRaycast.onClick.AddListener(RePhysicsRaycastClick);
}
void AngleClick()
{
Debug.Log("点击角度旋转-----前: X1 : " + hitPosition.x + "***"
+ "Y1 : " + hitPosition.y + "***"
+ "Z1 : " + hitPosition.z);
cylinder.localEulerAngles = new Vector3(cylinder.localEulerAngles.x, cylinder.localEulerAngles.y, cylinder.localEulerAngles.z - 10);
UpdatePhysics("角度发生改变: ");
Debug.Log("点击角度旋转-----后: X2 : " + hitPosition.x + "***"
+ "Y2 : " + hitPosition.y + "***"
+ "Z2 : " + hitPosition.z);
}
void PositionClick()
{
cylinder.position = new Vector3(cylinder.position.x, cylinder.position.y + 0.2f, cylinder.position.z);
UpdatePhysics("位置发生改变: ");
Debug.Log("点击位置移动-----后: X5 : " + hitPosition.x + "***"
+ "Y5 : " + hitPosition.y + "***"
+ "Z5 : " + hitPosition.z);
}
void ResetClinder()
{
cylinder.position = initPosition;
cylinder.localEulerAngles = initRotation;
}
void RePhysicsRaycastClick()
{
UpdatePhysics("不进行位置、角度,只进行射线碰撞检测:");
Debug.Log("不进行位置、角度,只进行射线碰撞检测: X3 : " + hitPosition.x + "***"
+ "Y3 : " + hitPosition.y + "***"
+ "Z3 : " + hitPosition.z);
}
void UpdatePhysics(string name)
{
isDebugMessage = true;
//GameObject temp1 = new GameObject(name + "temp1");
//temp1.transform.position = hitPosition;
//创建一条指定方向的射线
Ray ray = new Ray(physicsRaycast.position, physicsRaycast.right * 100);
RaycastHit hit;
//范围内是否有碰撞
bool isHit = Physics.Raycast(ray, out hit, 100);
if (isHit && hit.collider.gameObject.name.Equals("Cylinder"))
{
hitPosition = hit.point;
Debug.Log("射线碰撞检测-----中: X6 : " + hitPosition.x + "***"
+ "Y6 : " + hitPosition.y + "***"
+ "Z6 : " + hitPosition.z);
//GameObject temp2 = new GameObject(name + "temp2");
//temp2.transform.position = hitPosition;
}
}
// Update is called once per frame
void Update()
{
if (isDebugMessage)
{
time -= Time.deltaTime;
if(time <= 0)
{
isDebugMessage = false;
time = 1;
}
else
{
//创建一条指定方向的射线
Ray ray = new Ray(physicsRaycast.position, physicsRaycast.right * 100);
RaycastHit hit;
//范围内是否有碰撞
bool isHit = Physics.Raycast(ray, out hit, 100);
if (isHit && hit.collider.gameObject.name.Equals("Cylinder"))
{
hitPosition = hit.point;
Debug.Log("在Update中开启射线检测: X4 : " + hitPosition.x + "***"
+ "Y4 : " + hitPosition.y + "***"
+ "Z4 : " + hitPosition.z);
//GameObject temp2 = new GameObject(name + "temp2");
//temp2.transform.position = hitPosition;
}
}
Debug.Log("在Update中,点击按钮后开始打印信息: X7 : " + hitPosition.x + "***"
+ "Y7 : " + hitPosition.y + "***"
+ "Z7 : " + hitPosition.z);
}
}
}