2016-07-18 1 views
0

사용자가 카메라를 드래그하여 이동하는 Unity3d의 Android 태블릿 장치 용 스크립트를 작업하고 있습니다. 나는 그가 움직이는 동안 사용자의 손가락 아래에 머무르기 위해 터치 위치에있는 "땅"을 원한다. 여기에 지금까지 내 simplyfied 작업 코드 :Unity3d의 관성이있는 Android 터치 카메라 컨트롤

using UnityEngine; 

public class CameraMovement : MonoBehaviour 
{ 
    Plane plane = new Plane(Vector3.forward, Vector3.zero); 
    Vector2 worldStartPoint; 

    void Update() 
    { 
     if (Input.touchCount == 1) 
     { 
      Touch touch = Input.GetTouch(0); 

      if (touch.phase == TouchPhase.Began) 
      { 
       this.worldStartPoint = GetWorldPoint(touch.position); 
      } 

      if (touch.phase == TouchPhase.Moved) 
      { 
       Vector2 worldDelta = GetWorldPoint(touch.position) - worldStartPoint; 
       transform.Translate(-worldDelta.x, -worldDelta.y, 0); 
      } 
     } 
    } 

    Vector2 GetWorldPoint(Vector2 screenPoint) 
    { 
     Ray ray = Camera.main.ScreenPointToRay(screenPoint); 
     float rayDistance; 
     if (plane.Raycast(ray, out rayDistance)) 
      return ray.GetPoint(rayDistance); 

     return Vector2.zero; 
    } 
} 

지금 문제가있는 부분 : 사용자가 자신의 손가락을 리프트 일단 내가 물리학 객체처럼 이동 카메라를 싶습니다. 드래그하는 동안 현재 속도를 계산하려고 시도하고 있으며 현재 드래그하지 않는 동안 감속/관성과 같은 효과로 적용하려고합니다. 이론적으로 나는 이런 짓을 했을까 :

Vector2 worldStartPoint; 
Vector3 velocity; 

void Update() 
{ 
    if (Input.touchCount == 1) 
    { 
     Touch touch = Input.GetTouch(0); 

     if (touch.phase == TouchPhase.Began) 
     { 
      this.worldStartPoint = GetWorldPoint(touch.position); 
     } 

     if (touch.phase == TouchPhase.Moved) 
     { 
      Vector2 worldDelta = GetWorldPoint(touch.position) - worldStartPoint; 
      transform.Translate(-worldDelta.x, -worldDelta.y, 0); 

      velocity = worldDelta/Time.deltaTime; 
     } 
    } 
    else 
    { 
     transform.Translate(-velocity * Time.deltaTime); 
     velocity = Vector3.MoveTowards(velocity, Vector3.zero, damping * Time.deltaTime); 
    } 
} 

그래서 이동하는 동안, 난 항상 속도를 계산하고 내가 입력을 중지하면, 그것은, 마지막으로 알려진 속도 유지를 적용하고 정지 할 때까지 거기부터 줄여야합니다. 그러나 화면을 가로 질러 드래그/스 와이프하면 실제로 손가락이 곧 멈추고 0 속도를보고하기 때문에 마지막 속도는 0입니다. TouchPhase.Moved은 끝났습니다.

이제 내 솔루션/해결 방법은 마지막 몇 프레임 (어쩌면 30)의 속도 배열을 유지하고 손가락을 들으면 평균 속도를 계산합니다.

Vector3[] velocityBuffer = new Vector3[bufferSize]; 
int nextBufferIndex; 

Vector3 GetAverage() 
{ 
    Vector3 sum = Vector3.zero; 
    for (int i = 0; i < bufferSize; i++) 
     sum += velocityBuffer[i]; 

    return sum/bufferSize; 
} 

이 종종 그것이 적어도 일부 속도를보고보다 이후, 좀 더 나은 작동하지만 총이별로 더 나은 또한 매우 해키 느낀다. 터치의 속도에 따라, 제로 속도의 20 개 항목으로 끝나서 댐핑을 너무 강하게 만들 수 있습니다. 때로는 속도가 무작위로 커져 카메라가 단지 수백 개의 단위를 긋습니다.

계산에 문제가 있습니까? 아니면 이것을 간단하게 살펴볼 수 있습니까? 누구든지 부드러운 카메라 드래그의 작업 솔루션을 가지고 있습니까? 나는 약간의 모바일 게임을 보았고 많은 사람들이 사실 델타 이동의 몇 픽셀 후에 손가락 위치로 카메라를 찍은 것처럼 갑자기 조금 어색함을 느꼈다.

답변

0

완벽한 해결책을 찾은 것처럼 느껴지지는 않지만, 적어도 지금은 더 잘 작동하고 또한 "신체적으로 올바른"것이 있습니다. 먼저, 속도 대신 카메라 위치와 deltaTime을 버퍼에 저장합니다. 이렇게하면 정확한 시간 계수를 사용하여 10 프레임마다 롤링 평균을 계산할 수 있습니다.

/// <summary> 
/// Stores Vector3 samples such as velocity or position and returns the average. 
/// </summary> 
[Serializable] 
public class Vector3Buffer 
{ 
    public readonly int size; 

    Sample[] sampleData; 
    int nextIndex; 

    public Vector3Buffer(int size) 
    { 
     if (size < minSize) 
     { 
      size = minSize; 
      Debug.LogWarning("Sample count must be at least one. Using default."); 
     } 

     this.size = size; 
     sampleData = new Sample[size]; 
    } 

    public void AddSample(Vector3 position, float deltaTime) 
    { 
     sampleData[nextIndex] = new Sample(position, deltaTime); 
     nextIndex = ++nextIndex % size; 
    } 

    public void Clear() 
    { 
     for (int i = 0; i < size; i++) 
      sampleData[i] = new Sample(); 
    } 

    public Vector3 GetAverageVelocity(Vector3 currentPosition, float currentDeltaTime) 
    { 
     // The recorded sample furthest back in time. 
     Sample previous = sampleData[nextIndex % size]; 
     Vector3 positionDelta = currentPosition - previous.position; 
     float totalTime = currentDeltaTime; 
     for (int i = 0; i < size; i++) 
      totalTime += sampleData[i].deltaTime; 

     return positionDelta/totalTime; 
    } 

    [Serializable] 
    struct Sample 
    { 
     public Vector3 position; 
     public float deltaTime; 

     public Sample(Vector3 position, float deltaTime) 
     { 
      this.position = position; 
      this.deltaTime = deltaTime; 
     } 
    } 

    public const int minSize = 1; 
} 

또한, 나는 나는 나는 또한 드래그하지 않을 경우 업데이트 할 위치를 추적하고 있습니다 때문에 지금 완화 0의 속도 값을 많이 기록 만 유지 한 것을 발견 :

if (input.phase == TouchPhase.Moved || input.phase == TouchPhase.Stationary) 
{ 
    velocityBuffer.AddSample(transform.position, Time.deltaTime); 
} 

if (input.phase == TouchPhase.Ended || input.phase == TouchPhase.Canceled) 
{ 
    velocity = -velocityBuffer.GetAverageVelocity(transform.position, Time.deltaTime); 
} 

마지막으로 카메라를 모든 프레임의 핑거 월드 위치로 설정하는 대신 작은 비트의 Lerp/MoveTowards 보간을 사용하여 지터를 부드럽게 만듭니다. 선명한 제어와 매끄러운 모양 사이에서 최상의 가치를 얻는 것은 어렵지만 사용자 입력과 함께 이동하는 방법이라고 생각합니다. 사용자 입력은 빠르게 변할 수 있습니다.

물론, 저는 여전히 현재의 구현에 대한 다른 접근 방식, 더 나은 솔루션 또는 의견에 관심이 있습니다.