2012-07-16 84 views
4

我是Unity的新手,我正試圖弄清楚如何使用觸摸輸入將攝像機移動到地圖/地形上。相機將以(90,0,0)的旋轉俯視地形。地形是在第8層。我沒有任何問題讓它隨鍵盤移動,現在我試圖移動觸摸,如果你想保持在iOS上的預期使用,它是非常不同的。在Unity 3D中使用觸摸輸入移動攝像機

我能想到的iOS應用程序內置的最佳示例是地圖,用戶可以觸摸屏幕,只要手指停留在屏幕上,地圖上的那個點將保持在手指下。因此,當用戶移動他們的手指時,地圖似乎隨着手指移動。我一直無法找到證明如何以這種方式進行操作的例子。我已經看到可能會用鼠標移動相機或角色的例子,但它們似乎並沒有很好地適應這種風格。

也被張貼在Unity3D答案:

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

+0

只是爲了澄清,你是想模仿'地圖'的應用程序行爲,還是隻需要一個腳本來處理基於觸摸的移動? – Jerdak 2012-07-16 01:50:34

+0

實質上是,如果用戶將手指放在屏幕上,手指下面的地形/地圖區域應該保持在它們的手指下面,因爲它們移動。 – 2012-07-16 14:44:32

回答

11

下面應該是你所需要的。請注意,在使用「透視」攝像機時,在手指/光標與地形之間獲得1對1的對應關係非常棘手。如果您將相機更改爲拼寫,下面的腳本應該會爲您提供手指/光標位置和地圖移動之間的完美映射。用「透視圖」你會注意到一個輕微的偏移量。

你也可以使用光線追蹤來做到這一點,但我發現這條路線sl and而不直觀。

測試相機的設置(值從檢查拉動,應用它們存在):

  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; 
} 
} 
+0

這相當接近。在左側或右側移動的時間越長,手指/鼠標下方的地面越向阻力方向漂移。它引人注目,而且是一個很好的起點。謝謝! – 2012-07-19 00:38:56

+0

Input.GetMouseButtonDown是否適用於觸摸? – 2014-01-07 13:11:27

+0

@bagusflyer是的。 '(Input.GetMouseButtonDown(0))'相當於'(Input.touchCount> 0 && Input.GetTouch(0).phase == TouchPhase.Began)',或者它在Unity 3.5中。在版本4.x中沒有嘗試 – Jerdak 2014-01-07 14:45:09

6

心中已經Ë想出這個劇本(我把它附加在相機):

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; 
} 
+0

這對e很有用。 G。在你的「光標」/觸摸下保持一個平面。 – 2016-02-01 17:47:49

1

帕維爾的回答對我幫助很大,所以想分享我與社區的情況下,它可以幫助別人解決方案。我的場景是一個帶有正交相機的3D世界。我正在從事的自上而下的RTS風格。我希望平移和縮放像谷歌地圖一樣工作,當您平移和縮放時,鼠標始終停留在地圖上的相同位置。這個腳本爲我實現了這個目標,並希望它足夠強大,可以滿足其他人的需求。我還沒有測試過它,但我評論說它爲初學者學習。

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; 
    } 
}