2Dアクション・テンプレート:入力の対応(仮想化)

=仮想入力クラス=

まずは、キーボードの入力やジョイスティックの入力を抽象化したものを用意する。


今回の2Dアクションで使うのは「左右移動」と「ジャンプ」だけなので、それらが「押されているか」をチェックできるようにしておけばいい。


コードは以下の通り。

//IInput.as
package{
  public class IInput{

    //i_Buttonとして指定するもの(enum欲しい)
    static public const BUTTON_L:int    = 0;
    static public const BUTTON_R:int    = 1;
    static public const BUTTON_JUMP:int = 2;
    static public const BUTTON_NUM:int  = 3;

    //i_Buttonが現在押されているか
    public function IsPress(i_Button:int):Boolean{
      //継承されてなければ、常にfalseを返す
      return false;
    }

    //毎フレーム呼んで、必要なら情報の更新を行う
    public function Update():void{
    }
  }
}


「BUTTON_〜」のところで、「左右移動」や「ジャンプ」などのボタンの種類を設定。


あとは、「押されているか(IsPress)」と「毎フレームの更新(Update)」を用意しておいて、キーボード入力クラスなどの方で実際の処理を作ってもらう。

=キーボード入力クラス=

次に、上の「仮想入力クラス(IInput)」を継承して、「キーボード入力クラス」を作成する。


コードは以下の通り。

//CInput_Keyboard.as
package{
  import flash.display.Stage;
  //Input
  import flash.ui.Keyboard;
  import flash.events.KeyboardEvent;

  public class CInput_Keyboard extends IInput{
    //キーボードの入力を記憶しておく
    private var m_Input:Array;//Boolean[BUTTON_NUM]

    //初期化
    public function CInput_Keyboard(i_Stage:Stage):void{
      //キーボードの入力をOnKeyDownなどで受け取る
      {
        i_Stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
        i_Stage.addEventListener(KeyboardEvent.KEY_UP, OnKeyUp);
      }

      //記憶を初期化
      {
        m_Input = new Array(BUTTON_NUM);
        for(var i:int = 0; i < m_Input.length; i+=1){
          m_Input[i] = false;
        }
      }
    }

    //キーが押されたら、対応する部分をtrueにする
    private function OnKeyDown(event:KeyboardEvent):void{
      switch(event.keyCode){
      case Keyboard.LEFT:  m_Input[BUTTON_L] = true;    break;
      case Keyboard.RIGHT: m_Input[BUTTON_R] = true;    break;
      case Keyboard.UP:    m_Input[BUTTON_JUMP] = true; break;
      case Keyboard.SPACE: m_Input[BUTTON_JUMP] = true; break;
      }
    }
    private function OnKeyUp(event:KeyboardEvent):void{
      switch(event.keyCode){
      case Keyboard.LEFT:  m_Input[BUTTON_L] = false; break;
      case Keyboard.RIGHT: m_Input[BUTTON_R] = false;     break;
      case Keyboard.UP:    m_Input[BUTTON_JUMP] = false;  break;
      case Keyboard.SPACE: m_Input[BUTTON_JUMP] = false  break;
      }
      //「上とスペースを同時押し」→「片方だけ離す」でジャンプがオフになることに注意
    }

    //i_Buttonが現在押されているか
    override public function IsPress(i_Button:int):Boolean{
      return m_Input[i_Button];
    }

//    //毎フレーム呼んで、必要なら情報の更新を行う
//    override public function Update():void{
//    }
  }
}


やっていることは、「キーボードの入力があったら、m_Inputに記憶しておいて、"押されているかチェック"ではそのm_Input」を返す、ということだけ。


初期化時に「入力をOnKeyDownで受け取る」などの処理を追加して、m_Inputを「まだ何も押されていない」という状態にリセット。あとは「ボタンが押された(OnKeyDown)時に、m_Inputをtrueにする」という処理と「ボタンが離された(OnKeyUp)時に、m_Inputをfalseにする」という処理を追加して、IInputから継承した「IsPress」を「m_Inputを返す」という処理に変更した。

=実行確認=


以上のクラスを使い、画像を動かして実行確認を行う。


まずは入力クラスを用意する。

//Input
private var m_Input:IInput;

というメンバを追加し、Initにて

{//Init Input
  m_Input = new CInput_Keyboard(stage);
}

という風に初期化する。


あとは毎回Updateを呼びつつ、IsPressでボタンが押されたかどうかをチェックすればいい。


まずは「毎フレームUpdateという関数を呼んでもらう」ための処理を追加する。

//update
import flash.events.Event;

でイベントをインポートして、Initにて

//毎フレームUpdateを呼ぶ
{
  addEventListener("enterFrame", function(event:Event):void {
    Update();
  });
}

という処理を追加して、Updateを毎回呼ぶようにする。


あとはそのUpdateにて、以下のようにして画像を動かせばいい。

//!毎フレーム更新のために呼ばれる関数
private function Update():void{
  //入力の更新
  m_Input.Update();

  //入力に応じた画像の移動
  if(m_Input.IsPress(IInput.BUTTON_L)){
    m_TestImage.x -= 1;
  }
  if(m_Input.IsPress(IInput.BUTTON_R)){
    m_TestImage.x += 1;
  }
  if(m_Input.IsPress(IInput.BUTTON_JUMP)){
    m_TestImage.y -= 1;
  }
}

ちなみに、m_TestImageには、前回ImageManager.LoadImage_Player()で作った画像が入っているものとする。


以上で、入力の実行確認までできた。来週はようやく物理エンジンに入る。ただ、バージョンが以前とは異なるので、2日に1回くらいの更新頻度になるかもしれない。


一応、現在のデータをActionTemplate1.zipにまとめておいた。(画像はhttp://forever.sakura.ne.jp/index.htmlのものを、抜き色を独自に作って使わせてもらっている)