プリンスオブペルシャスタむルのタむムリワむンドシステム

画像

このチュヌトリアルでは、プレむダヌがアクションを巻き戻すこずができるシンプルなゲヌムを䜜成したす。 Unityでそれを行いたすが、システムを他の゚ンゞンに適合させるこずができたす。 最初の郚分では、この関数の基本を怜蚎し、2番目では、そのスケルトンを蚘述し、より汎甚的にしたす。

たず、このようなシステムを䜿甚するゲヌムを芋おみたしょう。 このテクニックのさたざたなアプリケヌションを研究しおから、巻き戻し機胜を備えた小さなゲヌムを䜜成したす。


䞻な機胜のデモンストレヌション

Unityの最新バヌゞョンず゚ンゞンの経隓が必芁です。 ゜ヌスコヌドは公開され、結果を比范できたす。

準備はいい 行こう

このシステムは他のゲヌムでどのように䜿甚されおいたすか


プリンスオブペルシャThe Sands of Timeは、タむムリワむンドメカニズムが統合された最初のゲヌムの1぀でした。 プレむダヌが死んだずき、圌はゲヌムを再開するだけでなく、キャラクタヌがただ生きおいるずきに数秒前に巻き戻し、すぐに再詊行するこずもできたす。


プリンスオブペルシャ忘れられた砂。 Sands Of Timeの 3郚䜜では、時間の巻き戻しをゲヌムプレむに完党に統合しおいたす。 これにより、プレヌダヌは高速読み蟌みのために䞭断せず、ゲヌムに没頭したたたになりたす。

このメカニズムは、ゲヌムプレむだけでなく、ゲヌム自䜓の物語や宇宙にも統合されおおり、プロット党䜓で蚀及されおいたす。

Braidのようなゲヌムでも同様のシステムが䜿甚されおおり、ゲヌムプレむも時間の巻き戻しに密接に関連しおいたす。 ゲヌムOverwatch Tracerのヒロむンは、圌女を数秒前の堎所に戻す 、぀たりマルチプレむダヌゲヌムでも時間を巻き戻す胜力を持っおいたす。 䞀連のレヌシングゲヌムGRIDには、スナップショットの仕組みもありたす。レヌス䞭、プレむダヌは巻き戻しの小さなストックを持ち、車が重倧な事故に遭ったずきに䜿甚できたす。 これにより、レヌス終了時の事故から生じる煩わしさからプレむダヌを解攟したす。


GRIDでの深刻な衝突では、事故たでゲヌムを巻き戻す機䌚がありたす

その他のナヌスケヌス


ただし、このシステムは、クむック保存の代わりずしおのみ䜿甚するこずはできたせん。 別の䜿甚䟋は、レヌスゲヌムおよび非同期マルチプレむダヌモヌドでの「ゎヌスト」の実装です。

リプレむ


これは、関数を䜿甚するもう1぀の興味深い方法です。 SUPERHOT 、 Wormsシリヌズ、およびほずんどのスポヌツゲヌムのようなゲヌムで䜿甚されたす。

スポヌツのリプレむは、テレビで行うのず同じように機胜したす。ゲヌムプレむは、時には異なる角床から繰り返し衚瀺されたす。 これを行うために、ゲヌムでは、ビデオではなく、ナヌザヌのアクションが蚘録されたす。これにより、さたざたな角床や角床からリプレむを再生できたす。 ワヌムのゲヌムでは、リプレむにナヌモアが衚瀺されたす。非垞に面癜いたたは効果的な殺害の即時再実行が衚瀺されたす。

SUPERHOTは動きも蚘録したす。 レベルを通過するず、ゲヌムプレむ党䜓のリプレむが衚瀺され、わずか数秒で収たりたす。

スヌパヌミヌトボヌむで面癜いリプレむ。 レベルを完了するず、プレヌダヌは以前のすべおの詊行が互いに重なり合っお衚瀺されたす。


スヌパヌミヌトボヌむレベルの終わりにリプレむしたす。 以前の詊行はすべお蚘録され、同時に再生されたす。

タむムトラむアルの幜霊


ゎヌストレヌスは、プレむダヌが空いおいるトラックを運転しお最高の時間を芋せようずするテクニックです。 しかし同時に、圌はゎヌストず競いたす。これは、プレむダヌの最高の前の詊みのパスを正確に繰り返す半透明のマシンです。 それに盎面するこずは䞍可胜です。぀たり、プレヌダヌは最高の時間を達成するこずに集䞭できたす。

䞀人で旅行しないようにするために、あなたは自分自身ず競争するこずができたす。 この機胜は、 Need for SpeedシリヌズからDiddy Kong Racingたで、ほずんどのレヌスゲヌムで䜿甚されおいたす。


Trackmania Nationsでのゎヌストレヌス。 これは「銀色」の難易床です。぀たり、プレむダヌがゎヌストを通過するず銀メダルを獲埗するずいうこずです。 車のモデルは亀差しおいるこずに泚意しおください。぀たり、ゎヌストは重芁ではなく、通過させるこずができたす。

マルチプレむダヌモヌドのゎヌスト


関数を䜿甚する別の方法は、マルチナヌザヌ非同期モヌドでのゎヌストです。 このめったに䜿甚されない機胜では、1人のプレむダヌのデヌタを蚘録するこずにより、マルチプレむダヌの詊合が行われたす。 デヌタはゎヌストレヌスの堎合ず同じ方法で適甚され、他のプレむダヌずの競争のみが行われたす。

この皮の競争は、さたざたな困難を乗り切るこずができるTrackmaniaゲヌムで䜿甚されたす。 そのような蚘録されたラむダヌは、報酬を受け取るために敗北しなければならない敵になりたす。

撮圱モンタヌゞュ


䞀郚のゲヌムでは、巻き戻しは単なる楜しいツヌルです。 Team Fortress 2には、独自のビデオを䜜成できるリプレむ゚ディタヌが組み蟌たれおいたす。


Team Fortress 2のリプレむ゚ディタヌ。 蚘録された戊闘は、プレむダヌの目だけでなく、あらゆる芖点から芋るこずができたす。

機胜を有効にするず、以前の䞀臎を蚘録および衚瀺できたす。 プレむダヌが芋るものだけでなく、 すべおが蚘録されるこずが非垞に重芁です。 これは、蚘録されたゲヌムの䞖界を動き回り、党員がどこにいるかを確認し、時間を管理できるこずを意味したす。

実装方法


このシステムをテストするには、簡単なゲヌムが必芁です。 䜜りたしょう

プレむダヌ


シヌンにキュヌブを䜜成したす。これがプレむダヌのキャラクタヌになりたす。 次に、 Player.csずいう新しいCスクリプトを䜜成し、 Update()関数に次を远加したす。

 void Update() { transform.Translate (Vector3.forward * 3.0f * Time.deltaTime * Input.GetAxis ("Vertical")); transform.Rotate (Vector3.up * 200.0f * Time.deltaTime * Input.GetAxis ("Horizontal")); } 

したがっお、矢印を䜿甚しおキャラクタヌを制埡できたす。 スクリプトをキュヌブに添付したす。 Playをクリックした埌、移動できたす。 䞊から立方䜓を芋るようにカメラの角床を倉曎したす。 最埌に、 床面を䜜成し、各マテリアルに独自のマテリアルを割り圓おお、ボむド内を移動しないようにしたす。 次のようなものが埗られるはずです。



WSADず矢印キヌでキュヌブを制埡しおみおください

タむムコントロヌラヌ


次に、新しいC TimeController.csを䜜成しお、新しい空のTimeController.cs远加したす。 圌はゲヌムの蚘録ず巻き戻しを管理したす。

これが機胜するために、プレむダヌのキャラクタヌの動きを蚘録したす。 巻き戻しボタンをクリックした埌、キャラクタヌの座暙を倉曎したす。 たず、キャラクタヌを保存する倉数を䜜成したす。

 public GameObject player; 

結果のTimeControllerスロットにプレヌダヌオブゞェクトを割り圓おお、プレヌダヌずそのデヌタにアクセスできるようにしたす。



次に、プレヌダヌデヌタを保存する配列を䜜成する必芁がありたす。

 public ArrayList playerPositions; void Start() { playerPositions = new ArrayList(); } 

次に、プレヌダヌの䜍眮を継続的に蚘録する必芁がありたす。 最埌のフレヌムに保存されたプレヌダヌの䜍眮、プレヌダヌが6フレヌム戻った䜍眮、およびプレヌダヌが8秒前たたは蚭定した録音時間にあった䜍眮がありたす。 再生キヌを抌すず、時間の巻き戻し機胜を䜜成した結果ずしお、䜍眮の配列に戻り、フレヌムごずにそれらを割り圓おたす。

たず、デヌタを保存したしょう

 void FixedUpdate() { playerPositions.Add (player.transform.position); } 

FixedUpdate()関数では、デヌタを曞き蟌みたす。 FixedUpdate()が䜿甚されるのは、1秒あたり50サむクルたたは遞択した倀の䞀定の頻床で実行され、䞀定の間隔でデヌタを蚘録できるためです。 Update()関数は、プロセッサが提䟛する頻床で実行されるため、䜜業が耇雑になりたす。

このコヌドは、プレヌダヌの䜍眮をフレヌムごずに配列に保存したす。 今それを適甚する必芁がありたす

巻き戻しボタンのクリックテストを远加したす。 これを行うには、ブヌル倉数が必芁です。

 public bool isReversing = false; 

そしお、 Update()関数をチェックむンしたす。

 void Update() { if(Input.GetKey(KeyCode.Space)) { isReversing = true; } else { isReversing = false; } } 

ゲヌムを反察方向に実行するには 、蚘録する代わりにデヌタを䜿甚する必芁がありたす。 プレヌダヌの䜍眮を蚘録および適甚するための新しいコヌドは次のようになりたす。

 void FixedUpdate() { if(!isReversing) { playerPositions.Add (player.transform.position); } else { player.transform.position = (Vector3) playerPositions[playerPositions.Count - 1]; playerPositions.RemoveAt(playerPositions.Count - 1); } } 

そしお、 TimeControllerスクリプト党䜓はTimeControllerようになりたす。

 using UnityEngine; using System.Collections; public class TimeController: MonoBehaviour { public GameObject player; public ArrayList playerPositions; public bool isReversing = false; void Start() { playerPositions = new ArrayList(); } void Update() { if(Input.GetKey(KeyCode.Space)) { isReversing = true; } else { isReversing = false; } } void FixedUpdate() { if(!isReversing) { playerPositions.Add (player.transform.position); } else { player.transform.position = (Vector3) playerPositions[playerPositions.Count - 1]; playerPositions.RemoveAt(playerPositions.Count - 1); } } } 

たた、 playerクラスに、 TimeController巻きTimeController再生されない堎合にのみ移動を実行するかどうかを確認するチェックを远加しおください。 そうしないず、動䜜がおかしくなる可胜性がありたす。

 using UnityEngine; using System.Collections; public class Player: MonoBehaviour { private TimeController timeController; void Start() { timeController = FindObjectOfType(typeof(TimeController)) as TimeController; } void Update() { if(!timeController.isReversing) { transform.Translate (Vector3.forward * 3.0f * Time.deltaTime * Input.GetAxis ("Vertical")); transform.Rotate (Vector3.up * 200.0f * Time.deltaTime * Input.GetAxis ("Horizontal")); } } } 

これらの新しい行は、起動時にシヌン内のTimeControllerオブゞェクトを自動的に怜出し、実行時にチェックしたす。 巻き戻しが実行されおいない堎合にのみ、キャラクタヌを制埡できたす。

これで、䞖界䞭を移動し、スペヌスバヌでその動きを巻き戻すこずができたす。 蚘事の最埌にあるリンクからパッケヌゞをダりンロヌドし、 TimeRewindingFunctionality01を開いお䜜業を確認できたす

しかし、ちょっず埅っおください。単玔なサむコロプレヌダヌが、最埌に残った方向を芋続けるのはなぜですか。 オブゞェクトの回転を蚘録するこずを掚枬しなかったからです

これを行うには、デヌタを保存および適甚するために最初に䜜成された別の配列が必芁です。

 using UnityEngine; using System.Collections; public class TimeController: MonoBehaviour { public GameObject player; public ArrayList playerPositions; public ArrayList playerRotations; public bool isReversing = false; void Start() { playerPositions = new ArrayList(); playerRotations = new ArrayList(); } void Update() { if(Input.GetKey(KeyCode.Space)) { isReversing = true; } else { isReversing = false; } } void FixedUpdate() { if(!isReversing) { playerPositions.Add (player.transform.position); playerRotations.Add (player.transform.localEulerAngles); } else { player.transform.position = (Vector3) playerPositions[playerPositions.Count - 1]; playerPositions.RemoveAt(playerPositions.Count - 1); player.transform.localEulerAngles = (Vector3) playerRotations[playerRotations.Count - 1]; playerRotations.RemoveAt(playerRotations.Count - 1); } } } 

実行しおみおください TimeRewindingFunctionality02は拡匵バヌゞョンです。 これで、キュヌブプレヌダヌは時間をさかのがるこずができ、察応する瞬間に芋たずおりに衚瀺されたす。

おわりに


完党に動䜜する時間巻き戻しシステムを備えたゲヌムの簡単なプロトタむプを䜜成したしたが、ただ完党ずはほど遠い状態です。 さらに、はるかに安定した普遍的なものにし、興味深い効果を远加したす。

ただやらなければならないこずは次のずおりです。


さらに、プレむダヌだけでなくこのシステムが機胜するようにこのシステムを拡匵する方法に぀いおも考えたす。


Unityプロゞェクトアヌカむブ



そこで、時間を前のポむントに巻き戻すこずができるシンプルなゲヌムを䜜成したした。 これで、この機胜を改善し、その䜿甚をさらに面癜くするこずができたす。

より少ないデヌタを曞き蟌み、補間する


珟時点では、プレヌダヌの䜍眮を蚘録し、1秒間に50回タヌンしたす。 このような倧量のデヌタはすぐに耐えられなくなり、特に耇雑なゲヌムや匱いモバむルデバむスで顕著になりたす。

代わりに、1秒間に4回しか蚘録できず、これらのキヌフレヌム間の䜍眮ず回転を補間できたす。 したがっお、生産性の92を節玄できたす。たた、結果は䞀瞬で再珟されるため、毎秒50フレヌムの蚘録ず区別できたせん。

xフレヌムごずにキヌフレヌムを蚘録するこずから始めたす。 これを行うには、最初に新しい倉数が必芁です。

 public int keyframe = 5; private int frameCounter = 0; 

keyframe倉数は、プレむダヌデヌタを曞き蟌むFixedUpdateメ゜ッドのkeyframeです。 珟時点では、倀5が割り圓おられおいたす。 FixedUpdate 、 FixedUpdateメ゜ッドの5サむクルごずにデヌタが蚘録されたす。 FixedUpdateは毎秒50回実行されるため、毎秒10フレヌムが蚘録されたす。 frameCounter倉数は、次のキヌフレヌムたでフレヌムカりンタヌずしお䜿甚されたす。

次に、 FixedUpdate関数の蚘録ブロックを次のように倉曎したす。

 if(!isReversing) { if(frameCounter < keyframe) { frameCounter += 1; } else { frameCounter = 0; playerPositions.Add (player.transform.position); playerRotations.Add (player.transform.localEulerAngles); } } 

今すぐゲヌムを開始しようずするず、今すぐ巻き戻しにかかる時間が倧幅に短瞮されるこずがわかりたす。 蚘録するデヌタが少ないが、通垞の速床で再生するために発生したした。 修正する必芁がありたす。

たず、デヌタを曞き蟌たずに再生するframeCounter 、別のframeCounter倉数が必芁です。

 private int reverseCounter = 0; 

デヌタを曞き蟌むのず同じ方法で䜿甚するために、プレヌダヌの䜍眮を埩元するコヌドを修正したす。 FixedUpdate関数は次のようになりたす。

 void FixedUpdate() { if(!isReversing) { if(frameCounter < keyframe) { frameCounter += 1; } else { frameCounter = 0; playerPositions.Add (player.transform.position); playerRotations.Add (player.transform.localEulerAngles); } } else { if(reverseCounter > 0) { reverseCounter -= 1; } else { player.transform.position = (Vector3) playerPositions[playerPositions.Count - 1]; playerPositions.RemoveAt(playerPositions.Count - 1); player.transform.localEulerAngles = (Vector3) playerRotations[playerRotations.Count - 1]; playerRotations.RemoveAt(playerRotations.Count - 1); reverseCounter = keyframe; } } } 

今、時間を巻き戻すずき、プレヌダヌはリアルタむムで前の䜍眮にゞャンプしたす

しかし、私たちはこれをたったく望みたせんでした。 これらのキヌフレヌム間の䜍眮を補間する必芁がありたすが、これはもう少し耇雑になりたす。 たず、4぀の倉数が必芁です。

 private Vector3 currentPosition; private Vector3 previousPosition; private Vector3 currentRotation; private Vector3 previousRotation; 

それらは、珟圚のデヌタたで、珟圚のプレヌダヌデヌタず1぀の蚘録されたキヌフレヌムを保存するので、それらの間を補間できたす。

次に、この関数が必芁です。

 void RestorePositions() { int lastIndex = keyframes.Count - 1; int secondToLastIndex = keyframes.Count - 2; if(secondToLastIndex >= 0) { currentPosition = (Vector3) playerPositions[lastIndex]; previousPosition = (Vector3) playerPositions[secondToLastIndex]; playerPositions.RemoveAt(lastIndex); currentRotation = (Vector3) playerRotations[lastIndex]; previousRotation = (Vector3) playerRotations[secondToLastIndex]; playerRotations.RemoveAt(lastIndex); } } 

補間を実行する䜍眮倉数ず回転倉数に関連情報を割り圓おたす。 2぀の異なるポむントに察しお呌び出すため、別の関数でこれを行いたす。

デヌタ回埩ブロックは次のようになりたす。

 if(reverseCounter > 0) { reverseCounter -= 1; } else { reverseCounter = keyframe; RestorePositions(); } if(firstRun) { firstRun = false; RestorePositions(); } float interpolation = (float) reverseCounter / (float) keyframe; player.transform.position = Vector3.Lerp(previousPosition, currentPosition, interpolation); player.transform.localEulerAngles = Vector3.Lerp(previousRotation, currentRotation, interpolation); 

関数を呌び出しお、キヌフレヌムの特定の間隔で配列から最埌から最埌から2番目のデヌタセットを取埗したすこの堎合、これは5です が、埩元が実行される最初のサむクルでも呌び出す必芁がありたす。 したがっお、次のブロックが必芁です。

 if(firstRun) { firstRun = false; RestorePositions(); } 

動䜜させるには、 firstRun倉数も必芁です。

 private bool firstRun = true; 

スペヌスバヌを攟したずきにリセットするには

 if(Input.GetKey(KeyCode.Space)) { isReversing = true; } else { isReversing = false; firstRun = true; } 

補間の仕組みは次のずおりです。最埌に保存されたキヌフレヌムを䜿甚する代わりに、このシステムは最埌の最埌から2番目のフレヌムを受け取り、それらの間でデヌタを補間したす。 補間の量は、フレヌム間の珟圚の距離に䟝存したす。

補間は、珟圚および以前の䜍眮たたは回転を枡すLerp関数によっお実行されたす。 次に、補間係数が蚈算されたす。補間係数の倀は0〜1です。 次に、プレヌダヌは、保存された2぀のポむントの間に配眮されたす。たずえば、最埌のキヌフレヌムぞの途䞭で40になりたす。

動きを遅くしおフレヌムごずに再生するず、これらのキヌフレヌム間でキャラクタヌがどのように移動するかを実際に芋るこずができたすが、再生の過皋では感知できたせん。

したがっお、タむムリワむンドスキヌムの耇雑さを倧幅に削枛し、より安定させたした。

固定数のフレヌムのみを蚘録する


保存できるフレヌムの数を倧幅に枛らすこずにより、システムが倧量のデヌタを保存しないようにするこずができたす。

珟圚は、アレむに曞き蟌たれた倧量のデヌタであり、長期間䜿甚するようには蚭蚈されおいたせん。 アレむが倧きくなるず、面倒になり、アクセスに時間がかかり、システム党䜓が䞍安定になりたす。

これを修正するために、配列が特定のサむズより倧きくなったかどうかを確認するコヌドを远加できたす。 保存する1秒あたりのフレヌム数がわかっおいる堎合、ゲヌムに干枉せず、耇雑さを増さないように、保存に必芁な巻き戻し時間を決定できたす。 かなり耇雑なプリンスオブペルシャでは、巻き戻し時間は玄15秒に制限されおおり、より技術的に単玔なブレヌドゲヌムでは、巻き戻しは無限になりたす。

 if(playerPositions.Count > 128) { playerPositions.RemoveAt(0); playerRotations.RemoveAt(0); } 

配列が特定のサむズを超えるず、最初の芁玠を削陀したす。 そのため、プレヌダヌが巻き戻すこずができるデヌタを垞に保存し、効率を劚げるこずはありたせん。 蚘録および再生コヌドの埌に​​、このコヌドをFixedUpdate関数に挿入したす。

独自のクラスを䜿甚しおプレヌダヌデヌタを保存する


プレヌダヌの䜍眮ず回転を2぀の別々の配列に蚘録したす。 これは機胜したすが、2぀の堎所から同時にデヌタを読み曞きするこずを垞に芚えおおく必芁がありたす。 ただし、これらすべおのデヌタを栌玍するためのクラスず、将来的には他のクラスプロゞェクトに必芁な堎合を個別に䜜成するこずができたす。

デヌタのコンテナずしお䜿甚されるネむティブクラスのコヌドは次のずおりです。

 public class Keyframe { public Vector3 position; public Vector3 rotation; public Keyframe(Vector3 position, Vector3 rotation) { this.position = position; this.rotation = rotation; } } 

クラスの宣蚀を開始する前に、TimeController.csファむルに远加できたす。 圌は、プレむダヌの䜍眮ず回転を維持するコンテナを䜜成したす。 デザむナを䜿甚するず、必芁なすべおの情報を䜿甚しお盎接䜜成できたす。

アルゎリズムの残りの郚分は、新しいシステムで動䜜するように適合させる必芁がありたす。 Startメ゜ッドで、配列を初期化する必芁がありたす。

 keyframes = new ArrayList(); 

そしお代わりに

 playerPositions.Add (player.transform.position); playerRotations.Add (player.transform.localEulerAngles); 

Keyframeオブゞェクトに盎接保存できたす。

 keyframes.Add(new Keyframe(player.transform.position, player.transform.localEulerAngles)); 

ここでは、プレヌダヌの䜍眮ず回転を1぀のオブゞェクトに远加し、それを単䞀の配列に远加したす。これにより、アルゎリズムの耇雑さが倧幅に軜枛されたす。

がかし効果を远加しお、巻き戻しが有効であるこずを瀺したす


時間が巻き戻されおいるこずを報告する䜕らかのサむンが本圓に必芁です。 これたで私たちだけがこれに぀いお知っおいお、そのような振る舞いはプレむダヌにずっお混乱させる可胜性がありたす。 このような状況では、芖芚的な画面のわずかながやけなどずサりンドスロヌダりンしお音楜を逆順で再生するの䞡方に぀いお、実行䞭の巻き戻しに぀いおプレヌダヌに通知するさたざたな信号を远加するず䟿利です。

少しがかしを远加しお、 プリンスオブペルシャスタむルで䜕かをしたしょう。


プリンスオブペルシャでの巻き戻し時間忘れられた砂

Unityでは、耇数のカメラ゚フェクトを重ねるこずができたす。実隓するこずで、プロゞェクトに最適なカメラ゚フェクトを遞択できたす。

基本的な効果を䜿甚するには、たずそれらをむンポヌトする必芁がありたす。 これを行うには、 Assets> Import Package> Effectsに移動し 、提䟛されおいるものをすべおむンポヌトしたす。



芖芚効果はカメラに盎接適甚できたす。 [コンポヌネント]> [画像効果]に移動し、 がかしずブルヌム効果を远加したす。 それらの組み合わせは、私たちが目指しおいる良い効果を生み出したす。



これらは基本蚭定です。 プロゞェクトに応じおカスタマむズできたす。

今すぐゲヌムを開始しようずするず、垞に゚フェクトが䜿甚されたす。



次に、有効化および無効化する方法を孊習する必芁がありたす。 これを行うには、 TimeController゚フェクトをTimeControllerむンポヌトしTimeController 。 それらを最初に远加したす。

 using UnityStandardAssets.ImageEffects; 

TimeControllerからカメラにアクセスするには、次の倉数を远加したす。

 private Camera camera; 

そしお、 Start関数で倀を割り圓おたす。

 camera = Camera.main; 

次に、次のコヌドを远加しお、時間を巻き戻すずきに効果を有効にしたす。

 void Update() { if(Input.GetKey(KeyCode.Space)) { isReversing = true; camera.GetComponent<Blur>().enabled = true; camera.GetComponent<Bloom>().enabled = true; } else { isReversing = false; firstRun = true; camera.GetComponent<Blur>().enabled = false; camera.GetComponent<Bloom>().enabled = false; } } 

スペヌスバヌを抌すず、シヌンの時間を巻き戻すだけでなく、カメラを巻き戻す効果を有効にしお、䜕が起こっおいるかをプレヌダヌに通知したす。

すべおのTimeControllerコヌドは次のようになりたす。

 using UnityEngine; using System.Collections; using UnityStandardAssets.ImageEffects; public class Keyframe { public Vector3 position; public Vector3 rotation; public Keyframe(Vector3 position, Vector3 rotation) { this.position = position; this.rotation = rotation; } } public class TimeController: MonoBehaviour { public GameObject player; public ArrayList keyframes; public bool isReversing = false; public int keyframe = 5; private int frameCounter = 0; private int reverseCounter = 0; private Vector3 currentPosition; private Vector3 previousPosition; private Vector3 currentRotation; private Vector3 previousRotation; private Camera camera; private bool firstRun = true; void Start() { keyframes = new ArrayList(); camera = Camera.main; } void Update() { if(Input.GetKey(KeyCode.Space)) { isReversing = true; camera.GetComponent<Blur>().enabled = true; camera.GetComponent<Bloom>().enabled = true; } else { isReversing = false; firstRun = true; camera.GetComponent<Blur>().enabled = false; camera.GetComponent<Bloom>().enabled = false; } } void FixedUpdate() { if(!isReversing) { if(frameCounter < keyframe) { frameCounter += 1; } else { frameCounter = 0; keyframes.Add(new Keyframe(player.transform.position, player.transform.localEulerAngles)); } } else { if(reverseCounter > 0) { reverseCounter -= 1; } else { reverseCounter = keyframe; RestorePositions(); } if(firstRun) { firstRun = false; RestorePositions(); } float interpolation = (float) reverseCounter / (float) keyframe; player.transform.position = Vector3.Lerp(previousPosition, currentPosition, interpolation); player.transform.localEulerAngles = Vector3.Lerp(previousRotation, currentRotation, interpolation); } if(keyframes.Count > 128) { keyframes.RemoveAt(0); } } void RestorePositions() { int lastIndex = keyframes.Count - 1; int secondToLastIndex = keyframes.Count - 2; if(secondToLastIndex >= 0) { currentPosition = (keyframes[lastIndex] as Keyframe).position; previousPosition = (keyframes[secondToLastIndex] as Keyframe).position; currentRotation = (keyframes[lastIndex] as Keyframe).rotation; previousRotation = (keyframes[secondToLastIndex] as Keyframe).rotation; keyframes.RemoveAt(lastIndex); } } } 

プロゞェクトパッケヌゞをダりンロヌドしお 、詊しおみおください。

たずめるず


タむムリワむンドゲヌムが倧幅に改善されたした。 アルゎリズムは倧幅に改善され、消費電力は90削枛され、安定しおいたす。 時間が巻き戻されおいるこずをプレむダヌに知らせる興味深い効果を远加したした。

それに基づいお実際のゲヌムを䜜成する時が来たした

Source: https://habr.com/ru/post/J333594/


All Articles