こんにちは!布浦です。
Unity2D企画、6回目です。
今日は、
「6. キー操作によるキャラクターの移動を実装する(Physics2Dスクリプト編その2)」
をやっていきたいと思います。
今回でサンプル完成です!
- 画像をSpriteとして画面に配置する
- Spriteにコマアニメを設定する(Animation View の使い方)
- 複数のアニメを切り替える仕組みをつくる(Mecanim)
- 2D物理エンジンでキャラクターを動かす(Physics2D設定編)
- 地面に当たったかどうかを判定する(Physics2Dスクリプト編その1)
- キー操作によるキャラクターの移動を実装する(Physics2Dスクリプト編その2)
物理演算が適用されたオブジェクトをプログラムで動かす
キャラクターは物理演算で動いているので、単純に座標を移動させてしまうと、
物理演算による衝突判定などの動きと噛み合なくなります。
不自然な動きになったり、当たり抜けが発生したりします。
void Update () { Vector2 pos = (Vector2)transform.position + Vector2.right; transform.position = pos; }

物理演算で本来壁に衝突するところを、無理にプログラムで座標を動かすとめり込んだりする
そこで使うのが、AddForceという関数です。
物理演算が適用されている物体に対して、力を加えることができます。
例えば、「キャラクターに右方向の力を加える」というコードは以下のようになります。
力を加えた結果の動きは物理シミュレーションによるものなので、
カベなどとの衝突判定も動きます。
void FixedUpdate () { rigidbody2D.AddForce(Vector2.right * 10); }

壁で止まる
UpdateとFixedUpdate
Unityでは、描画の更新が行われるUpdateと、物理シミュレーションの更新が行われるFixedUpdateという2つのUpdate関数があります。
AddForceのように、物理シミュレーションによる物体の動きに作用するような処理はFixedUpdate関数内に書きます。
void Update () { /*下記以外の処理*/ } void FixedUpdate () { /*物理演算による物体の動きに作用するような処理*/ }
矢印キーの入力を取得する
今回は、矢印キーによる移動(左右キーで移動、上キーで飛ぶ)を実装します。
矢印キーの入力具合は、Input.GetAxis という関数で取得できます。
縦方向と横方向の入力に対して、-1~1という扱いやすい数値で取得できるので、
これをつかって、力を加える方向をコントロールします。
Kotori.csに、下記のコードを追記します。
void FixedUpdate() { //左右キーの入力 float h = Input.GetAxis("Horizontal"); //上下キーの入力 float v = Input.GetAxis("Vertical"); //左右キーの入力にあわせて、横方向の力を加える(歩く) rigidbody2D.AddForce(Vector2.right * h * 30f); //もし、上キーの入力だったら(下キーは無視する) if(v > 0) { //上方向の力を加える(飛ぶ) rigidbody2D.AddForce(Vector2.up * v * 50f); } }
何もキーを押してない状態では、Input.GetAxisが0を返すので、何も力を加えないということになります。
物理シミュレーションなので、急に停止するのではなく、デフォルトで設定されている摩擦によって減速して止まります。
自然な動きが少ないコードで実装できるので便利です。
再生して、動かせるか確認しましょう。

画面上を動き回れるようになったことり
速度に上限を設定する
キャラクターがキー操作に合わせて動くようになりました。
もう少し、自然な動きになるように工夫したいと思います。
AddForceは文字通り力を加えて物体を動かす関数ですが、
単純に繰り返しAddForceを使うと、
力を加え続けることになるので、物体はどんどん加速します。
キーを押しっぱなしにしているとき、加速をするのはいいのですが、
上限なく加速し続けると操作しづらくなってしまいます。

velocityを出力してみると、速度が上がり続けるのがわかる
これを解決するために、制限速度をつくります。
– 制限速度を超えているときはAddForceを行わない
– 制限速度を超えているときは速度を制限速度に合わせる
この2つの処理を追加したコードが以下です。
各種パラメータは、GUI上で調整できるようにしました。
しっくりくる操作感になるように、調節してみてください。
//publicなグローバル変数にしておくとGUI上で調整できる public float walkForce = 30f; public float flyForce = 50f; public float maxWalkSpeed = 3f; public float maxFlySpeed = 5f; void FixedUpdate() { float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); //制限速度以下だったら、という条件を追加 if(rigidbody2D.velocity.x < maxWalkSpeed) { rigidbody2D.AddForce(Vector2.right * h * walkForce); } //制限速度以下だったら、という条件を追加 if(v > 0 && rigidbody2D.velocity.y < maxFlySpeed) { rigidbody2D.AddForce(Vector2.up * v * flyForce); } //制限速度より大きかったら if(Mathf.Abs(rigidbody2D.velocity.x) > maxWalkSpeed) { //自分の速度を制限速度に合わせる //飛ぶ動きは、重力がかかって勝手に減速するので、そのまま //Mathf.Sign -> 値の符号を取得 rigidbody2D.velocity = new Vector2( Mathf.Sign(rigidbody2D.velocity.x) * maxWalkSpeed, rigidbody2D.velocity.y ); } }
進む方向に合わせてSpriteを反転する
キャラクターは、色々な方向に動けるようになりました。
右に進んでいるときは右、左を進んでいるときは左を向くようにします。
Spriteの反転ですが、Sprite はtransform のscale値が適用されるので、localScale.xを移動方向に合わせて変更します。
//右を向いているかどうか(初期値はtrue) private bool facingRight = true; void FixedUpdate() { /* ... */ float h = Input.GetAxis("Horizontal"); //右を向いていて、左の入力があったとき、もしくは左を向いていて、右の入力があったとき if((h > 0 && !facingRight) || (h < 0 && facingRight)) { //右を向いているかどうかを、入力方向をみて決める facingRight = (h > 0); //localScale.xを、右を向いているかどうかで更新する transform.localScale = new Vector3((facingRight ? 1 : -1), 1, 1); } }
再生して、操作してみましょう!移動方向に合わせて、向きが切り替わるはずです。
あとは、適当にCubeなどを置いて、ステージをつくってみてください。
3Dも
そういえば今回、ちょっと手抜きをして壁などをCubeでつくりましたが、カメラを切り替えると・・・
あっという間に、ステージだけ3Dに!これはこれで、いいかも。
(背景色は、Cameraの「Background」というプロパティで変えられます。)
Unityの2Dは、3Dとコードの違いもあまりなく、2つを簡単に混ぜることができるので、色々な表現が考えられて楽しいです。
記事は全6回と結構多くなってしまいましたが、コード自体は少ないので、
ここまで、慣れれば2〜3時間程度でできてしまうと思います。
サンプルのプロジェクトはこちらからダウンロードできます。
また、今回のサンプルはAssetStoreで公式で配布されているチュートリアルプロジェクト「2DPlatformer」を参考に制作しました。
一般的なジャンプの処理など(ことりは飛べるようにしてしまったので・・・)をつくりたい、という方は参考にしてみてください。
2Dのワークフローを紹介している、こちらも公式の、動画もあります。(日本語字幕つき!)
年明けから、Unity講座第5期が開講されます。
「書籍やWeb上の情報だけではわからないことが多い」「1からしっかり勉強したい」という方におすすめです。
受講生募集中です!詳しくはこちら↓