キャラクターのステータスを操作します。 統一実験

Unityでゲームを開発しているときに、面白いタスクに出くわしました。キャラクターにネガティブまたはポジティブな効果をもたらす拡張可能なアクション時間を作成する方法です。



要するに、弱体化、ゲイン、速度増加、速度減少など、特定の効果を適用できるキャラクターがいます。 特定の効果の効果についてプレイヤーに通知するために、ゲームはステータスラインを提供します。



この行の最初のバージョンには、すべてのステータスの暗いアイコンが含まれており、エフェクトが発生すると、目的のライトが点灯します。



画像



各ステータスにはコルチンが含まれていたため、一定時間後に効果がキャンセルされました。

この決定にはかなり重要なマイナスがあります。 ゲーム内の特定のイベントの結果として、以前の同様の効果の持続時間よりも短い時間後に同じ効果がキャラクターに適用される場合、イベントの2つのバージョンが存在する可能性があります。



  1. かなり間違っています:2番目のコルーチンが最初のコルーチンと並行して起動されます。 最初のものが完了すると、元の値に戻ります。つまり、2番目のコルーチンが作業を完了する前に効果が削除されます。



    画像

  2. また間違っていますが、場合によっては受け入れられます。最初のコルーチンをキャンセルし、2番目のコルーチンを実行します。 この場合、効果の持続時間は、コルーチンがキャンセルされるまでの最初の効果の持続時間+ 2番目のコルーチンの持続時間に等しくなります。



    画像



エフェクトの期間を延長する必要があるため、どちらの方法もタスクに受け入れられません。そのため、エフェクトが適用される回数に関係なく、各エフェクトの期間の合計を取得します。



キャラクターがスパイクを踏んだ場合、彼の足は条件付きで損傷を受け、同じ速度で動き続けることができません。 速度が5秒減少するとします。 3秒後にキャラクターが他のスパイクを踏んだ場合、速度はさらに5秒低下します。 つまり、3秒が経過し、新しいスパイクから2 + 5秒が残りました。 効果の持続時間は、2番目のスパイクの攻撃の瞬間からさらに7秒間続きます(合計10)。



そして、コルーチンの助けを借りても、コルーチンを新しいコルーチンに追加するためにコルーチンが完了するまでの残り時間を見つけることは不可能なので、問題の解決策は見つかりませんでした。



この問題の解決策は、辞書を使用することです。 Listに対する利点は、辞書にキーと値があることです。つまり、キーで任意の値にアクセスできます。 さらに、このソリューションを使用すると、行の永続的なステータスアイコンを削除し、必要に応じて必要なアイコンを含めて、行の位置に発生順に設定できます。



Dictionary<string, float> statusTime = new Dictionary<string, float>();
      
      





キューは先入れ先出しの原則に従って機能するため、この場合の辞書はキューを使用するよりも有利ですが、効果の持続時間は異なるため、削除する必要があるステータスはキューの最初ではない可能性があります。



このために、3つのメソッドを追加しました。



Addstatus



そのようなステータスが辞書にすでに存在する場合、目的のステータスを辞書に追加してから、期間を追加します。 ステータスがない場合は、終了時間を計算して辞書に追加します。



 private void AddStatus(string status, float duration) { if (statusTime.ContainsKey(status)) { statusTime[status] += duration; } else { float endTime = Time.timeSinceLevelLoad + duration; statusTime.Add(status, endTime); } }
      
      





RemoveStatus



辞書からステータスを削除し、元の値を復元します。



 private void RemoveStatus(string status) { statusTime.Remove(status); RestoreStats(status); }
      
      





チェックステータス



ディクショナリにステータスがある場合、その時間が経過したかどうかを確認します。



有効期限が切れている場合は、辞書からステータスを削除します。 ループ内の辞書を変更すると、辞書の値を同期することができなくなるため、ここで辞書のキーを通常のリストにスローします。



 private void CheckStatuses() { if (statusTime.Count > 0) { float currTime = Time.timeSinceLevelLoad; List<string> statuses = new List<string>(statusTime.Keys);  foreach (string stat in statuses) { if (currTime > statusTime[stat]) { RemoveStatus(stat); } } } }
      
      





さらに、明らかに、これは効果の延長可能な期間です。 つまり、問題は解決されます。

しかし、かなり重要なマイナスがここにあります。 ステータスの確認は、「フレームごとに更新」で実行されます。 私のゲームには最大4人のプレイヤーがいます。つまり、このメソッドはフレームごとに4回並行して実行されます。 4文字では、これは重要ではないと思いますが、より多くの文字では、これがパフォーマンスの問題を引き起こす可能性があると確信しています。 また、ディクショナリ内の要素をチェックすることでメソッドが保護され、空のディクショナリでは負荷が減少することに注意する必要があります。



将来を見据えて(このゲームではまだ完全に霧がかかっています)、オンラインモードでのこの決定にも自信があります。プレーヤーのステータスのチェックは、インスタンス化されたすべてのプレーヤーではなく、現在のローカルプレーヤーに対してのみ行われるからです。



All Articles