この記事でのバージョン
Unity 5.4.1f1, 5.5.0b6
はじめに
今回はUnityの入力を簡単に処理できるInputクラスの話です。
タイトルの通り、このInputはシーンを移動するとリセットされる場合があります。
例えば、以下のようにキーボードのAとSを押すとログが表示され(Input.GetKeyで取得)、
ボタンを押したらシーンを移動するという場合に、
複数の入力があると、シーン移動後は一つの入力しか受け取れません。
以下の例ではAとSキーを入力したまま、シーン移動をしていますが、
Sキーの入力しか取れていないのが分かると思います。
なお、キーの入力が受け取れなくなった場合、
指を離してもInput.GetKeyUpも取得出来ないため、指を離したかどうかも分かりません。
仕様?バグ?
仕様かバグなのかよく分からず、ネット上にもそれらしい情報を見つけれられなかったので、
Unityの日本語ヘルプデスクで聞いてみました。
頂いた回答を要約すると以下のような感じでした。
- シーンがロードされるタイミングですべての入力がリセットのは仕様。
- ゲームの種類等にも依るが、各レベル、ステージ等でシーンを分けることは推奨されず、一つのシーンにすべて詰め込むほうがよい。
Inputがリセットされるのが仕様という事なので、
一つだけ入力が受け取れていた事の方がバグだったっぽいです。
なお、一つのシーンに詰め込む件の参考文献とその要約は以下の通りです。
すべてのスクリーンやアセット、GameObjectを一つのシーンに展開し、現在使用するレベル、ステージで使用するGameObject等をアクティブにし、カメラ座標を移動、固定、使用しなくなったGameObject等を無効化したほうが効率がよい
How to use Application.LoadLevel() without resetting Input axes? : Unity3D
上記の方法でも確かにInputがリセットされる事はなくなりますが、
非表示にしているテクスチャなどのリソースもメモリ上には存在するので、
ある程度、規模の大きいゲームには向かない方法です。
シーンを移動しない実装方法
- シーンを移動してもInputを継続して受け取りたい。
- けど、上記のように全部マップ(ステージ)作成して切り替えはしたくない。
- かと言って、適宜マップの破棄と生成するのはめんどくさい 。
と言った私におすすめな方法が、
メインシーンとその他のシーンを作成し、 他のシーンのロードとアンロードをするという方法です。
以下の画像がその例で、マップ移動時にシーンが一度破棄されているのが分かると思います。
これならメインシーンは移動していないので、入力が継続して受け取れて、
マップ切り替えの度にマップシーン全体が破棄されるので、
シーン移動している時とほぼ同じような感覚で実装が行えます。
なお、シーンの追加と破棄は以下のようなコードです。
//SceneManagerを使うには using UnityEngine.SceneManagement: が必要 SceneManager.LoadScene("シーン名", LoadSceneMode.Additive);//シーン追加 SceneManager.UnloadScene("シーン名");//シーンの破棄
また、シーンを破棄しても、リソースの破棄はしてくれないらしいので、
UnloadScene後にResources.UnloadUnusedAssetsをした方がいいかもしれません。
SceneManager.UnloadScene("シーン名");
Resources.UnloadUnusedAssets();
さらにシーンを追加後、プログラムから新たにゲームオブジェクトを生成すると、
メインシーンの方に生成されてしまい、マップシーンを破棄した時に一緒に破棄出来なくなるため、
生成したオブジェクトはマップシーン内に最初からいるオブジェクトの子に配置しましょう。
おわりに
現在開発中のピコンティアではマップ移動した時に移動キーを入力しなさなきゃいけない、
という致命的な問題に繋がっていたので、解決できて一安心している今日この頃です(:3っ)∋〜