Unityを使い始めたばかりの人がつまづきやすい点を解消する

この記事ではUnityを使い始めたばかりの方に向けた疑問や不具合の解消方法を載せていきます。

スクリプトエラーの解消方法に関しては

Unityのスクリプトを組んでいると必ず発生するのがコンパイルエラーです。このコンパイルエラーを修正する方法を実例とともに紹介したいと思います。

の記事で特化して記載しているのでそちらを参照してください。

この記事ではUnity全般で『こういう不具合が出たけどどうしてこうなっているのかわからない!』という時に確認するポイントを載せていきます。

基本的には当ブログに寄せられたよくある質問をこの記事でまとめてお応えしていこうと思います(2018年8月より個別の回答は停止している為)。

スポンサーリンク

キャラクター操作、アニメーション関連

キャラクター操作やアニメーション関連の不具合に陥った時の見るべきポイントです。

キャラクターが動かない

CharacterControllerで動かす場合

CharacterControllerコンポーネントを使った場合でキャラクターが動かない(アニメーションしないではなくその場から動かない)原因としてありえるのは、

  • キャラクターにCharacterControllerを設定していない、もしくはキャラクターの移動スクリプトをキャラクターにアタッチ(取り付け)していない可能性があります。
  • ゲームスタート時のCharacterControllerのコライダが他のゲームオブジェクトのコライダに被っていて動けないという事もあるのでゲームスタート時にお互いのコライダの範囲が被らないようにします。
  • キャラクターの移動に関してはCharacterControllerコンポーネントを使うと移動機能とコライダを含んでいるので、物理的な作用を厳密にしたいと言うのでなければそちらを使うと便利です。

    キャラクターの基本的な移動に関しては

    Unityでキャラクターを移動する為に準備しておく事と、移動させる為に必要な事を考える

    の記事辺りから参照してみてください。

    Rigidbody+コライダで動かす場合

    キャラクター操作をRigidbodyコンポーネントとコライダを使った移動で行う場合でキャラクターが動かない場合は、

  • コライダのIs Triggerにチェックが入っていて、コライダが他のコライダと衝突をしないで単なるコライダ検知範囲として使用してしまっている可能性があります。基本的にコライダを他のコライダの検知として使う場合はIs Triggerにチェック、他のコライダと衝突させる場合はIs Triggerのチェックを外すという事になります。
  • Rigidbodyとコライダの発生イベントは設定によって変わってくるので詳細は、

    Unityのコリジョン(OnCollision)とコライダ(OnCollider)のイベントが呼ばれる為の条件を検証してみました。

    辺りを参照してください。

    キャラクターと他のオブジェクトが衝突しない

  • キャラクターやゲームオブジェクトにコライダを取り付けたけどお互いが衝突しないですり抜けてしまう。
  • こんな時は先ほどのキャラクターを『Rigidbody+コライダで動かした時』の項目で見たようにコライダのIs Triggerにチェックを入れてしまっている可能性。

    または3D用のコライダと2D用のコライダを衝突させようとしている可能性。

    があります。

    Is Triggerについては先ほどやりましたので置いておいて、コライダには3D用と2D用がありそれぞれのコライダの物理エンジンは別物なので、お互いは衝突出来ません。

    2D用のコライダはコライダ名の後に2D等と付いているのでわかりやすくなっています。

    キャラクターがアニメーションをしない

    キャラクターがアニメーションをしない場合は、

  • 人型モデルのタイプをHumanoid型にしていない可能性があります。
  • 他の3DCGソフトを使って作成した人型モデルをUnityに取り込んで他の人型キャラクターモデル用に作られたアニメーションを使うにはキャラクターモデルのアニメーションタイプをHumanoid型にする必要があります。

    人型キャラクターをHumanoidにする

    Humanoid型にしないでキャラクターモデルに人型モデル用のアニメーションを適用した時にキャラクターが変なポーズをしたままになります。

    人型以外のキャラクターやそのモデル固有のアニメーションを使う場合はアニメーションタイプをGenericにして使用します。

  • AnimatorにAnimatorControllerを設定していない
  • キャラクターのAnimatorにはそのキャラクターのアニメーションを制御するAnimatorControllerを設定する必要があります。

    AnimatorにAnimatorControllerを設定する

  • AnimatorControllerの遷移が適切でない
  • キャラクターのアニメーションであれば、何もしていない→歩く、歩く→何もしていない、といったアニメーションの遷移をAnimatorControllerで作成しています。

    AnimatorControllerでアニメーションの状態と遷移条件にしたがってそのアニメーションの状態へと遷移させるわけです。

    AnimatorControllerの基本構造

    上のAnimatorControllerであればEntryから繋がる状態がアニメーションの最初の状態になり、その後アニメーションパラメータ(アニメーションを制御する条件のパラメータ)によって状態を遷移させます。

    その為、IdleからOtherAnim状態へは直接遷移する事は出来ず、必ずWalk状態からしかOtherAnim状態へは遷移出来ないようになっています。

    なのでIdleからOtherAnimに直接遷移させたい時はIdleからOtherAnimにMake Transitionで遷移を作成し条件を設定する必要があります。

    わたくしがUnityを始めた頃、『どの状態からでも直接他の状態に勝手に遷移出来るんじゃないの?』というよくわからない疑問を持っていたことがあるので、同じように感じる方がもしかしたらいるかもしれないので書いておきました。

    どの状態からでもある状態に遷移させたい時はAny Stateからその状態への遷移を作成すると実現出来ます。

  • キャラクターのアニメーションの切り替わりが遅い
  • キャラクターの移動等で、何もしていない→歩く、というようなアニメーションの遷移はするけどキーボードを押して移動してもアニメーションが歩きに遷移するのが遅いというような事があります。

    この原因としてはAnimatorControllerの遷移条件のHas Exit Timeにチェックが入っている可能性があります。

    AnimatorControllerのHas Exit Timeのチェックを外す

    このHas Exit Timeにチェックが入っているとその状態のアニメーションの正規化した時間がExit Timeに指定した時間を越えるまでは次の状態に遷移しなくなります。

    その状態のアニメーションを最初から最後まで再生してから次の状態へと遷移させたい時にHas Exit Timeにチェックを入れ、Exit Timeでアニメーションの再生時間を調整します。

    Has Exit Timeの他にアニメーション遷移が遅いと感じる原因のひとつにアニメーションのブレンドの設定があります。

    例えばIdle状態からWalk状態へと遷移させる時に、

    アニメーション遷移のブレンドを長くしたサンプル

    上のようなブレンドにした場合IdleアニメーションとWalkアニメーションをブレンドした状態が長いので歩くアニメーションがなかなか再生されていないように見えてしまいます。

    そんな時はアニメーションのブレンド時間を短くします。

    アニメーションのブレンド時間を操作する

    Transition Durationの時間を直接変更するか、下のブレンドのグラフを直接操作してブレンド時間を短くします。

    アニメーションブレンドに関しては

    UnityのAnimatorControllerのアニメーションのブレンド方法や遷移の設定、Interruption Sourceの設定等を見ていきます。アニメーションの遷移途中で中断し次の状態へとうまく移行させる為のサンプルも作成します。

    の記事やUnityマニュアルの

    アニメーション遷移 (Animation Transition) は、ステートマシン が、あるアニメーションステートから別のアニメーションステートへ切り替わったりブレンドしたりすることを可能にします。遷移は、複数のステート間のブレンドにかかる時間の長さを指定するだけでなく、どのような条件下でブレンドが始まるかを指定しま...

    辺りが参考になると思います。

    スクリプト関連の疑問

    プログラミングをあまりしたことがない方はスクリプトの中身がどうなっているのか?がわからないことが多いと思います。

    そこで基本的なUnityスクリプトの構造を解説します(個人的見解)。

    例えば新しくC#スクリプトを作成すると、

    上のようなスクリプトが最初から書かれています。

    そこでこのスクリプトの中身について少し解説していきます。

    usingディレクティブ部分

    の部分はusingディレクティブで例えばusing UnityEngine;の部分であればUnityEngineパッケージ(パッケージはフォルダのようなもの)で定義されている機能をUnityEngineを記述しないでも呼び出すことが出来るようにする為の記述です。

    例えばUnityEngineパッケージに『Mathf』というクラスが定義されていてその中のMaxメソッドを使用する場合にusingディレクティブでUnityEngineを指定していない場合は、

    という記述が必要ですが(Debugも同じようにUnityEngineパッケージに存在する)、usingディレクティブを書いておくと、

    と、UnityEngineから書かなくても良くなります。

    同じ名前のメソッドが複数のパッケージで定義されていることもあるので、あえてパッケージ名全部を指定する必要があることもあります。

    ここら辺の事は

    Unityのスクリプトを組んでいると必ず発生するのがコンパイルエラーです。このコンパイルエラーを修正する方法を実例とともに紹介したいと思います。

    の記事の『名前空間関連のエラー』項目を見てください。

    スクリプトの名前と継承

    次はスクリプトの名前と継承についてです。

    このスクリプトの名前はNewBehaviourScriptで、MonoBehaviourクラスを継承して作られています。

    ここで記載しているNewBehaviourScriptという名前とUnityのAssetsフォルダ内のスクリプトの名前は一致させておきます。

    継承に関してはオブジェクト指向プログラミングの書籍等で勉強しないとなかなか難しい話になりますが、要はMonoBehaviourクラスで定義されている機能をNewBehaviourScriptクラスでも使用出来るようにするという事です。

    publicという記述はアクセス修飾子で、このクラスが他のどのクラスからも参照出来るクラスであることを示し、classというのはクラスを定義する時に記述します。

    StartメソッドやUpdateメソッド

    Startメソッドはスクリプトを設定したゲームオブジェクトが登場した時に1回だけ実行されるメソッドでゲームオブジェクトのパラメータ等の初期設定等に適しています。

    詳しくはこちらを参照してください。

    Unityで初期化処理等でよく使うAwakeとStart関数の違いを検証してみます

    Updateメソッドは1秒間に何回も実行されるメソッドで、巷でよく言われる30fpsという用語は1秒間に30フレーム実行する事の意味で、Updateメソッドは30回実行されることになります。

    詳しくはこちらを参照してください。

    Unityのスクリプトでよく使うUpdate関数、FixedUpdate関数、LateUpdate関数について見ていき、違いを確認します。

    C#の書籍等で勉強してきた方でStartメソッドやUpdateメソッドって何なの!?C#で定義されてるメソッド?という方もいるかもしれません。

    StartメソッドやUpdateメソッドはUnity独自のメソッドでMonoBehaviourクラスで定義されているメソッドです。

    実際はStartやUpdateはUnityの内部から最初の1回やマイフレームイベントを発生し、それを受け取っているのがStartやUpdate等のイベントハンドラなんだと思います。

    なのでStartは最初の1回、Updateはマイフレーム実行されるというのが決まっています。

    そんなわけでそういった発生するタイミングに合わせてその中身を自分で記述していくことになります。

    あらかじめ用意されているそういうメソッドだと思っていればいいと思います。

    スクリプトで元々定義されているメソッドか自前のメソッドかわからない場合の対応

    Unityのサイト等のサンプルスクリプトを見て自分も実行してみようと思った時に書かれているメソッドがその人独自のメソッドなのか?はたまたUnityで用意されているメソッドなのか?がわからないこともあります。

    そんな時に便利なのがUnityスクリプトリファレンスです。

    例えばUnityのスクリプトリファレンスでMonoBehaviourで検索して出てくるページを開くと、

    MonoBehaviour is the base class from which every Unity script derives.

    MonoBehaviourで定義されている変数やメソッド等の一覧が見れるのでStartやUpdateがMonoBehaviourで定義されているのがわかりますし、StartメソッドやUpdateメソッドがどういったものなのか?も記載されています。

    スクリプトリファレンスを見て調べる癖が付くと、例えばCharacterControllerコンポーネントを使って地面と接地しているかどうか調べるプロパティってないかな?と思ったら、

    スクリプトリファレンスでCharacterControllerで検索し、そのページでisGroudedというプロパティで地面に接地しているかどうかを調べることが出来るという事がわかります。

    CharacterController は Rigidbdy による処理を持たなくても衝突判定によって簡単に動きの制限を行うことが可能です。

    コライダに関連したものを調べる時も、CapsuleColliderを使っていたらそのCapsuleColliderと他のコライダとの接触点の座標を調べたい時に自分で何らかの計算をして求める前にCapsuleColliderで使えるプロパティやメソッドがないかを調べて使えるものを探すという事を先にすると良いと思います。

    コライダをゲームオブジェクトの検知範囲として使用した時の不具合

  • コライダの検知範囲内に相手のコライダが侵入したのに検知出来ない
  • 操作キャラクターの検知範囲に相手方のコライダが侵入した時に何らかの処理をしたい事は多々ありますが、設定によっては相手方の検知が出来ません。

    相手のコライダを検知した時にOnTriggerEnter等のイベントが発生しますが、この発生する条件があります。

    詳しくは

    Unityのコリジョン(OnCollision)とコライダ(OnCollider)のイベントが呼ばれる為の条件を検証してみました。

    の記事で検証しています。

    ここで簡単な例で確認してみます。

    OnTriggerイベント等の簡単な検証サンプル

    上のようなキャラクターと子要素に検知エリアであるSearchAreaを作成し、そこに検知エリアであるSphereColliderと検知スクリプトであるSearchScriptを取り付けます。

    その他に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 を使うと、ゲームオブジェクト を物理特性によって制御する事ができるようになります。リジッドボディに力やトルクを加えると、オブジェクトをリアリスティックに動かすことができます。重力の影響を加えたり、スクリプトを使って力を与えたり、NVIDIA PhysX 物理エンジンを通して他のオブジェクトと相互作用...

    説明の中に、

    ゲームオブジェクトを物理特性を使って制御する事が出来るようになります。

    とあります。

    Rigidbodyコンポーネントを取り付けたゲームオブジェクトは力を加えたり力を受けたりするようになります。

    なので何らかの物体と衝突した時に力を加えて押したり、逆に押されたりといった事が出来るようになります。

    Rigidbodyコンポーネントを取り付けていないゲームオブジェクトは動かないゲームオブジェクトと見なされる為、動くことを想定しているゲームオブジェクトにはRigidbodyを取り付けておくといいかもしれません。

    動かない前提のゲームオブジェクトをスクリプト等で動かすと処理速度に影響が出る可能性があります。

    UIのボタンを使った処理

    UIのボタンを押した時に何らかの処理をする事はよくありますが、そんな時の疑問点です。

  • UIのボタンを押したのに何の処理も実行してくれない。
  • 「UIのボタンを押したらコンソールに文字列を表示する」という処理を作ったけれどボタンを押しても何の処理も実行されないということがあります。

    スクリプトの処理が間違っているという可能性もありますが、その前にボタンを押した時に実行するスクリプトの設定が間違っていることが多いです。

    そんなわけでUIのボタンが押された時に作成したスクリプトのメソッドを実行する流れを確認していきたいと思います。

    UIのボタンはボタンが押された時にOn Clickで指定されたゲームオブジェクトに設定されているスクリプトのメソッドを実行するように設定します。

    まぁ説明が長ったらしくてわかりにくいので簡単なサンプルを作成し確認していきます。

    まずはヒエラルキー上で右クリック→UI→Buttonを押します。

    サンプルのUIボタンを作成

    UIのゲームオブジェクトを作成すると必ずEventSystemというゲームオブジェクトも作られますが、このEventSystemというゲームオブジェクトがUIの操作を監視しイベントを発生させる機能なので削除してはダメです。

    次にボタンが押された時のスクリプトを作成します。

    クリックされた時に実行するメソッド名をOnMyClickという名前にしました(名前はわかりやすい名前、例えばクリック時に実行するメソッドはOnClick等にします)。

    ここで作成したメソッドは普通に作成したメソッドと何ら変わりはなく、スクリプト中から普通に呼び出せます。

    例えば、Updateメソッドに以下のように記述すると、マウスの右クリックをした時にOnMyClickメソッドを呼び出すことが出来ます。

    なのでButtonのOn Clickに指定するメソッドはボタンを押した時に実行するべき普通のメソッドを指定しているだけということになります。

    スクリプトが出来たので、Buttonの親要素のCanvasにMyMouseScriptをドラッグ&ドロップして設定します。

    またButtonの親要素であるCanvas以外にスクリプトを設定しても同じか確認する為、ヒエラルキー上で右クリック→Create Emptyで空のゲームオブジェクトを作成し、そのゲームオブジェクトにもMyMouseScriptを取り付けておきます。

    Buttonが押された時に実行するスクリプトをゲームオブジェクトに取り付ける

    あとはButtonのOn ClickにCanvasに取り付けたMyMouseScriptのOnMyClickメソッドを設定するだけです。

    On Clickの+を押してスロットを追加します。

    ボタンを押した時に実行するメソッドのスロットを追加

    スクリプトが設定されているゲームオブジェクトをドラッグ&ドロップします。

    ボタンを押した時に実行するスクリプトが設定されたゲームオブジェクトを設定

    最後にそのスクリプトで実行するメソッドを選択します。

    ボタンを押した時に実行するメソッドを設定

    ここでOnMyClickメソッドが表示されていない時はOnMyClickメソッドのアクセス修飾子にpublicが指定されていない可能性があるのでスクリプトを確認します。

    ボタンを押した時に実行されるメソッドが設定された

    これで設定が終わりました。

    後はゲームを実行してボタンを押せばコンソールに『クリックされたよ!』という文字列が表示されます。

    Canvasに設定されたMyMouseScriptのOnMyClickが実行が出来たら、空のゲームオブジェクトに設定されたMyMouseScriptのOnMyClickも実行出来るかどうか設定を変えてやってみてください。

    終わりに

    Unityを使い始めの頃によくある躓きポイントについて解説しました。

    使い始めの頃と書いてますが、使っていないと忘れてしまってはまるポイントでもあるので、自分の為にも良かったかもしれません。

    他にもつまづきポイントがあれば追記していきます。

    スポンサーリンク

    記事をシェアして頂ける方はこちら

    フォローして頂くとやる気が出ます