在Unity 3D中使用触摸input在地形上移动摄像机

我是Unity的新手,我正试图弄清楚如何使用触摸input在地图/地形上移动摄像头。 相机将会以(90,0,0)的旋转向下看地形。 地形是在第8层。我已经没有问题让它随键盘移动,现在我试图移动触摸,这是非常不同的,如果你想保持预期的使用在iOS上。

在iOS应用程序中我可以想到的最好的例子是地图,用户可以触摸屏幕,只要手指停留在屏幕上,地图上的那个点就会留在手指的下面。 所以当用户移动他们的手指时,地图似乎是随着手指移动的。 我一直没有find能够说明如何去做的例子。 我已经看到可能会用鼠标移动相机或angular色的例子,但他们似乎不能很好地转换这种风格。

也发布在Unity3D上答案:

http://answers.unity3d.com/questions/283159/move-camera-over-terrain-using-touch-input.html

以下应该是你需要的。 请注意,在使用“透视”摄像机时,在手指/光标与地形之间获得1对1的对应关系是非常棘手的。 如果您将相机更改为正交,下面的脚本应该会为您提供手指/光标位置和地图移动之间的完美映射。 用“透视”你会注意到一个轻微的偏移量。

你也可以用光线跟踪来做到这一点,但是我发现这条路线很sl and,不那么直观。

用于testing的相机设置(值从检查员拉出,所以应用在那里):

  1. 位置:0,20,0
  2. 方向:90,0,0
  3. 投影:透视/正字法

using UnityEngine; using System.Collections; public class ViewDrag : MonoBehaviour { Vector3 hit_position = Vector3.zero; Vector3 current_position = Vector3.zero; Vector3 camera_position = Vector3.zero; float z = 0.0f; // Use this for initialization void Start () { } void Update(){ if(Input.GetMouseButtonDown(0)){ hit_position = Input.mousePosition; camera_position = transform.position; } if(Input.GetMouseButton(0)){ current_position = Input.mousePosition; LeftMouseDrag(); } } void LeftMouseDrag(){ // From the Unity3D docs: "The z position is in world units from the camera." In my case I'm using the y-axis as height // with my camera facing back down the y-axis. You can ignore this when the camera is orthograhic. current_position.z = hit_position.z = camera_position.y; // Get direction of movement. (Note: Don't normalize, the magnitude of change is going to be Vector3.Distance(current_position-hit_position) // anyways. Vector3 direction = Camera.main.ScreenToWorldPoint(current_position) - Camera.main.ScreenToWorldPoint(hit_position); // Invert direction to that terrain appears to move with the mouse. direction = direction * -1; Vector3 position = camera_position + direction; transform.position = position; } } 

我已经提出了这个脚本(我已经把它添加到相机):

 private Vector2 worldStartPoint; void Update () { // only work with one touch if (Input.touchCount == 1) { Touch currentTouch = Input.GetTouch(0); if (currentTouch.phase == TouchPhase.Began) { this.worldStartPoint = this.getWorldPoint(currentTouch.position); } if (currentTouch.phase == TouchPhase.Moved) { Vector2 worldDelta = this.getWorldPoint(currentTouch.position) - this.worldStartPoint; Camera.main.transform.Translate( -worldDelta.x, -worldDelta.y, 0 ); } } } // convert screen point to world point private Vector2 getWorldPoint (Vector2 screenPoint) { RaycastHit hit; Physics.Raycast(Camera.main.ScreenPointToRay(screenPoint), out hit); return hit.point; } 

帕维尔的回答帮了我很大的忙,所以想与社区分享我的解决scheme,以帮助他人。 我的场景是一个正交相机的3D世界。 我正在从事自上而下的RTS风格。 我希望平移和缩放像Google地图一样工作,当您平移和缩放时,鼠标总是停留在地图上的相同位置。 这个脚本为我实现了这个目标,希望它足够强大,可以满足他人的需求。 我还没有testing过它,但我评论说,它为初学者学习。

 using UnityEngine; // I usually attach this to my main camera, but in theory you can attach it to any object in scene, since it uses Camera.main instead of "this". public class CameraMovement : MonoBehaviour { private Vector3 MouseDownPosition; void Update() { // If mouse wheel scrolled vertically, apply zoom... // TODO: Add pinch to zoom support (touch input) if (Input.mouseScrollDelta.y != 0) { // Save location of mouse prior to zoom var preZoomPosition = getWorldPoint(Input.mousePosition); // Apply zoom (might want to multiply Input.mouseScrollDelta.y by some speed factor if you want faster/slower zooming Camera.main.orthographicSize = Mathf.Clamp(Camera.main.orthographicSize + Input.mouseScrollDelta.y, 5, 80); // How much did mouse move when we zoomed? var delta = getWorldPoint(Input.mousePosition) - preZoomPosition; // Rotate camera to top-down (right angle = 90) before applying adjustment (otherwise we get "slide" in direction of camera angle). // TODO: If we allow camera to rotate on other axis we probably need to adjust that also. At any rate, you want camera pointing "straight down" for this part to work. var rot = Camera.main.transform.localEulerAngles; Camera.main.transform.localEulerAngles = new Vector3(90, rot.y, rot.z); // Move the camera by the amount mouse moved, so that mouse is back in same position now. Camera.main.transform.Translate(delta.x, delta.z, 0); // Restore camera rotation Camera.main.transform.localEulerAngles = rot; } // When mouse is first pressed, just save location of mouse/finger. if (Input.GetMouseButtonDown(0)) { MouseDownPosition = getWorldPoint(Input.mousePosition); } // While mouse button/finger is down... if (Input.GetMouseButton(0)) { // Total distance finger/mouse has moved while button is down var delta = getWorldPoint(Input.mousePosition) - MouseDownPosition; // Adjust camera by distance moved, so mouse/finger stays at exact location (in world, since we are using getWorldPoint for everything). Camera.main.transform.Translate(delta.x, delta.z, 0); } } // This works by casting a ray. For this to work well, this ray should always hit your "ground". Setup ignore layers if you need to ignore other colliders. // Only tested this with a simple box collider as ground (just one flat ground). private Vector3 getWorldPoint(Vector2 screenPoint) { RaycastHit hit; Physics.Raycast(Camera.main.ScreenPointToRay(screenPoint), out hit); return hit.point; } }