ふらふら。なう

ふらふら。なう

渋谷で働くサーバーサイドエンジニアのふらふらメモ

Unity初心者がVRアプリ作ってみた話 ④「プレイヤーと敵の作成」

UnityでVRアプリ作ってみた連載4回目。

今日はゲームの核となるプレイヤーと敵の作成に入ります。

 

今回からC#でコード書いていきます!

 

 

 VRアプリのプレイヤー作成

  

 

今回は、ゲームの中心となるプレイヤーと敵の作成をしていきます。

・プレイヤーと敵の作成

・プレイヤーにDive Camera設定

・プレイヤーのアニメーション設定

・敵のアニメーション設定

に関して、見ていきましょう!

 

プレイヤーと敵の作成

 まずは、プレイヤーと敵を作成していきます。

 当初は、Asset Storeから人型のものをimportして使おうと思っていたのですが、剣道のAssetは存在していないみたいだったので、やむなく自分でプレイヤーを作ることにしました。

 

プレイヤーと敵のつくり方は、会場の作り方と同じです。CubeやCylinderを使って、サイズや位置や回転を調整し、作成していきます。

f:id:furafura-nau:20170401161152p:plain

 

今回は、プレイヤーと敵は同じものを180度回転させた関係性にあるので、Playerを複製して、InspectorのRotationでY軸の回転を180にします。 

f:id:furafura-nau:20170401161716p:plain

 

するといい感じに敵キャラも作成することが出来ました。自分と敵の区別をつけられるように、敵キャラの柄の色を変えておきます。

 

 

プレイヤーにDive Camera設定

  次に、プレイヤーにDive Cameraを設定していきます。これからの作業をすることで、スマホを傾けるとカメラが傾くようにできます。

 

Durovis - SDK

まずは、↑のリンクからDive Unity Plugin packageをダウンロードします。そして、ダウンロードするとインポート画面が出るので、importします。

 

そのうえで、Dive_Cameraをプレイヤーの頭(Head)にドラッグ&ドロップすると、カメラの目線をDive_Cameraにすることができます。

f:id:furafura-nau:20170401171620p:plain

 

この時、Dive_Cameraを選択した状態で、InspectorのDive Mouse Lookのチェックを外し(これによって、Dive_Cameraの目線でカメラが設定できます)、もともと存在していたMainCameraを削除しておきましょう。

 

次に、Projectで「Create→C# Script」を選択して、新しいファイルを作成し、名前をGyroScriptに変更してください。

f:id:furafura-nau:20170401172741p:plain

 

そして、GyroScriptファイルを開き、編集していきます。

最初に書いてあるコードをすべて消して、

using UnityEngine;
using System.Collections;

public class GyroScript : MonoBehaviour {

    Quaternion currentGyro;

    void Start(){
        Input.gyro.enabled = true;
    }

    void Update () {
        currentGyro = Input.gyro.attitude;
        this.transform.localRotation = 
            Quaternion.Euler(90, 90, 0) * ( new Quaternion (-currentGyro.x, -currentGyro.y, currentGyro.z, currentGyro.w)); 
    }
}

こちらのスクリプトを記載して保存してください。

 

そして、GyroScriptファイルをDive_Cameraにドラッグ&ドロップして、アタッチ(貼り付け)しましょう。

f:id:furafura-nau:20170401173158p:plain

 

Dive_Cameraを選択した状態でInspectorを確認し、上の画像のように「Gyro Script」が貼り付けられていればOKです。

これで、スマホに搭載されているGyroセンサーの動きを検知して、Dive_Cameraを動かすことが出来ます。

 

次に、Unity Remote5というアプリをダウンロードします。スマホでApp StoreもしくはGoogle Playからダウンロードしましょう。

 

(*ぼくはMacとAndroidで開発しようと思ったんですが、どうもうまくいかなかったので、iOSとMacの組み合わせにしました。後者の組み合わせではうまく機能しました。)

 

そして、Unity上で「File→BuildSettings」を選択し、Platformで該当のデバイスを選択し、Switch Platformを押します。 

f:id:furafura-nau:20170401174523p:plain

 

該当のデバイスにUnityのロゴがついていればOKです。

 

次に、「Edit → Project Settings → Editor」を選択し、InspectorのDevideをnoneから該当のデバイスに変更します。

f:id:furafura-nau:20170401174751p:plain

 

これで、スマホ上でUnity Remoteを起動した状態でPCとスマホをUSBケーブルで繋、Unityをプレイすればスマホの傾きに応じて画面上のカメラが傾くようになります。

 

 

プレイヤーのアニメーション設定

  次に、プレイヤーのアニメーションを設定していきます。

 

Hierarchy上でPlayerを選択した状態で、Projectで「Create→Animator Controller」を選択します。

f:id:furafura-nau:20170401180132p:plain

 

そうすると、Animator Controllerが作成されるので、適当に名前を付けておきましょう。

f:id:furafura-nau:20170401180128p:plain

 

そして、「Window → Animation」を選択します。すると、Animationが起動するのでどこか適当な場所にドラッグ&ドロップしておきましょう。

f:id:furafura-nau:20170401180108p:plain

 

今回はPlayerが攻撃するアニメーションを設定したいので、Animation画面でCreateを押し、「Attack」という名前のAnimationを作成します。 

f:id:furafura-nau:20170401180106p:plain

 

Animationを作成したら、「Add Property」を押し、動きを付ける部分を選択します。今回の場合、Playerが攻撃する=場所(Position)と腕の回転(Rotation)を変化させるので、その2つを選択します。

f:id:furafura-nau:20170401180105p:plain

 

今回の攻撃はそんなに複雑な動きを求めず、「元の状態→振りかぶる→攻撃した状態」という3段階のものにするので、真ん中の地点と最後の地点に赤い線を移動させ、右クリックして「Add Key」を押します。

 

Add Keyを押してKeyをつくった地点に赤い線がある状態で、Hierarchyから動かしたい部分を選択し、PositionやRotationの値を変化させていきます。

 

 ↓ Keyの真ん中の地点でのプレイヤーの状態

f:id:furafura-nau:20170401180103p:plain

 

 ↓ Keyの最後の地点でのプレイヤーの状態

f:id:furafura-nau:20170401180100p:plain

 

Playerの動きを設定し終わったら、Animation画面上の「▶」ボタンを押して、実際にどのような動きになっているか確認して、調整していきます。 

f:id:furafura-nau:20170401181928p:plain

 

最後に、Attackが連続で再生されないように、Inspectorで「Loop Time」のチェックを外しておきましょう。

f:id:furafura-nau:20170401205752p:plain

 

これで、攻撃の動作を作ることが出来ました。

 

次に、Player(つまりスマホ)が前に40度以上傾いたら、攻撃の動作が実行されるように設定していきます。

 

まずは、Project内の「Player」というAnimator Controllerをダブルクリックすると、Sceneの隣に「Animator」という画面が表示されるので、そこで操作していきます。

f:id:furafura-nau:20170401201611p:plain

 

今のままだと、ゲームを開始してすぐにAttackが呼ばれてしまうので、特定のタイミングでのみ、Attackが呼ばれるようにしていきます。

 

Animator画面上で「右クリック → Create State → Empty」で、空のStateを作成します。 

f:id:furafura-nau:20170401201934p:plain

 

その後、NewStateを選択した状態で「右クリック → Set As Layer Default State」で「Entry→NewState」という矢印関係になるようにします。

そして、NewStateで「右クリック → Make Transition」でAttackと繋げます。同じように、AttackからNewStateにも矢印を繋げます。

 

次に、Parametersタブを選択し、「+」をクリックして「Bool」という欄をクリックします。

f:id:furafura-nau:20170401202451p:plain

 

すると、新しい欄が作成されるので、「IsAttack」などと適当に名前を付けておきます。

その後、「NewState→Attack」というようになっている矢印をクリックして、InspectorのConditionsで「IsAttackをtrue」に設定します。また、「Has Exit Time」のチェックを外しておきます。(これにチェックが入っていると、自動で次の動作が行われてしまいます。)

f:id:furafura-nau:20170401202911p:plain

 

同じように、AttackからNewStateに出ている矢印では、「IsAttackをfalse」に設定します。同様に「Has Exit Time」のチェックを外しておきます。

f:id:furafura-nau:20170401203041p:plain

 

これでアニメーションの設定はOKです。次にアニメーションを特定のタイミングで動かすためのスクリプトを書いていきます。

 

ProjectでC# Scriptを選択し、「PlayerController」などと適当な名前を付けておきます。

f:id:furafura-nau:20170401203405p:plain

 

スクリプトが作成できたら、PlayerControllerのスクリプトに以下のようなコードを書いていきます。

PlayerController.cs
using System.Collections;
using UnityEngine;

public class PlayerController : MonoBehaviour {

    public GameObject playerCamera;
    public Animator playerAnim;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        PlayerAttack ();
    }

    void PlayerAttack () {
        if (playerCamera.transform.localEulerAngles.x > 40 && playerCamera.transform.localEulerAngles.x < 90) {
            playerAnim.SetBool ("IsAttack", true);
            Invoke ("PlayerAttackToIdle", 1.5f);
        }
    }

    void PlayerAttackToIdle() {
        playerAnim.SetBool ("IsAttack", false);
    }
}

 

簡単にコードの内容を説明しておきます。

 

if (playerCamera.transform.localEulerAngles.x > 40 && playerCamera.transform.localEulerAngles.x < 90)

Dive_CameraのX軸の傾きを取得していて、40度以上90度以下前に傾いたら呼び出される。

 

playerAnim.SetBool ("IsAttack", true);

playerAnim、つまりPlayerというAnimatorを取得して、そのBoolにチェックを入れています。

f:id:furafura-nau:20170401204830p:plain

これで、「IsAttack」にチェックが入ります。(= Attackが呼び出される。)

 

Invoke ("PlayerAttackToIdle", 1.5f);

Invokeは処理をn秒後に呼び出すことが出来ます。コレ以外にも実装方法はありますが、今回はInvoke使いました。この記述で、PlayerAttackToIdleメソッドを1.5秒後に呼び出しています。

 

void PlayerAttackToIdle() {
        playerAnim.SetBool ("IsAttack", false);
    }

この処理によって、AttackからNewStateの状態に戻っています。この処理がないと、Playerは攻撃したままになってしまって最初の状態に戻ることが出来ません。

 

スクリプトが完成したら、変更を保存してHierarchyのPlayerにドラッグ&ドロップしておきます。

その後、HierarchyでPlayerを指定した状態で、AnimatorにPlayerを設定し、PlayerCameraにDive_Camera、PlayerAnimにPlayerをそれぞれアタッチ(ドラッグ&ドロップ)していきます。

f:id:furafura-nau:20170401205616p:plain

 

以上で、UnityをプレイすればPlayerが攻撃するようになったかと思います。

 

Attackと同じ要領で防御のアニメーションも作って機能するようにしました。

 

 

敵のアニメーション設定

 敵のアニメーションも基本的にはPlayerのアニメーションと同じです。全く同じ挙動を逆向きで動かしたいため、EnemyのAnimatorで「Apply Root Motion」にチェックを入れます。

f:id:furafura-nau:20170401212544p:plain

 

そして、Attackを選択した状態で「Genetate Root Motion Curves」をクリックします。

f:id:furafura-nau:20170401212502p:plain

 

これで、EnemyでもAttackアクションを使うことができるようになりました。

 

あとはPlayerの時と同様にスクリプトを作成して、Enemyが特定のタイミングで動くようにしていきます。

EnemyController1.rb
using System.Collections;
using UnityEngine;

public class EnemyController1 : MonoBehaviour {

    float time;
    public Animator enemyAnim;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        EnemyRandomAttack ();
    }

    void EnemyRandomAttack() {
        time += Time.deltaTime;
        if (time >= 2.5f) {
            EnemyAttack ();
            Invoke ("EnemyAttackToIdle", 1.5f);
            time = 0.0f;
        }
    }

    void EnemyAttack() {
        enemyAnim.SetBool ("IsAttack", true);
    }

    void EnemyAttackToIdle() {
        enemyAnim.SetBool ("IsAttack", false);
    }
}

 

このように、2.5秒毎にEnemyが攻撃してくるような処理を書き、そのスクリプトをEnemyにアタッチします。

 

そして、Playerの時のようにenemyAnimにEnemyをアタッチして、動作確認をしてみます。

すると、Enemyは動くことには動きますが、最初の地点には戻らず、前に進んでいってしまいます。

 

結局、このような動きをさせたくないので、Enemyも一からアニメーションを作成して設定しました。

 

 

以上、プレイヤーと敵の作成でした!

今回はDive Cameraの設定とAnimationの設定が大変でしたね。

 

次回は「審判」を作っていきます。

 

 

では。