Unityに関連する記事です

 ここからは空中床以外のゲームオブジェクトを作成して、ゲーム内容にバリエーションを持たせて行きます。

手順14 −障害物の設置・移動−
23.障害物用の敵を設置する
24.スクリプトを使って、敵を上下に移動させる

<実行動画 上下移動しながら画面左側へ移動する>
https://gyazo.com/fe32fe621b42c0bc0e9eacfd770fda7f



 新しく学習する内容は以下になります。

・DOTweenの機能と実装例  DOMoveYメソッド、SetEaseメソッド、SetLoopsメソッド、SetLink メソッド−



23.障害物用の敵を設置する

設計


 空中床以外のゲームオブジェクトを作成して、ゲーム内に登場させましょう。
最初にインポートしたアセットの中には色々な画像のデータがありますので、まずは最初に敵役のゲームオブジェクトを作成します。


敵キャラと敵用のアニメーションクリップを作成する


 キャラのアニメーションクリップを作成したときの手順と同じように、複数の画像をまとめて選択して、ヒエラルキーにドラッグアンドドロップします。
こうすることで常にアニメーションしている敵を作成することが出来ます。


ファイルの場所 ファイルの場所 Assets/Sunnyland/artwork/Sprites/Enemies/eagle/eagle-attack-1.png から eagle-attack-4.png までの4ファイル



選択時のインスペクター画像



 選択したファイルをそのままヒエラルキーにドラッグアンドドロップします。
先ほどと同じように、複数の画像をまとめて設置したため、画像をアニメーションクリップとして保存するための Create New Animation ウインドウが開きます。


Create New Animation ウインドウ



 ファイル名を eagle.anim に変更して保存を選択してください。

 ヒエラルキーに eagle-attack-1 ゲームオブジェクトが作成されます。


ヒエラルキー画像



SceneビューとGameビュー画像


ゲームを実行して動作を確認する


 作成されたゲームオブジェクトにはアニメーションクリップが設定されています。ゲームを実行して、アニメーションが再生されるか確認します。


<実行動画 敵がアニメーションするか確認する>
https://gyazo.com/992d3a384c89ac0ecf59a9f5703f64e4


eagle-attack-1 ゲームオブジェクトの名前を Eagle に変更する


 名前を Eagle に変更してください。


ヒエラルキー画像



Eagle ゲームオブジェクトの設定を行う


 ゲーム画面やキャラに比べて Eagle ゲームオブジェクトが小さいため、Transform コンポーネントの Scale の値をすべて (2.5, 2.5, 2.5) に変更してください。
SpriteRenderer コンポーネント と Animator コンポーネントは作成と同時にアタッチされていますが、こちらは変更箇所はありません。


インスペクター画像



SceneビューとGameビュー画像(Scale を2.5 に変更後)
https://gyazo.com/a0ed52f03386edb82416677e2bb66220



 新しくコンポーネントを2つ追加します。
インスペクターの一番下にある Add Compnent ボタンを押して、CapsuleCollider2D コンポーネントと Rigidbody2D コンポーネントを追加します。


 CapsuleCollider2D コンポーネントの Edit Collider ボタンを押して、Sceneビューで画像に見合った大きさのコライダーに調整してください。


インスペクター画像◆CapsuleCollider2D コンポーネント



Sceneビューのコライダー編集画像



 Rigidbody2D コンポーネントの BodyType プロパティを Kinematic に変更してください。
また、Constraints プロパティの Freeze Rotation の Z にチェックをいれてください。

 この設定については、ご自分で調べてみてください。


インスペクター画像 Rigidbody2D コンポーネント



 以上で設定は終了です。


Eagle ゲームオブジェクトに MoveObject スクリプトをアタッチして設定する


 ヒエラルキーの Eagle ゲームオブジェクトに MoveObject スクリプトをドラッグアンドドロップしてアタッチします。
MoveSpeed 変数の値を 0.01 に設定してください。この値は空中床のゲームオブジェクトと同じ値にしていますが、自由に調整してください。


Eagle ゲームオブジェクト インスペクター画像



ゲームを実行して動作を確認する


 MoveSpeed を設定しましたので、ゲームを実行してみましょう。
空中床のゲームオブジェクトと同じ値を設定していますので、画面の左側に向かって移動をすれば成功です。


<実行動画 敵が画面の左側に移動する>
https://gyazo.com/28f5d23cae21a535e1803d373a02b855


24.スクリプトを使って、敵を上下に移動させる

設計


 敵役のゲームオブジェクトは鳥の画像です。そのままの位置で浮遊しているより、実際の鳥のように羽ばたいている様子を再現した方が
画像にも合っていますし、動きがあることによってゲーム的にも面白くなります。

 画面内の移動処理は完成していますので、新しくスクリプトを作成して、上下方向への移動も加えましょう。移動させる処理も色々な方法がありますが、
今回はアセットとしてインポートした DOTween の機能を利用して移動の処理を実装します。


VerticalFloatingObject スクリプトを作成する


 宣言フィールドでは2つの変数を宣言します。この変数を利用して、上下の移動にかかる時間と、どの位の上下幅を移動できるかの範囲を設定します。

 StartメソッドではDOTweenによる座標の変更処理を行い、移動の処理として実装しています。
今回のケースでは、DOTweenによる処理を無限ループさせて、ゲームオブジェクトがある限り敵を上下させるロジックです。
DOTween の処理は非同期処理と呼ばれる処理であり、ゲームオブジェクトの挙動とは紐づいていません。
そのため、適切なタイミングで DOTween による無限ループを解除しないと、ゲームオブジェクトがない状態にもかかわらず
ループさせる処理のみが残ってエラーを引き起こす原因になります。

 実装例を2つ提示しておきます。DOTween によるループ処理の終了方法が異なるだけで敵の挙動自体に変化はありません。



 最初の実装例では、DOTween の処理を変数に代入しておいて、ゲームオブジェクトが破棄されるタイミングで DOTween の処理を破棄する処理を実行するパターンです。

 OnDestroy メソッドは Unity の MonoBehaviour クラスの持つ機能の1つです。
このメソッドはゲームオブジェクトが破壊されたときに自動的に呼び出される、コールバックという種類のメソッドになります。
このメソッドの中でループ処理を行っている DOTween の処理を破棄しています。

 一度命令を出して動き出した DOTween の処理は、後から修正(一時停止したり、終了したり)出来ません。
修正を行うためには、実行のタイミングで Tween 型、あるいは Tweener 型の変数に代入しておき、
この変数を使って DOTween へ再度命令を出すことで対応できます。


VerticalFloatingObject.cs 

 <= クリックすると開きます




 もう1つの実装例の方は、DOTween の終了するタイミングをゲームオブジェクトの破棄のタイミングに紐付けしておきます。
この方法の場合は、DOTween の実行命令の際に SetLink メソッドを追加して対応しています。
こちらの場合にはゲームオブジェクトの破棄と同時に DOTween の処理自体も停止してくれるようになります。
そのため、動きだした DOTween に対して後から処理を行う必要がないため、変数への代入は不要になっています。


VerticalFloatingObject.cs 

 <= クリックすると開きます



<DOTweenの機能と実装例  DOMoveYメソッド、SetEaseメソッド、SetLoopsメソッド、SetLink メソッド、Kill メソッド−>


 敵の移動処理に対しては、DOTweenによる補間処理を実装しています。
DOTween の処理はコルーチンの処理と同じで非同期処理と呼ばれる処理です。
通常の処理は、1つの処理が終了してから次の処理に移行しますが、
非同期処理の場合、その処理の終了をメインスレッドは待ちません。そのため、実行だけして、次の処理に移行します。

 非同期処理のイメージとしては、マルチタスクな処理の実現を可能にすることであり、
メインの処理とは異なる場所で、その処理だけが指定された時間の間だけ処理を行い、自動的に処理を終了します。

 カップラーメンをイメージするとわかりやすいかもしれません。
お湯を入れておけば、何分かしたら調理が終わって食べれるようになっています。
その間は、その場で待っている必要はなく、他の作業をしていても、時間が経過すれば調理は自動的に終了します。
この「お湯を入れる」部分が非同期処理の実行命令であり、一度お湯を注げば、あとは調理の方で自動的に計測していますので
自分がその場にして時間を計測していなくても調理は終了します。

 この処理をゲーム内で同期的に行ってしまうと、その場でラーメンが出来上がるまで、他の処理を停止して待っている必要が生まれます。
それは非効率であるため、メインの処理は止めずに、お湯だけ注いだらあとは関知せず、
ラーメンに調理が終了するまで処理を委任してしまうようにしています。

 バルーンの生成処理もコルーチンを利用した非同期処理です。
バルーンの生成を行っている際、ゲームは停止していますでしょうか?
動作を思い出してみてください。

 非同期処理によってバルーンの生成を行っているので、キャラは自由に移動できていると思います。
この処理も、バルーンの生成部分の命令だけ行い、あとはバルーンを生成するメソッド内の処理が独自のタイミングで動ているため、
ゲームの処理自体を阻害せずにマルチタスク的な処理が実装出来ています。



 スクリプト内でDOTweenの処理を実装するためには、最初に using による宣言が必要になります。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;                      //  <= 追加します


 このスクリプト内では5つのメソッドを利用していますので、順番に説明していきます。

  tweener = transform.DOMoveY(transform.position.y - moveRange, moveTime).SetEase(Ease.Linear).SetLoops(-1, LoopType.Yoyo);


  transform.DOMoveY(transform.position.y - moveRange, moveTime).SetEase(Ease.Linear).SetLoops(-1, LoopType.Yoyo).SetLink(gameObject);

 これらは複数のメソッドがつながって1つの処理を形成しています。その場合、ピリオドの位置で改行しておくことで処理が読みやすくなります。
改行する場合には、インデントを1段落分ずらして記載します。1つの処理内に複数の改行を行う場合には、2つ目以降は同じインデントに揃えます。

 // DOTween による命令を実行し、SetLink メソッドを利用してゲームオブジェクトの破棄に Tween の終了を紐付けする
  transform.DOMoveY(transform.position.y - moveRange, moveTime)
   .SetEase(Ease.Linear)
   .SetLoops(-1, LoopType.Yoyo)
   .SetLink(gameObject);

 このように記述することで、1行分の実行命令は、合計で4つメソッドがつながって構成されていることをわかりやすくできます。


1.DOMoveY(float endValue, float duration)

 DOMoveYメソッドは、ゲームオブジェクトの位置のうち、Y軸(transform.position.y)だけを指定して移動させる処理です。
移動時に補間処理を行うことでアニメーションしているように見せてくれます。
DOTween には主(メイン)となる実行命令を持つメソッドがあり、それらはすべて DO でメソッド名が始まる規則を持っています。

 DOMoveY メソッドも DO でメソッド名が始まっていますので、主となるメソッドの1つです。

  transform.DOMoveY(transform.position.y - moveRange, moveTime)

 このメソッドは処理を行いたいゲームオブジェクトの、transfromに対して実行します。ここではこのスクリプトがアタッチされているゲームオブジェクトを移動させる命令を行いたいので
このゲームオブジェクトのTransform コンポーネントが代入されている transform 変数に対して処理を行うようにしています。

 transform.DOMoveY()の第1引数はfloat型で、移動させる位置を指定します。
今回はゲーム画面内の上下に移動したいので transform.position.y - moveRange を指定しています。
これは、現在の transform.position.y の値から、 moveRange 変数の値を引いた計算結果の値を移動させる位置として指定しています。

 第2引数はfloat型で、移動する際にかかる時間を指定します。今回は moveTime 変数を指定しているので、この変数の値 秒かけて
このスクリプトがアタッチされているゲームオブジェクトのYの位置を transform.position.y - moveRange の位置まで移動をさせる、という命令になります。


2.SetEase()
2〜4までに説明している各メソッドは、DOTween の主となる実行メソッドに付随して記載できるメソッドです。
不随できるメソッドは Set でメソッド名が始める規則を持っています。

 SetEaseメソッドは、DOTweenの DO〜 で始まる主メソッドに付随する処理です。

  transform.DOMoveY(transform.position.y - moveRange, moveTime)
   .SetEase(Ease.Linear)

 このようにDOTweenではDOTweenのメソッド同士を1つの処理の塊として続けて処理を行うことができます。
処理を続ける場合には、前のメソッドの後にピリオド(ドット)を書くことで、次のメソッドを書くことが可能です。こういった処理をメソッドチェーンといいます。

 SetEaseメソッドではEaseというアニメーションさせる際のパターンを変更することができます。Easeはenum型で設定されており、Ease.タイプ の書式で記述します。
非常に多くの種類があります。今回は最も一般的は Ease.Linear を使用しています。Linear を指定すると等速のアニメーション(動き始めから終わるまで同じ速度で動く)が実装されます。
 

3.SetLoops(int loops, LoopType loopType)

 SetLoopsメソッドは、DOTweenの DO〜 で始まる主メソッドに付随して記述できるメソッドです。この命令単体で実行することはできません。

  transform.DOMoveY(transform.position.y - moveRange, moveTime)
   .SetEase(Ease.Linear)
   .SetLoops(-1, LoopType.Yoyo)

 一緒に命令をしている主となるメソッドに対してループ処理を付与することが出来ます。
今回の処理では、transform.DOMoveYメソッドに対して、ループ処理を行っています。(SetEaseメソッドもSetLoopsメソッドと同じで単体では動かないメソッドです)

 第1引数はループ処理を行う回数です。int型で設定します。今回のように -1 を指定すると、それは無限ループになります。(ループが終了しません)
このような場合は明示的に処理を停止させないと無限にループを繰り返します。

 第2引数ではループさせるタイプをLoopTypeというenum型から選択します。LoopType.Yoyo の場合は、A => B , B => A という形式でループを繰り返します。(ヨーヨーと同じ動きです)
他にもLoopTypeがありますので調べてみてください。この処理によって、最初は下方向へ移動し、その後、元の位置に戻る処理が行われます。それを無限にループします。

 説明の冒頭にも書いたように、DOTween の処理は指定された時間だけ処理が動き、その時間経過後には自動的に終了します。
ただし、無限ループの場合、処理を終了する時間が明記されていませんので、DOTween によって動いているゲームオブジェクトが破棄されても DOTween の処理は自動的には終了しません。そのため、バグの温床になりやすく、警告が発生します。


4.SetLink()

 SetLink メソッドは、DOTweenの DO〜 で始まる主メソッドに付随できるメソッドです。この命令単体で実行することはできません。
SetLink メソッドを付与することで一緒に命令している DOTween の終了するタイミングをゲームオブジェクトの生存期間(破棄のタイミング)に紐づけて、
ゲームオブジェクトの破棄と同時に DOTween の処理を終了することができます。

 DOTween の処理は非同期処理と呼ばれる種類のものであり、一度処理が実行されると、その処理が正常に終了するまではキャンセルできません。
DOTween を実行したスクリプトがアタッチされているゲームオブジェクトが破棄されると、DOTween の処理が途中であった場合、処理だけが残り続けてしまう可能性があります
 
 そうなった場合、DOTween 側から Console ビューに対して、警告の形で通知されます。
そういったケースが想定される場合、SetLink メソッドを利用して、ゲームオブジェクトが破棄されると同時に、DOTween の処理も終了するようにしておく必要があります。

  transform.DOMoveY(transform.position.y - moveRange, moveTime)
   .SetEase(Ease.Linear)
   .SetLoops(-1, LoopType.Yoyo)
   .SetLink(gameObject);

 SetLoops メソッドと一緒に利用するケースが多いです。
特にループの回数が無制限の場合には、必ず SetLink メソッドを利用してゲームオブジェクトの破棄のタイミングと紐づけて利用します。
そうしておかないと、ゲームオブジェクトが破棄されたあとも、DOTween の処理がプログラムの内部では無制限に動作しつづけてしまうことになり、不具合の原因となります。

 DOTween の終了のタイミングを紐づけるゲームオブジェクトは、SetLink メソッドの引数に指定して設定を行います。
GameObject 型であれば指定できますので、スクリプトをアタッチしているゲームオブジェクト以外でも設定できます。

  SetLink(gameObject);    // スクリプトをアタッチしているゲームオブジェクトに紐づける

  SetLink(enemy.gameObject); // enemy 変数のゲームオブジェクトに紐づける

 繰り返しになりますが、SetLoops メソッドを実行した場合、そのループの回数が無制限になっている場合には SetLink メソッドを利用することで
無限ループになっている DOTween の処理を適切なタイミングで終了することが出来ます。



 なお、DOTween の Set〜 で始まるメソッドを記述する順番は任意です。どの Set〜 から書かないと動作しない、というルールはありません。
そのため、下記のような順番で記述して同様に動作します。

<現在の書式>
  transform.DOMoveY(transform.position.y - moveRange, moveTime)
   .SetEase(Ease.Linear)
   .SetLoops(-1, LoopType.Yoyo)
   .SetLink(gameObject);

<Set〜 メソッドの順番を変えた場合>
  transform.DOMoveY(transform.position.y - moveRange, moveTime)
      .SetLink(gameObject)
   .SetEase(Ease.Linear)
   .SetLoops(-1, LoopType.Yoyo);
   

<Set〜 メソッドの順番を変えた場合>
  transform.DOMoveY(transform.position.y - moveRange, moveTime)
      .SetLoops(-1, LoopType.Yoyo)
   .SetEase(Ease.Linear)
   .SetLink(gameObject);

 ただし、多くの場合、主メソッドの後には SetEase メソッドを記述するケースが多いです。
また SetLoops メソッドと SetLink メソッドは一緒に記述することが多いですが、その場合はどちらから記述しても問題ありません。


5.Tween.Kill()

 Tween 型、あるいは Tweener 型に代入している DOTween の処理を終了するメソッドです。

 基本的に DOTween の処理は指定した時間と同時に自動的に終了します。
ただし、処理の途中でゲームオブジェクトが破棄されてしまったり、SetLoops メソッドを利用してループをしている最中にゲームオブジェクトが破棄されてしまった場合、
その DOTween は正常に動作を終了していないため、破棄されているゲームオブジェクトに対して命令をおこなおうとします。

 それを防ぐため、上記のようなケースが想定される DOTween の処理については、適切なタイミングで Kill メソッドを利用して
処理を終了させておく必要があります。

 多くのプログラミングでは、処理の最初と最後をしっかりと考えて記述しておく必要があります。


Eagle ゲームオブジェクトに VerticalFloatingObject をアタッチして設定を行う


 スクリプトを作成したらセーブを行い、ヒエラルキーの Eagle ゲームオブジェクトに VerticalFloatingObject スクリプトをドラッグアンドドロップしてアタッチします。
Eagle ゲームオブジェクトを選択して、 VerticalFloatingObject スクリプトのインスペクターを確認します。public 修飾子で宣言した変数が2つ表示されていますので、値を設定します。


Eagle ゲームオブジェクト インスペクター画像



 moveTime 変数は、DOTween の処理に利用している変数で、この変数の値の時間をかけて、上下の移動を行います。
初期値は 0 になっていますので 2 を設定してください。こうすることにより、現在の位置から移動を行い、最後に現在の位置に戻るまで 2 秒かけて移動を行うようになります。

 moveRange 変数も DOTween の処理に利用している変数で、この変数の値が上下の移動の幅になります。
初期値は 0 になっていますので 2 に設定してください。現在の位置から下方向へ 2.0 移動します。

 moveTime 変数の値が大きいほど、1回辺りの上下の移動にかかる時間が長くなり、moveRange 変数の値が大きいほど、1回の移動の距離が長くなります。
実際に動く様子を見ながら調整を行いましょう。


設定後のインスペクター画像



ゲームを実行して動作を確認する


 設定が完了しましたので、ゲームを実行して確認します。

 ゲームがスタートすると、Eagle ゲームが上下方向に移動しながら、画面の左側へと移動をするようになります。
MoveObject スクリプトがアタッチされていますので、ゲーム画面から消えて少しすると自動的に破棄されます。


<実行動画 上下移動しながら画面左側へ移動する>
https://gyazo.com/fe32fe621b42c0bc0e9eacfd770fda7f


<実行動画 ゲーム画面から消えたら破棄される>
https://gyazo.com/c35bc017174d3d4652f1baf6c4073558


 またキャラとEagle ゲームにはコライダーがアタッチされていますので、コライダーとコライダーが接触してオブジェクトを通過することが出来ないはずです。
(床と同じような状態)


<実行動画 コライダー同士で接触する>
https://gyazo.com/03ee1f4de9a3b8d8a9ce21adcb45c224


 以上でこの手順は終了です。

 次は 手順15 −障害物とキャラ・バルーンの接触処理の実装− です。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



プログラムの基礎学習

コード練習

技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

3Dトップビューアクション(白猫風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます