Unityでオンラインに接続してリアルタイムで他の人とゲームが出来る機能を作成していきます。
他の人とオンラインでゲームをする為にサーバーに接続します。
その時にそれぞれのキャラクターの位置や敵を攻撃してダメージを与えた、といった情報をサーバーを介して情報をやりとりします。
しかしこのサーバーを用意したりオンラインに対応したプログラミングをしようと思うと相当な知識と能力を必要とします。
こりゃだめだ・・・・とオンライン対応を諦めてしまいます。
Unityでもネットワーク対応のコンポーネントが用意されておりそれを使うと比較的簡単に対応できるようです。
あくまで比較的にで実際に作ろうと思うとやっぱり敷居が高い感じがしますね・・・・(^_^;)
PhotonCloudを使ったオンライン対応
今回はPhotonCloudというリアルタイムでやりとりをする時に便利なサーバーシステムを利用しオンライン対応していきます。
PhotonCloudはUnityのNetworkManagerと似たような感じで使う事が出来るアセットを使いオンライン対応する事が出来ます。
UnityNetworkでマルチプレイ対応をしたい方は
から参照してみてください。
アセットのインポートや登録等はまた別の記事で行います。
UnityのライブトレーニングでもPhotonCloudを利用したリアルタイム対戦の動画があるのでこちらを参考にリアルタイムでやりとり出来るゲームを作っていきたいと思います。
オンライン対応するゲームを作成
今回はオンラインに対応する前にオフラインで動作する主人公と敵キャラクターを作成しておきます。
シンプルな動きにしておきオンライン対応した時に大変にならないようにします・・・・・(^_^;)
あらかじめ言及しておかなければいけないんですが、スクリプトをJavaScriptで作成していくとスクリプトの連携で結構面倒臭い事になります。
C#からJavaScriptを参照する為に別フォルダに移動しなければいけなかったりアセンブリの参照がうまくいかなかったりで、わたくしには出来ませんでした(^_^;)
その為、今回はキャラクターの移動やネットワーク接続のスクリプト等は全てC#で記述していきます。
JavaScriptでの記事を期待していた方には申し訳ないですね(-_-)
主人公キャラクターの作成
主人公にCharacterControllerの設定と移動スクリプトの取り付け
主人公キャラクターはStandardAssets/Characters/ThirdPersonCharacter/ModelsにあるEthanをヒエラルキーに設置しCharacterControllerの取り付けを行い、
移動と攻撃をするCharaスクリプトを作成し取りつけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | using UnityEngine; using System.Collections; using UnityEngine.UI; public class Chara : MonoBehaviour { private Animator animator; private CharacterController cCon; private float x; private float y; private Vector3 velocity; // Use this for initialization void Start () { animator = GetComponent<Animator>(); cCon = GetComponent<CharacterController>(); velocity = Vector3.zero; } // Update is called once per frame void Update () { // 地面に接地してる時は初期化 if(cCon.isGrounded) { velocity = Vector3.zero; x = Input.GetAxis("Horizontal"); y = Input.GetAxis("Vertical"); Vector3 input = new Vector3(x, 0, y); // 方向キーが多少押されている if(input.magnitude > 0.1f && !animator.GetCurrentAnimatorStateInfo(0).IsName("Attack")) { animator.SetFloat("Speed", input.magnitude); transform.LookAt(transform.position + input); velocity += input.normalized * 2; // キーの押しが小さすぎる場合は移動しない } else { animator.SetFloat("Speed", 0); } if(Input.GetButtonDown("Fire1") && !animator.GetCurrentAnimatorStateInfo(0).IsName("Attack") && !animator.IsInTransition(0) ) { animator.SetBool("Attack", true); } } velocity.y += Physics.gravity.y * Time.deltaTime; cCon.Move(velocity * Time.deltaTime); } } |
↑が移動と攻撃をさせる処理です。
Animator Controllerの設定と取りつけ
主人公キャラクターには新しくCharaというAnimator Controllerを作成しインスペクタのAnimatorに設定します。
Float型のSpeed、Bool型のAttackのアニメーションパラメータを作成します。
状態と遷移は↑のように作成しSpeedが0.1より上の時Walk、0.1より下の時Idle、AttackがtrueになったらAttack状態へと遷移するように設定します。
Attack→Idleへの遷移条件はなしでHas Exit Timeにチェックを入れます。
Attack状態を選択しインスペクタでAdd Behaviourをクリックし新しくAttackEndというビヘイビアを作成します。
↑のように設定します。
ビヘイビアはC#になります(JavaScriptでも作成出来ます)。
ビヘイビアには
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | using UnityEngine; using System.Collections; public class AttackEnd : StateMachineBehaviour { // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state //override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks //override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} // OnStateExit is called when a transition ends and the state machine finishes evaluating this state override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { animator.SetBool ("Attack", false); } // OnStateMove is called right after Animator.OnAnimatorMove(). Code that processes and affects root motion should be implemented here //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} // OnStateIK is called right after Animator.OnAnimatorIK(). Code that sets up animation IK (inverse kinematics) should be implemented here. //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} } |
と状態が終わった時にAttackをfalseにしています。
Animatorについては
を参照してください。
Attackに設定したアニメーションにはAttackStartとAttackEndというアニメーションイベントを設定します。
アニメーションイベントに関しては
を参照し設定してください。
AttackStartは↑のような位置で発生させます。
AttackEndは↑のように剣を振りきった位置で発生させます。
Animator ControllerのAttackに設定したアニメーションによってイベントの攻撃開始位置と攻撃終了位置は変わります。
Ethanの右手に武器を持たせる
Ethanに武器を持たせます。
Asset Store等からインポートした武器をEthanの右手のボーンの子要素に設定します。
↑のようにEthanRightHandの子要素に武器を配置しました。
武器を正確に持たせるやり方は
を参照してください。
武器にはCapusule Colliderを取りつけ横のチェックボックスのチェックを外しておきます。
スクリプトからここのチェックをオン・オフして当たり判定を調整します。
Is Triggerにチェックを入れ物理的に当たらないようにします。
武器が敵に当たった時に実行するAttackスクリプトを作り武器に取りつけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | using UnityEngine; using System.Collections; public class Attack : MonoBehaviour { // 攻撃力 [SerializeField] private int attackPower = 10; void OnTriggerEnter(Collider col) { if (col.tag == "Enemy") { col.GetComponent<Enemy>().Damage(attackPower); } } } |
武器がEnemyタグを設定したゲームオブジェクトに侵入した場合、相手が持っているEnemyスクリプトのDamage関数を攻撃力を引数にして呼び出します。
与えるダメージはインスペクタで設定出来るようにします。
アニメーションイベントを受け取るProcessAttackスクリプトの作成
アニメーションイベントの作成が出来たらそのイベントを受け取るスクリプトが必要です。
Animatorが設定されているゲームオブジェクトであるEthanに新しいスクリプトProcessAttackを作成し取りつけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using UnityEngine; public class ProcessAttack : MonoBehaviour { public Collider col; void AttackStart() { col.enabled = true; } void AttackEnd() { col.enabled = false; } } |
アニメーションイベントと同じ名前の関数を記述する事でアニメーションイベントが発生した時に処理をする事が出来ます。
インスペクタで武器に設定したCapsule Colliderを指定し、アニメーションの再生位置によってコライダのオン・オフをしています。
キャラクターのステータススクリプト
次にキャラクターのステータススクリプトStatusを作成し、Ethanに取り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class Status : MonoBehaviour { [SerializeField] private int hp = 50; public int GetHp() { return hp; } } |
これで主人公キャラクターの作成が出来ました。
敵キャラクターの作成
Asset StoreでMonster3という敵のモデルを探しインポートします。
モデルをヒエラルキー上にドラッグ&ドロップしたらCharacterControllerを取りつけコライダの調整をしてください。
敵キャラクターには新しくEnemyスクリプトを作成し、取りつけます。
今回は主人公から攻撃を受けた時のダメージ処理と倒れた時の処理を記述しているだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | using UnityEngine; using System.Collections; public class Enemy : MonoBehaviour { private int hp; // 敵の体力 void Start () { hp = 10; } void Damage(int damage) { Debug.Log("敵に" + damage + "ポイント与えた"); this.hp -= damage; if(this.hp <= 0) { Dead(); } } void Dead() { Debug.Log("敵を倒した"); Destroy(gameObject); } } |
非常にシンプルな作りですね。
敵キャラクターはただ立って攻撃を受け続ける事しか出来ません・・・・(-_-)
作成したサンプルの動作確認
これでオフラインでの主人公と敵キャラクターが出来ました。
主人公を操作し敵キャラクターを攻撃して問題がないか確認してください。
↑は敵のhpを100に設定し主人公の攻撃力attackPowerを20に設定して試しました。
攻撃のアニメーションフレームが少なく当たり判定がなかなかされないです・・・・(^_^;)
敵キャラの当たり判定を大きくしたり、剣の当たり判定を大きくしたり、剣にRigidbodyを取りつけCollision DetectionをContinuous Dynamicにすると
多少当たるようになるかも!?
次回はPhoton Cloudのアカウント作成からUnityでの設定をやっていきます。