c# - 如何使用透视相机移动物体并在 Unity3D 中旋转相机?
问题描述
我正在尝试旋转我的相机(X 轴为 50 度)并在触摸位置之后放置一个对象,这是我的脚本,可以旋转相机并移动对象,但由于它是透视的,因此对象没有正确移动手指,关于如何实现这一目标的任何提示?
目标是在此视频中实现类似https://www.youtube.com/watch?v=Ljnpp5ibfGQ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraRotator : MonoBehaviour
{
private float initialX;
public float offset = 10f;
public float speed = 10f;
public GameObject cube;
public bool movingPlayer = false;
void Update()
{
if (Input.touchCount > 0 && !movingPlayer)
{
Touch touch = Input.GetTouch(0);
Vector3 touchPosition = Camera.main.ScreenToWorldPoint(touch.position);
switch (touch.phase)
{
case TouchPhase.Began:
initialX = touch.position.x;
break;
case TouchPhase.Moved:
if (touch.position.x + offset < initialX)
transform.rotation = Quaternion.Euler(0f, transform.rotation.eulerAngles.y - speed, 0f);
else if (touch.position.x - offset > initialX)
transform.rotation = Quaternion.Euler(0f, transform.rotation.eulerAngles.y + speed, 0f);
initialX = touch.position.x;
break;
}
}
if (Input.touchCount > 0 && movingPlayer)
{
Touch touch = Input.GetTouch(0);
Vector3 touchPosition = Camera.main.ScreenToWorldPoint(touch.position);
Ray raycast = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
Vector3 xx = ray.GetPoint(10f);
xx.y = 1f;
xx.x = (int)xx.x;
xx.z = (int)xx.z;
cube.transform.position = xx;
}
}
}
}
解决方案
我前段时间创造了类似的东西。
你需要小心ScreenToWorldPoint()
。Click 位置基本上不是世界上的 3D 点,而是一条射线。空间中有一整行位置都将出现在屏幕上的同一个位置。
Unity 函数ScreenToWorldPoint()
使用来自输入向量的 Z 坐标作为距离。既然你只是从 捡来的Input.GetTouch()
,那肯定不是你想要的距离。
文档:https ://docs.unity3d.com/2020.1/Documentation/ScriptReference/Camera.ScreenToWorldPoint.html
最好使用Camera.ScreenPointToRay()
. 然后使用该射线来确定您要考虑单击的点。
在我的抓取实现中,我用它来调用Physics.Raycast()
or Physics.RaycastAll()
,查看找到的命中,然后决定命中点。
当玩家拖动时,你需要决定如何改变距离。如果单击示例视频链接中的地图,您可能会保留单击目标的 Y 坐标,然后每次鼠标移动都将新射线与该 Y 平面相交。
在我的示例中,我只是保持距离,让玩家移动物品,保持与拾取时相同的距离。
从我的示例中,单击时我会这样做:
// try to grab something.
Ray beam = new Ray(){origin=head.transform.position,direction=head.transform.forward};
RaycastHit hit;
if( ! Physics.Raycast(beam,out hit,15.0f) )
return;
grab_item = hit.rigidbody;
if( grab_item==null || grab_item.isKinematic )
return;
grab_pos_on_item = grab_item.transform.InverseTransformPoint(hit.point);
grab_distance = (hit.point-beam.origin).magnitude;
然后,在每次更新中,检查新点的位置,然后将项目移到那里。
if(grab_item!=null)
{
// p1: hand, p2: item
Vector3 p1 = head.transform.position + head.transform.forward * grab_distance;
Vector3 p2 = grab_item.transform.TransformPoint(grab_pos_on_item);
Vector3 dist = p1-p2;
// code to make the item move by 'dist'
如果我理解正确,您可能有兴趣保持 Y 坐标不变?
推荐阅读
- json.net - 反序列化基类对象的集合不会调用继承的转换器
- json - 无法使用 React Native 从 API 获取单个项目
- javascript - 如何编写这些方法来更改可构造函数中的 x 和 y 位置?
- ruby-on-rails - ActiveRecord::RecordNotSaved: 未能保存新的关联余额
- excel - 将 CSV 数据导入工作簿时 Excel 崩溃
- python - 将值添加到字典中的列
- r - 如何基于另一个 var 提取具有相同最大日期的 dup 值?
- python - 在数据帧上计算杰卡德相似度
- javascript - 控制不进入认知认证功能
- python - *错误:发生 FileNotFoundError 类型的异常。参数:(2, '系统找不到指定的文件', None, 2, None)