【Unity2D】キー入力を保持する配列を作ろう
こんにちは。なおキーヌです。
ブログ毎日更新は310日目になります。
前回「【Unity2D】キー操作を出来るようにしよう」にてキー操作を実装しました。
今回は前回の応用編という事で、キー操作用の配列を作っていきます。
何に使うのかと言うと、斜めに歩くとき最初に押されていた方向を向きながら
移動するようにしたい(ゼルダの伝説神々のトライフォースの移動方式)のでキー入力の保持が必要になります。
他にも同時押しコマンドとかにも応用できます。
キー配列の中に特定のキーが押されていたらソフトリセット何かを実装するのに使えますね。
Unity2DでARPG作成、第3回目始めましょう。
押されたキーを格納するList型の配列を作ろう
イメージ的には押された順番に配列に組み込まれていく感じです。
しかし最初に覚えておいてほしいのは、C#の配列(Array)は一度配列数を決めてしまうと
可変式に配列の要素数を変更できません。
CやC++等厳密な言語をやっている人からすると当然かもしれませんが、
Web系の言語から始めた人にとっては煩わしい仕様です。
そんな人のため?に、C#は様々な形の配列的な仕組みを用意しています。
Dictionary型とList型が用意されています。
今回はList型を使ってキー保持配列を作りましょう。
using System.Collections.Generic;
using System.Linq;
//~~~~クラス表記省略
private List<KeyCode> PushedArrowKeyList = new List<KeyCode>();
ちょっと長いので説明します。
まずList型を使うにはソースの最初にusingで「System.Collections.Generic」宣言が必要になります。
後はList型をソートやらサーチやらを楽にしてくれるLinqという仕組みを使うために「System.Linq」も宣言しておきましょう。
これは無くても大丈夫なのですが、あった方がリスト操作処理を楽に書けます。
そしてクラス宣言の直下、vxとかvyとかある変数と同じ場所(つまりクラス変数)にprivateでList型の変数を作ります。
「List<データの型>」という感じで型を宣言します。
可変式の配列風の仕組みではありますが、型が違うものは入れることはできません。
JavaScriptであればintもstringも関係なく入れられていましたが
あっちが特別何だと覚えておきましょう。
基本的なプログラミング言語は違う型が織り交ざる配列は基本NGです。
そして変数名を付けてイコールでList型のKeyCodeを格納するための空のインスタンスを作成します。
後はaddメソッドとかを使って配列に格納していきましょう。
配列へのアクセスは変数名[要素数]と、普通の配列と同じ感じで扱えます。
【C#知識】Dictionary型とList型について
Dictionary型はその名の通り辞書なのでKeyとValueの概念があります。
JavaScriptでいう連想配列とかjsonオブジェクトみたいな感じですね。
一方List型は、基本の方(intやstring)を指定したリストを扱えるようになります。
大きさも可変式でWeb系言語で使っていた配列の仕組みに似ています。
ゲームでは可変式の配列の方が取り回ししやすいので、
数が変わらない時以外は基本的にListを使っておくと楽かもしれません。
メモリを極限まで節約したいという人は普通の配列でいいかと思います。
個人で開発する分には今の時代そこまで気にする必要も無いですね。
押されたキーをList型の配列に格納しよう
List型の変数を作ったので、さっそく使っていきましょう。
基本的に押されている間だけ配列に格納され、離されたら配列から消すという仕組みにします。
// キーのリスト入れ替え関数
private void KeyAddRemove(KeyCode keycode) {
if (Input.GetKey(keycode)) {
// Linqの機能:リストに指定物が中身になければリストに加える
if (!(PushedArrowKeyList.Contains(keycode))) {
// あれば削除
PushedArrowKeyList.Add(keycode);
}
} else {
// Linqの機能:リストに指定物が中身にあればリストにから外す
if (PushedArrowKeyList.Contains(keycode)) {
// あれば削除
PushedArrowKeyList.Remove(keycode);
}
}
}
KeyAddRemoveという関数を作り、引数にKeyCodeを取ります。
渡されたキーに対して押されていた場合、キー保持配列に押されているキーが存在するかをLinqを使って調べます。
入っていれば何もしませんし、入っていなければキー配列に組み込みます。
そして渡されたキーに対して押されていなかった場合、キー保持配列を見て含まれていたら配列から消し、無ければ何もしません。
という関数です。
この関数は使用するキーコード全てに適用します。
// キーチェック関数
private void KeyCheck() {
KeyAddRemove(KeyCode.LeftArrow);
KeyAddRemove(KeyCode.RightArrow);
KeyAddRemove(KeyCode.UpArrow);
KeyAddRemove(KeyCode.DownArrow);
}
ループ処理でスッキリ書いてもいいですが、個人的にはコチラの方が管理しやすいかなと思います。
監視するボタンが確定したらキーコード配列を作ってそれを回して処理するとコードがスッキリします。
とりあえず現状は4方向キーのみなのでこれでいきましょう。
後はキー配列を見てプレイヤーを動かす処理に書き替えてやればOKです。
キー保持配列を監視してプレイヤーを移動させよう
現在、update関数のところに移動処理を書いていますが基本的には直接的な処理を書かない方がいいです。
updateに直接書いても問題はないですが、処理が増えてくると見通しが悪くなってくるので基本的に処理に1つの塊がある場合、
関数化しておくとメンテナンス性も向上しますので今のうちに関数化する癖をつけておきましょう。
void Update()
{
// 毎フレーム数値を初期化
vx = 0;
vy = 0;
// キャラクター移動
CharaMove();
}
updateを先に書いておくとこんなにスッキリしました。
vxとvyもCharaMoveに埋め込んでも良かったのですがまだどうするか決めていないので一旦外に出しています。
続いてCharaMove関数を作っていきましょう。
// キャラクター移動
private void CharaMove() {
// キーチェック
KeyCheck();
// プレイヤーの移動
PlayerMove();
}
これもシンプルですね。
先ほど作ったKeyCheck関数を呼び出し、その後に新たなPlayerMove関数を呼び出しています。
更に続いてPlayerMove関数を作りましょう。
private void PlayerMove() {
if (PushedArrowKeyList.Count > 0) {
// 最初に押されているキーの方向に移動
switch (PushedArrowKeyList[0]) {
case KeyCode.LeftArrow:
vx = -speed;
break;
case KeyCode.RightArrow:
vx = speed;
break;
case KeyCode.UpArrow:
vy = speed;
break;
case KeyCode.DownArrow:
vy = -speed;
break;
default:
break;
}
// 実際の移動処理
this.transform.Translate(vx/50, vy/50, 0);
}
}
ここが移動処理のメイン部分です。
現状は最初に作ったキー保持配列の0個目の要素を見て、
switchで該当するキーコードの処理に切り分けています。
これで実行してみると、4方向にしか移動出来ない事がわかります。
当然ですね。
swtichで1つの処理しか行えてないので、毎回vxとvyが初期化されるため1方向にしか動けません。
次回は8方向に動けるようにこの処理を改良してみましょう。
やり方をネタバレしておくとキー保持配列の0個目がキーコードが上下であれば、
1個目のキーコードが左右かを見てvyの加減算をきめるだけです。
次回に行くまでに各自で実装してみてください。
自力で考えてやることによって深く記憶に刻み込まれます。
それでは。