Unity 5.5、5.6の新機能&Animator Controllerを使わないアニメーション制御ゲーム開発初心者のためのUnity入門(14)(2/3 ページ)

» 2017年03月13日 05時00分 公開
[薬師寺国安PROJECT KySS]

「Animation」の設定

 「woman1-e」の「Animation」の横にある「○に・」アイコンをクリックして表示される「Select AnimationClip」から「Walk」を選択しておく(図8)。

図8 「woman1-e」の「Animation」に「Walk」を指定する

 「Plane」の上空に位置する「woman2-e」の「Animation」は「Idle」を指定する。これはキャラクターが休憩している状態だ。

「スペース」キーで3Dキャラを表示させるスクリプト

 このアプリを実行するためには、最初に「スペース」キーを押して、戦う相手を出現させる必要がある。この処理は、前々回記事で解説した方法を一部利用した形になる。

 まず、Unityメニューの「GameObject」→「Create Empty」と選択する。空の「GameObject」がHierarchy内に追加される。この「GameObject」を選択し、表示されるInspectorから「Add Component」をクリックする。

 「New Script」を選択し「Name」に「AddObject」、「Language」に「C Sharp」を指定して、「Create and Add」をクリックする。Inspector内にスクリプトが表示されるので、マウスでダブルクリックする。Visual Studioのエディターが起動するので、リスト1のコードを記述する。

  1. public Transform myObj;
  2. private GameObject obj2;
  3. void Start () {
  4. obj2 = GameObject.Find("woman2-e");
  5. }
  6. void Update () {
  7. if(Input.GetKey(KeyCode.Space))
  8. {
  9. obj2.SetActive(true);
  10. myObj.transform.position = new Vector3(0, 0.1f, 0);
  11. }
  12. }
リスト1 「スペース」キーで「woman2-e」を表示させる処理(AddObject.cs)

 まず、Transform型のpublicな変数「myObj」を宣言し(1行目)、次に、GameObject型のprivateな変数「obj2」を宣言する(2行目)。「myObj」変数はpublicにしているため、Inspector内のプロパティに表示されるようになる。

 Start関数内でFind関数を使って「woman2-e」にアクセスし、変数「obj2」で参照する(4行目)。Update関数内では、8行目で、「スペース」キーが押されたときにどうするかを記述している。

 9~12行目で、SetActive関数に「true」を指定して、「woman2-e」を表示させている。表示させる位置は「Vector3」で指定した位置になる。「Vector3」はX、Y、Zの値を持つベクトルで、位置情報を表す。この場合は、X=0、Y=0.1、Z=0の位置に「woman2-e」が出現する。

JavaScriptのコード

 JavaScriptのコードも記載しておく、コードの解説はC#と同じだ。JavaScriptで書きたい場合は、連載第5回のコラム「スクリプトエディタの切り替え」を参照されたい。

  1. public var myObj:Transform;
  2. private var obj2:GameObject;
  3. function Start () {
  4. obj2=GameObject.Find("woman2-e");
  5. }
  6. function Update () {
  7. if(Input.GetKey(KeyCode.Space)){
  8. obj2.SetActive(true);
  9. myObj.transform.position=Vector3(0,0.1,0);
  10. }
  11. }
リスト1 「スペース」キーで「woman2-e」を表示させる処理(AddObjectJS.js)

いったんビルドして実行

 では、ビルドして「GameObject」のInspectorを表示させてみよう。

 図9のように、「My Obj」というプロパティが追加されている。横にある「○に・」アイコンをクリックして、「Select Transform」から「woman2-e」を選択する(図9)。

図9 「My Obj」プロパティに「woman2-e」を指定する

 「woman1-e」のAnimationには「Walk」と指定しているので、実行すると、同じ位置で一瞬、歩行してすぐ停止する(動画1)。

動画1 一瞬歩行して停止する

 これでは具合が悪いので、矢印キーで左右に方向転換し、ずっと歩き続けるスクリプトを書く必要がある。

 また、これまでの連載で作ってきたサンプルはAnimator Controllerを使っていたので、衝突時にどのようなアニメーションをさせるかのスクリプトを書く必要がなかった。しかし、Animator Controllerを使わない場合はそうはいかない。細かいスクリプトの記述が必要となる。

スクリプトで3Dキャラにどんなアニメーションをさせるかを決める

 「woman1-e」を選択して表示されるInspectorから、今までの手順に従って「CharacterAction」というスクリプトを追加して、リスト2のコードを記述する。

  1. private GameObject obj1;
  2. private GameObject obj2;
  3. private bool flag;
  4. void Start()
  5. {
  6. flag = false;
  7. obj1 = GameObject.Find("woman1-e");
  8. obj2 = GameObject.Find("woman2-e");
  9. }
  10. void Update()
  11. {
  12. if (flag == false)
  13. {
  14. obj1.GetComponent<Animation>().Play("Walk");
  15. }
  16. if (Input.GetKey("down"))
  17. {
  18. obj1.transform.position += transform.forward * 0.01f;
  19. }
  20. if (Input.GetKey("left"))
  21. {
  22. obj1.transform.Rotate(0, 2, 0);
  23. }
  24. if (Input.GetKey("right"))
  25. {
  26. obj1.transform.Rotate(0, -2, 0);
  27. }
  28. }
  29. private IEnumerator OnCollisionEnter(Collision col)
  30. {
  31. if (col.gameObject.tag == "Woman2")
  32. {
  33. flag = true;
  34. obj1.GetComponent<Animation>().Play("Skill");
  35. obj2.GetComponent<Animation>().Play("Skill1");
  36. yield return new WaitForSeconds(3);
  37. obj1.GetComponent<Animation>().Play("Skill_move");
  38. yield return new WaitForSeconds(2);
  39. obj2.GetComponent<Animation>().Play("Dead2");
  40. yield return new WaitForSeconds(2);
  41. obj2.GetComponent<Animation>().Stop();
  42. yield return new WaitForSeconds(1);
  43. obj2.SetActive(false);
  44. yield return new WaitForSeconds(1);
  45. obj1.GetComponent<Animation>().Play("Walk");
  46. }
  47. }
リスト2 矢印キーでキャラクターが歩き、別なキャラクターと接触すると決闘をする処理(CharacterAction.cs)

 まず、「obj1」と「obj2」というGameObject変数を宣言する(1・2行目)。また「bool」型の変数「flag」も宣言しておく(3行目)。

 5~10行目のStart関数内では、変数「flag」を「false」で初期化しておく(7行目)。また、Find関数で「woman1-e」と「woman2-e」にアクセスして、変数「obj1」と「obj2」で参照しておく(8・9行目)。

 Update関数内では以下の処理を行う。

アニメーションをスクリプトから呼び出すAnimation.Play関数

 変数「flag」が「false」であった場合は、「GetComponent<Animation>().Play」で、図8で設定した「Walk」アニメーションを実行する(14~17行目)。これは女剣士が歩いているアニメーションだ。

Animator Controllerを使わないキーボード操作時の処理

 GetKey関数内では、キーボードの「down(↓)」「left(←)」「right(→)」キーが押された場合のそれぞれの処理を記述している。

 19~22行目では、「down(↓)」キーが押された場合の処理をしている。前方向に進ませる、スピードは「0.01」としている。この値を大きくすると歩く速さというより進む速さが大きくなる。あまり大きくし過ぎると、歩くテンポと地面の関係が不自然になるので注意してほしい。

 次は「left(←)」キーが押された場合の処理だ。「Rotate」を使って「Y」軸の値を「2」に指定している(24~27行目)。

 「right(→)」キーが押された場合は、「Rotate」を使って「Y」軸の値を「-2」と指定している。「left」キーが押された場合とは反対方向に向く(29~32行目)。

 なおAnimator Controllerを使わない場合は、スムーズに動かすためには、「down」キーを押しながら、同時に「right」や「left」キーを押す必要がある。単独で「right」や「left」キーを押すと、その場で回転だけをする動作になる。

「Character Controller」を使わない場合の接触時の処理はOnCollisionEnter関数

 次は、女剣士同志が接触した場合の処理で、OnCollisionEnter関数内に処理を書く(35行目)。前回も触れたが、「Character Controller」を使わない衝突判定にはOnCollisionEnter関数を使うのだ。

 引数になっているCollisionのオブジェクト「col」には接触情報が入っている(35行目)。

コルーチンとIEnumerator

 また、OnCollisionEnter関数の戻り値は、「IEnumerator」型となっている(35行目)。

 これは「コルーチン」から呼び出す場合に記述する方法だ。「yield return new WaitForSeconds(3)」といった処理が、IEnumeratorの中でしか使用できないから使っている(42、45、48、51、55行目)。

 以下は、ゲームオブジェクトの「tag」が「Woman2」であった場合、つまり「woman2-e」と接触した場合(37行目)の処理だ。

 「flag」を「true」で初期化し、「woman1-e」のアニメーションを「Skill」とし、「woman2-e」のアニメーションを「Skill1」とする(39~41行目)。

 「Skill1」のアニメーションを、3秒後に「Skill1_move」に変化させ(42~44行目)、2秒後に「woman2-e」のアニメーションを「Dead2」として、「死ぬ」アニメーションを実行する(45~47行目)。その2秒後にアニメーションを停止する(48~50行目)。

 「woman1-e」の接触する相手が「Woman2」ではなかった場合は、「woman1-e」の女剣士は歩き続けるはずだったのだが、コルーチンのOnCollisionEnter関数からは、Update関数が実行できず、そこで終わってしまう。「woman2-e」が死んで消えた後、「woman1-e」は一瞬歩き始めるが、すぐに停止する。この点はご了承願いたい。

 ただし、再度「スペース」キーを押すと女剣士が現れ、キーボードの「↓」キーを押すと、再度決闘が始まる。これは、永遠に繰り返すことができるが、歩き続けることはできない。歩き続ける処理については、各自が考えてみてほしい。

JavaScriptのコード

 JavaScriptのコードも記載しておく、コードの解説はほとんどC#と同じだが、JavaScriptコルーチンとIEnumeratorは使っていない。

  1. private var obj1:GameObject;
  2. private var obj2:GameObject;
  3. private var flag:boolean;
  4. function Start () {
  5. flag=false;
  6. obj1=GameObject.Find("woman1-e");
  7. obj2=GameObject.Find("woman2-e");
  8. }
  9. function Update () {
  10. if(flag==false){
  11. obj1.GetComponent(Animation).Play("Walk");
  12. }
  13. if (Input.GetKey("down")) {
  14. obj1.transform.position += transform.forward * 0.01f;
  15. }
  16. if (Input.GetKey("left")) {
  17. obj1.transform.Rotate(0, 2, 0);
  18. }
  19. if (Input.GetKey ("right")) {
  20. obj1.transform.Rotate(0, -2, 0);
  21. }
  22. }
  23. function OnCollisionEnter(col:Collision){
  24. if(col.gameObject.tag=="Woman2"){
  25. flag=true;
  26. obj1.GetComponent(Animation).Play("Skill");
  27. obj2.GetComponent(Animation).Play("Skill1");
  28. yield WaitForSeconds(3);
  29. obj1.GetComponent(Animation).Play("Skill1_move");
  30. yield WaitForSeconds(2);
  31. obj2.GetComponent(Animation).Play("Dead2");
  32. yield WaitForSeconds(1);
  33. obj2.GetComponent(Animation).Stop();
  34. yield WaitForSeconds(1);
  35. obj2.SetActive(false);
  36. flag=false;
  37. }else{
  38. flag=false;
  39. obj1.GetComponent(Animation).Play("Walk");
  40. }
  41. }
リスト2 矢印キーでキャラクターが歩き、別なキャラクターと接触すると決闘をする処理(CharacterActionJS.js)

Copyright © ITmedia, Inc. All Rights Reserved.

スポンサーからのお知らせPR

HTML5�ス�ス�ス�ス髯句ケ「�ス�スX 鬯ョ�ォ�ス�ェ髯区サゑスソ�ス�ス�ス�ス�コ髣包スオ隴∵コキ�ク�キ�ス�ケ隴趣ス「�ス�ス�ス�ウ鬩幢ス「�ス�ァ�ス�ス�ス�ュ鬩幢ス「隴趣ス「�ス�ス�ス�ウ鬩幢ス「�ス�ァ�ス�ス�ス�ー

鬮ォ�エ陝キ�「�ス�ス�ス�ャ鬮ォ�エ鬲�シ夲スス�ス�ス�・鬮ォ�エ陝カ�キ�ス�」�ス�ッ髣厄スォ�ス�」

注目のテーマ

4AI by @IT - AIを作り、動かし、守り、生かす
Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。