この記事ではUnityを使い始めたばかりの方に向けた疑問や不具合の解消方法を載せていきます。
スクリプトエラーの解消方法に関しては
の記事で特化して記載しているのでそちらを参照してください。
この記事ではUnity全般で『こういう不具合が出たけどどうしてこうなっているのかわからない!』という時に確認するポイントを載せていきます。
基本的には当ブログに寄せられたよくある質問をこの記事でまとめてお応えしていこうと思います(2018年8月より個別の回答は停止している為)。
キャラクター操作、アニメーション関連
キャラクター操作やアニメーション関連の不具合に陥った時の見るべきポイントです。
キャラクターが動かない
CharacterControllerで動かす場合
CharacterControllerコンポーネントを使った場合でキャラクターが動かない(アニメーションしないではなくその場から動かない)原因としてありえるのは、
キャラクターの移動に関してはCharacterControllerコンポーネントを使うと移動機能とコライダを含んでいるので、物理的な作用を厳密にしたいと言うのでなければそちらを使うと便利です。
キャラクターの基本的な移動に関しては
の記事辺りから参照してみてください。
Rigidbody+コライダで動かす場合
キャラクター操作をRigidbodyコンポーネントとコライダを使った移動で行う場合でキャラクターが動かない場合は、
Rigidbodyとコライダの発生イベントは設定によって変わってくるので詳細は、
辺りを参照してください。
キャラクターと他のオブジェクトが衝突しない
こんな時は先ほどのキャラクターを『Rigidbody+コライダで動かした時』の項目で見たようにコライダのIs Triggerにチェックを入れてしまっている可能性。
または3D用のコライダと2D用のコライダを衝突させようとしている可能性。
があります。
Is Triggerについては先ほどやりましたので置いておいて、コライダには3D用と2D用がありそれぞれのコライダの物理エンジンは別物なので、お互いは衝突出来ません。
2D用のコライダはコライダ名の後に2D等と付いているのでわかりやすくなっています。
キャラクターがアニメーションをしない
キャラクターがアニメーションをしない場合は、
他の3DCGソフトを使って作成した人型モデルをUnityに取り込んで他の人型キャラクターモデル用に作られたアニメーションを使うにはキャラクターモデルのアニメーションタイプをHumanoid型にする必要があります。
Humanoid型にしないでキャラクターモデルに人型モデル用のアニメーションを適用した時にキャラクターが変なポーズをしたままになります。
人型以外のキャラクターやそのモデル固有のアニメーションを使う場合はアニメーションタイプをGenericにして使用します。
キャラクターのAnimatorにはそのキャラクターのアニメーションを制御するAnimatorControllerを設定する必要があります。
キャラクターのアニメーションであれば、何もしていない→歩く、歩く→何もしていない、といったアニメーションの遷移をAnimatorControllerで作成しています。
AnimatorControllerでアニメーションの状態と遷移条件にしたがってそのアニメーションの状態へと遷移させるわけです。
上のAnimatorControllerであればEntryから繋がる状態がアニメーションの最初の状態になり、その後アニメーションパラメータ(アニメーションを制御する条件のパラメータ)によって状態を遷移させます。
その為、IdleからOtherAnim状態へは直接遷移する事は出来ず、必ずWalk状態からしかOtherAnim状態へは遷移出来ないようになっています。
なのでIdleからOtherAnimに直接遷移させたい時はIdleからOtherAnimにMake Transitionで遷移を作成し条件を設定する必要があります。
わたくしがUnityを始めた頃、『どの状態からでも直接他の状態に勝手に遷移出来るんじゃないの?』というよくわからない疑問を持っていたことがあるので、同じように感じる方がもしかしたらいるかもしれないので書いておきました。
どの状態からでもある状態に遷移させたい時はAny Stateからその状態への遷移を作成すると実現出来ます。
キャラクターの移動等で、何もしていない→歩く、というようなアニメーションの遷移はするけどキーボードを押して移動してもアニメーションが歩きに遷移するのが遅いというような事があります。
この原因としてはAnimatorControllerの遷移条件のHas Exit Timeにチェックが入っている可能性があります。
このHas Exit Timeにチェックが入っているとその状態のアニメーションの正規化した時間がExit Timeに指定した時間を越えるまでは次の状態に遷移しなくなります。
その状態のアニメーションを最初から最後まで再生してから次の状態へと遷移させたい時にHas Exit Timeにチェックを入れ、Exit Timeでアニメーションの再生時間を調整します。
Has Exit Timeの他にアニメーション遷移が遅いと感じる原因のひとつにアニメーションのブレンドの設定があります。
例えばIdle状態からWalk状態へと遷移させる時に、
上のようなブレンドにした場合IdleアニメーションとWalkアニメーションをブレンドした状態が長いので歩くアニメーションがなかなか再生されていないように見えてしまいます。
そんな時はアニメーションのブレンド時間を短くします。
Transition Durationの時間を直接変更するか、下のブレンドのグラフを直接操作してブレンド時間を短くします。
アニメーションブレンドに関しては
の記事やUnityマニュアルの
辺りが参考になると思います。
スクリプト関連の疑問
プログラミングをあまりしたことがない方はスクリプトの中身がどうなっているのか?がわからないことが多いと思います。
そこで基本的なUnityスクリプトの構造を解説します(個人的見解)。
例えば新しくC#スクリプトを作成すると、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class NewBehaviourScript : MonoBehaviour { // Use this for initialization void Start () { } // Update is called once per frame void Update () { } } |
上のようなスクリプトが最初から書かれています。
そこでこのスクリプトの中身について少し解説していきます。
usingディレクティブ部分
1 2 3 4 5 | using System.Collections; using System.Collections.Generic; using UnityEngine; |
の部分はusingディレクティブで例えばusing UnityEngine;の部分であればUnityEngineパッケージ(パッケージはフォルダのようなもの)で定義されている機能をUnityEngineを記述しないでも呼び出すことが出来るようにする為の記述です。
例えばUnityEngineパッケージに『Mathf』というクラスが定義されていてその中のMaxメソッドを使用する場合にusingディレクティブでUnityEngineを指定していない場合は、
1 2 3 4 5 | void Start () { UnityEngine.Debug.Log(UnityEngine.Mathf.Max(0, 2)); } |
という記述が必要ですが(Debugも同じようにUnityEngineパッケージに存在する)、usingディレクティブを書いておくと、
1 2 3 4 5 6 7 | using UnityEngine; void Start () { Debug.Log(Mathf.Max(0, 2)); } |
と、UnityEngineから書かなくても良くなります。
同じ名前のメソッドが複数のパッケージで定義されていることもあるので、あえてパッケージ名全部を指定する必要があることもあります。
ここら辺の事は
の記事の『名前空間関連のエラー』項目を見てください。
スクリプトの名前と継承
次はスクリプトの名前と継承についてです。
1 2 3 4 | public class NewBehaviourScript : MonoBehaviour { } |
このスクリプトの名前はNewBehaviourScriptで、MonoBehaviourクラスを継承して作られています。
ここで記載しているNewBehaviourScriptという名前とUnityのAssetsフォルダ内のスクリプトの名前は一致させておきます。
継承に関してはオブジェクト指向プログラミングの書籍等で勉強しないとなかなか難しい話になりますが、要はMonoBehaviourクラスで定義されている機能をNewBehaviourScriptクラスでも使用出来るようにするという事です。
publicという記述はアクセス修飾子で、このクラスが他のどのクラスからも参照出来るクラスであることを示し、classというのはクラスを定義する時に記述します。
StartメソッドやUpdateメソッド
Startメソッドはスクリプトを設定したゲームオブジェクトが登場した時に1回だけ実行されるメソッドでゲームオブジェクトのパラメータ等の初期設定等に適しています。
詳しくはこちらを参照してください。
Updateメソッドは1秒間に何回も実行されるメソッドで、巷でよく言われる30fpsという用語は1秒間に30フレーム実行する事の意味で、Updateメソッドは30回実行されることになります。
詳しくはこちらを参照してください。
C#の書籍等で勉強してきた方でStartメソッドやUpdateメソッドって何なの!?C#で定義されてるメソッド?という方もいるかもしれません。
StartメソッドやUpdateメソッドはUnity独自のメソッドでMonoBehaviourクラスで定義されているメソッドです。
実際はStartやUpdateはUnityの内部から最初の1回やマイフレームイベントを発生し、それを受け取っているのがStartやUpdate等のイベントハンドラなんだと思います。
なのでStartは最初の1回、Updateはマイフレーム実行されるというのが決まっています。
そんなわけでそういった発生するタイミングに合わせてその中身を自分で記述していくことになります。
あらかじめ用意されているそういうメソッドだと思っていればいいと思います。
スクリプトで元々定義されているメソッドか自前のメソッドかわからない場合の対応
Unityのサイト等のサンプルスクリプトを見て自分も実行してみようと思った時に書かれているメソッドがその人独自のメソッドなのか?はたまたUnityで用意されているメソッドなのか?がわからないこともあります。
そんな時に便利なのがUnityスクリプトリファレンスです。
例えばUnityのスクリプトリファレンスでMonoBehaviourで検索して出てくるページを開くと、
MonoBehaviourで定義されている変数やメソッド等の一覧が見れるのでStartやUpdateがMonoBehaviourで定義されているのがわかりますし、StartメソッドやUpdateメソッドがどういったものなのか?も記載されています。
スクリプトリファレンスを見て調べる癖が付くと、例えばCharacterControllerコンポーネントを使って地面と接地しているかどうか調べるプロパティってないかな?と思ったら、
スクリプトリファレンスでCharacterControllerで検索し、そのページでisGroudedというプロパティで地面に接地しているかどうかを調べることが出来るという事がわかります。
コライダに関連したものを調べる時も、CapsuleColliderを使っていたらそのCapsuleColliderと他のコライダとの接触点の座標を調べたい時に自分で何らかの計算をして求める前にCapsuleColliderで使えるプロパティやメソッドがないかを調べて使えるものを探すという事を先にすると良いと思います。
コライダをゲームオブジェクトの検知範囲として使用した時の不具合
操作キャラクターの検知範囲に相手方のコライダが侵入した時に何らかの処理をしたい事は多々ありますが、設定によっては相手方の検知が出来ません。
相手のコライダを検知した時にOnTriggerEnter等のイベントが発生しますが、この発生する条件があります。
詳しくは
の記事で検証しています。
ここで簡単な例で確認してみます。
上のようなキャラクターと子要素に検知エリアであるSearchAreaを作成し、そこに検知エリアであるSphereColliderと検知スクリプトであるSearchScriptを取り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class SearchScript : MonoBehaviour { public void OnTriggerEnter(Collider other) { Debug.Log(other.name); } } |
その他にCubeのデフォルト状態の物とその他のキャラクターを配置します。
CubeはBoxColliderのIs Triggerのチェックが外されているので物理的に接触するゲームオブジェクトで、OtherCharaには移動機能とコライダを含むCharacterControllerコンポーネントを取り付けています。
操作キャラクターを動かし検知範囲内にCubeや他のキャラクターを入れるとコンソールにそのゲームオブジェクトの名前が表示されるはずです。
このまま実行すると、コンソールに表示されるのは
Ethan
OtherChara
です。
Ethanは自分自身で自分自身のCharacterControllerのコライダも検知するので表示されます。Cubeは検知出来ないんですね。
次は設定を少し変えます。
CubeにはRigidbodyコンポーネントを取り付け、OtherCharaのCharacterControrllerを削除し、CapsuleColliderに変更してみます。
これで操作キャラクターの範囲内に他のゲームオブジェクトを入れてみると、
Ethan
Cube
が表示されます。
OtherCharaはRigidbodyがついていないので検知出来ませんね。
OtherCharaもRigidbodyを取り付ければ検知出来るようになります。
どういった時にOnTrigger等のイベントが発生するかは先ほどのリンク先を参照してみてください。
Rigidobodyコンポーネントとは一体何なのか?という疑問を持つ方もいると思いますが、UnityマニュアルのRigidbodyのページを見ると、
説明の中に、
ゲームオブジェクトを物理特性を使って制御する事が出来るようになります。
とあります。
Rigidbodyコンポーネントを取り付けたゲームオブジェクトは力を加えたり力を受けたりするようになります。
なので何らかの物体と衝突した時に力を加えて押したり、逆に押されたりといった事が出来るようになります。
UIのボタンを使った処理
UIのボタンを押した時に何らかの処理をする事はよくありますが、そんな時の疑問点です。
「UIのボタンを押したらコンソールに文字列を表示する」という処理を作ったけれどボタンを押しても何の処理も実行されないということがあります。
スクリプトの処理が間違っているという可能性もありますが、その前にボタンを押した時に実行するスクリプトの設定が間違っていることが多いです。
そんなわけでUIのボタンが押された時に作成したスクリプトのメソッドを実行する流れを確認していきたいと思います。
UIのボタンはボタンが押された時にOn Clickで指定されたゲームオブジェクトに設定されているスクリプトのメソッドを実行するように設定します。
まぁ説明が長ったらしくてわかりにくいので簡単なサンプルを作成し確認していきます。
まずはヒエラルキー上で右クリック→UI→Buttonを押します。
UIのゲームオブジェクトを作成すると必ずEventSystemというゲームオブジェクトも作られますが、このEventSystemというゲームオブジェクトがUIの操作を監視しイベントを発生させる機能なので削除してはダメです。
次にボタンが押された時のスクリプトを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class MyMouseScript : MonoBehaviour { public void OnMyClick() { Debug.Log("クリックされたよ!"); } } |
クリックされた時に実行するメソッド名をOnMyClickという名前にしました(名前はわかりやすい名前、例えばクリック時に実行するメソッドはOnClick等にします)。
ここで作成したメソッドは普通に作成したメソッドと何ら変わりはなく、スクリプト中から普通に呼び出せます。
例えば、Updateメソッドに以下のように記述すると、マウスの右クリックをした時にOnMyClickメソッドを呼び出すことが出来ます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class MyMouseScript : MonoBehaviour { public void OnMyClick() { Debug.Log("クリックされたよ!"); } private void Update() { if(Input.GetButtonDown("Fire2")) { OnMyClick(); } } } |
なのでButtonのOn Clickに指定するメソッドはボタンを押した時に実行するべき普通のメソッドを指定しているだけということになります。
スクリプトが出来たので、Buttonの親要素のCanvasにMyMouseScriptをドラッグ&ドロップして設定します。
またButtonの親要素であるCanvas以外にスクリプトを設定しても同じか確認する為、ヒエラルキー上で右クリック→Create Emptyで空のゲームオブジェクトを作成し、そのゲームオブジェクトにもMyMouseScriptを取り付けておきます。
あとはButtonのOn ClickにCanvasに取り付けたMyMouseScriptのOnMyClickメソッドを設定するだけです。
On Clickの+を押してスロットを追加します。
スクリプトが設定されているゲームオブジェクトをドラッグ&ドロップします。
最後にそのスクリプトで実行するメソッドを選択します。
ここでOnMyClickメソッドが表示されていない時はOnMyClickメソッドのアクセス修飾子にpublicが指定されていない可能性があるのでスクリプトを確認します。
これで設定が終わりました。
後はゲームを実行してボタンを押せばコンソールに『クリックされたよ!』という文字列が表示されます。
Canvasに設定されたMyMouseScriptのOnMyClickが実行が出来たら、空のゲームオブジェクトに設定されたMyMouseScriptのOnMyClickも実行出来るかどうか設定を変えてやってみてください。
Unityのバージョンアップをしたら動かなくなった
Unityのバージョンアップを行い、プロジェクトをそのバージョンで使えるように変更したら動かなくなることがあります。
Unityの古い機能や古いスクリプトを使っていることによって動かなくなることもありますが、その時はコンソールに出たエラーの内容を確認し修正することで動く場合もあります。
バージョンアップをしたことによってゲーム実行時にエラーが表示されるが、その内容を見てみてもどうしてもエラーが出ている感じがしなかったりUnityが突然クラッシュして閉じてしまうが原因がわからない!ということもあります。
そういう場合や、Unityのライブラリが原因でクラッシュしている場合はUnityで開いているシーンを再度保存したりスクリプトを再度保存し実行してみると正常に動くこともあります。
終わりに
Unityを使い始めの頃によくある躓きポイントについて解説しました。
使い始めの頃と書いてますが、使っていないと忘れてしまってはまるポイントでもあるので、自分の為にも良かったかもしれません。
他にもつまづきポイントがあれば追記していきます。