2016-04-25 137 views
3

我從斯威夫特SpriteKit背景,其中移動精靈的X位置是直線前進爲如下運行行動學習統一:移動遊戲物體隨着時間的推移

let moveLeft = SKAction.moveToX(self.frame.width/5, duration: 1.0) 
let delayAction = SKAction.waitForDuration(1.0) 
let handSequence = SKAction.sequence([delayAction, moveLeft]) 
sprite.runAction(handSequence) 

我想知道的相同或相似在特定的持續時間(例如,秒)中將精靈移動到特定位置的方式,其延遲不必在更新功能中調用。

+0

我強烈建議使用類似的ITween的擴展這種控制的動畫 – caulitomaz

+1

@caulitomaz並不需要的ITween或插件that.He只需要學習Coroutune。 – Programmer

+1

不要在這裏使用iTween,忘記了。 – Fattie

回答

9

gjttt1的答案是接近這一點遠遠優於工作,但缺少了重要的功能和用於移動遊戲對象是不可接受的使用WaitForSeconds()。您應該使用Lerp,CoroutineTime.deltaTime的組合。你必須理解這些東西才能夠從Unity中的Script中完成動畫。

public GameObject objectectA; 
public GameObject objectectB; 

void Start() 
{ 
    StartCoroutine(moveToX(objectectA.transform, objectectB.transform.position, 1.0f)); 
} 


bool isMoving = false; 

IEnumerator moveToX(Transform fromPosition, Vector3 toPosition, float duration) 
{ 
    //Make sure there is only one instance of this function running 
    if (isMoving) 
    { 
     yield break; ///exit if this is still running 
    } 
    isMoving = true; 

    float counter = 0; 

    //Get the current position of the object to be moved 
    Vector3 startPos = fromPosition.position; 

    while (counter < duration) 
    { 
     counter += Time.deltaTime; 
     fromPosition.position = Vector3.Lerp(startPos, toPosition, counter/duration); 
     yield return null; 
    } 

    isMoving = false; 
} 

類似的問題:SKAction.scaleXTo

+0

謝謝!也可以在'rotation'上使用'Vector3.Lerp',想象如果你想讓對象從'startRotation'旋轉到'endRotation'(x,y,z) – vikingsteve

+0

@vikingsteve是的。如果是增量旋轉,則可以使用'Vector3.Lerp'來更改'transform.eulerAngles'。如果你只想從rotationA轉到rotateB,那麼'Quaternion.Lerp'應該用來改變'transform.rotation'。其餘的代碼保持不變。請參閱我的[other](https://stackoverflow.com/a/37588536/3785314)該解決方案的答案。 – Programmer

+1

謝謝senpai! Unity線程是錯誤的.. –

1

您可以使用協程來做到這一點。要做到這一點,創建一個返回類型IEnumerator的功能,包括一個循環做你想要的:

private IEnumerator foo() 
{ 
    while(yourCondition) //for example check if two seconds has passed 
    { 
     //move the player on a per frame basis. 
     yeild return null; 
    } 
} 

然後,你可以通過使用StartCoroutine(foo())

這調用該函數每幀調用它它從上次停止的地方開始。因此在這個例子中,它在一幀上停止在yield return null,然後在下一幀重新開始:因此它每幀重複while循環中的代碼。

如果你想暫停一段時間,那麼你可以使用yield return WaitForSeconds(3)等待3秒鐘。你也可以yield return其他的例程!這意味着當前例程將暫停並運行第二個協程,然後在第二個協程完成後再次拾取。

我建議您檢查docs,因爲他們做解釋比我在這裏可以

2

GIT1的答案是好的,但有,如果你不希望使用couritines另一種解決方案。

您可以使用InvokeRepeating重複觸發某個功能。

float duration; //duration of movement 
float durationTime; //this will be the value used to check if Time.time passed the current duration set 

void Start() 
{ 
    StartMovement(); 
} 

void StartMovement() 
{ 
    InvokeRepeating("MovementFunction", Time.deltaTime, Time.deltaTime); //Time.deltaTime is the time passed between two frames 
    durationTime = Time.time + duration; //This is how long the invoke will repeat 
} 

void MovementFunction() 
{ 
    if(durationTime > Time.time) 
    { 
     //Movement 
    } 
    else 
    { 
     CancelInvoke("MovementFunction"); //Stop the invoking of this function 
     return; 
    } 
} 
+1

確實,這工作得很好,每個人都應該學會使用InvokeRepeating。通常,在這裏使用協程就是慣用的。 – Fattie