ActionScript 3.0で始めるオブジェクト指向スクリプティング

第14回キー操作とif以外の条件判定

前回の第13回キーボードによる操作では、上下左右の矢印キーでインスタンスがその方向に1ピクセルずつ動くというナビゲーションを作成した。その前回のスクリプト2に、さらに2つ手を加えてみよう。ひとつは、同時に[shift]キーを押したとき、インスタンスの移動距離を変更する。そしてもうひとつは、キーコードの判定を、ifでなくswitchというステートメントによる処理に書替える。

[shift]キーを押したら移動距離を変える

矢印キーを操作する際、同時に[shit]キーも押した場合、インスタンスの移動距離を10ピクセルにしてみる。これはFlashで[選択ツール]を使い、矢印キーでエレメントを移動するときと同じインターフェイスだ。

[shift]キーを押しているかどうかは、KeyboardEvent.shiftKeyプロパティで調べることができた前回の表1「KeyboardEventオブジェクトの基本的なプロパティ」参照⁠⁠。そこで、前回のスクリプト2におけるInteractiveObject.keyDownイベント(イベント定数KeyboardEvent.KEY_DOWNのリスナー関数xKeyDownにステートメントを加え、次のようにKeyboardEvent.shiftKeyプロパティの値を取出したうえで、関数xMove()の第2引数に渡して呼出すことにする。

stage.addEventListener(KeyboardEvent.KEY_DOWN, xKeyDown);
function xKeyDown(eventObject:KeyboardEvent):void {
  var nKeyCode:int = eventObject.keyCode;
  var bShiftKey:Boolean = eventObject.shiftKey;
  xMove(nKeyCode, bShiftKey);
}

関数xMove()は、第2引数として受取った値がtrueつまり[shift]キーが押されていればインスタンスの移動距離を10に設定し、falseで[shift]キーが押されていない場合には移動距離を1にする。この引数値がtrueかfalseかによって、10または1を返すという処理は、新たに関数xGetPixels()として定義しよう。引数にはブール(論理)値をひとつ渡す。すると、関数xMove()は次のようになる。

function xMove(nKeyCode:int, bShiftKey:Boolean):void {
  if (nKeyCode == Keyboard.LEFT) {
    x -= xGetPixels(bShiftKey);
  } else if (nKeyCode == Keyboard.RIGHT) {
    x += xGetPixels(bShiftKey);
  } else if (nKeyCode == Keyboard.UP) {
    y -= xGetPixels(bShiftKey);
  } else if (nKeyCode == Keyboard.DOWN) {
    y += xGetPixels(bShiftKey);
  }
}

関数xGetPixels()は、引数に渡したブール値がtrueなら10を、falseであれば1を返す。この処理はifステートメントを使って簡単に書くことができるだろう。しかし、今回は条件演算子?:を用いてみたい。条件演算子?:は、以下のシンタックスで記述する。そして、条件の評価がtrueなら式1の値を、falseであれば式2の値を返す。

    条件 ? 式1 : 式2

戻り値は、変数などに代入する。条件に指定する式は、if条件と同じだ。たとえば、Boolean型の変数bShiftKeyが与えられた場合、変数値がtrueなら10、falseのときは1を、int型で宣言した変数nPixelsに代入する式は次のとおりだ。

var nPixels:int = bShiftKey ? 10 : 1;

さて、これで関数xGetPixels()も定義できるだろう。インスタンスを移動する距離は、変数として宣言しておくことにする。nMoveが矢印キーのみのとき、nShiftMoveは[shift]キーを併せた場合の移動ピクセル数だ。以上の修正を加えた、キー操作で動かすインスタンスのフレームアクションは、つぎのスクリプト1とおりだ図1⁠。

スクリプト1 矢印キーで1ピクセル/[shift]キーを加えると10ピクセルずつインスタンスを移動
// MovieClip: キー操作で動かすインスタンス
var nMove:int = 1;
var nShiftMove:int = 10;
stage.addEventListener(KeyboardEvent.KEY_DOWN, xKeyDown);
function xKeyDown(eventObject:KeyboardEvent):void {
  var nKeyCode:int = eventObject.keyCode;
  var bShiftKey:Boolean = eventObject.shiftKey;
  xMove(nKeyCode, bShiftKey);
}
function xMove(nKeyCode:int, bShiftKey:Boolean):void {
  if (nKeyCode == Keyboard.LEFT) {
    x -= xGetPixels(bShiftKey);
  } else if (nKeyCode == Keyboard.RIGHT) {
    x += xGetPixels(bShiftKey);
  } else if (nKeyCode == Keyboard.UP) {
    y -= xGetPixels(bShiftKey);
  } else if (nKeyCode == Keyboard.DOWN) {
    y += xGetPixels(bShiftKey);
  }
}
function xGetPixels(bShiftKey:Boolean):int {
  var nPixels:int = bShiftKey ? nShiftMove : nMove;
  return nPixels;
}
図1 キー操作で動かすインスタンスのフレームアクションに[shift]キーによる動作を追加
図1 キー操作で動かすインスタンスのフレームアクションに[shift]キーによる動作を追加

[ムービープレビュー]で確かめると、矢印キーでは前回と同じく1ピクセルずつ動き、[shift]キーを押しながら矢印キーを操作すれば10ピクセルずつ移動するようになった。上記スクリプト1について、2つ補足しよう。

第1は、関数xMove()内からの関数xGetPixels()の呼出しだ。if/else ifそれぞれのステートメントで、いちいち関数を呼出している。つぎのように関数xMove()本体の最初に呼出して、戻り値をローカル変数[1]に入れた方がスマートではないだろうか。

function xMove(nKeyCode:int, bShiftKey:Boolean):void {
  var nPixels:int = xGetPixels(bShiftKey);
  if (nKeyCode == Keyboard.LEFT) {
    x -= nPixels;
  } else if (nKeyCode == Keyboard.RIGHT) {
    x += nPixels;
  // ...[後略]...

しかし、この流れでは、矢印キーを押さなくても、関数xGetPixels()が呼出されてしまう。確かに、元のスクリプト1では、xGetPixels()の呼出しが4ステートメント記述されている。けれども、1回の呼出しで処理されるのは、押された矢印キーに対応する1ステートメントだけである。それだけではない。矢印キーが押されなければ、関数xGetPixels()が呼出されることもないのだ。よって、スクリプト1の方が無駄は少ないといえる。

第2に、関数xGetPixels()の中で、移動ピクセル数の判定に条件演算子?:を使ったことだ。if/else ifステートメントと比べたメリットは何か。条件演算子?:を使うと、⁠演算子」という名前のとおり、値を返すという処理内容が明らかになる。また、短く記述されて見やすいということたろう。しかし、処理効率には大きな違いはない。if/else ifの方が見やすいと思う読者は、そちらを利用してもとくに差支えはない。

switchステートメント

前掲スクリプト1の関数xMove()におけるifおよびelse if条件は、4つともすべて左辺は関数に渡された第1引数nKeyCodeである。このように一つの式(変数やプロパティを含む)といくつかの式の値を等価比較するときには、switchステートメントを用いて条件判定することができる。シンタックスは、次のとおりだ。

switch (式0) {
  case 式1 :
    ステートメント1;
  case 式2 :
    ステートメント2;
  ...
  case 式N :
    ステートメントN;
  default :
    ステートメントdefault;
}

switch条件に指定された式0(変数やプロパティを含む)を、caseステートメントの式1、式2から式Nまでの値と順に等価比較する。等しいと評価されれば、対応したステートメントが処理される。defaultステートメントはオプション(省略可能)[2]⁠、switch条件がいずれのcaseステートメントの値とも等しくないとき処理される。

switchステートメントで注意しなければならないのは、あるcaseステートメントの値と条件が等しいと評価されたら、そのステートメントだけでなく、以降のcaseステートメントの処理がすべて行われてしまうことだ。たとえば、関数xMove()の処理を水平方向つまりDisplayObject.xプロパティの操作のみ、switchステートメントでつぎのように記述したとする。

function xMove(nKeyCode:int, bShiftKey:Boolean):void {
  switch (nKeyCode) {
    case Keyboard.LEFT :
      x -= xGetPixels(bShiftKey);
    case Keyboard.RIGHT :
      x += xGetPixels(bShiftKey);
  }
}

すると、右矢印キーでインスタンスは右に移動できるものの、左矢印キーではインスタンスが動かない。これは、左矢印キーを押したとき、switch条件の変数nKeyCodeが最初のcaseステートメントの値Keyboard.LEFTと一致して座標が左に動かされても、さらにつぎのcaseステートメントも実行されるので、同じ距離右に移動されて相殺されることになるからだ。

一つのcaseステートメントごとに処理を抜けるには、そのためのステートメントbreakを明示的に記述する必要がある。したがって、前掲のスクリプト1をswitchステートメントで書替えると、つぎのようになるスクリプト2⁠。

スクリプト2 キーコードをswitchステートメントで判定
// MovieClip: キー操作で動かすインスタンス
var nMove:int = 1;
var nShiftMove:int = 10;
stage.addEventListener(KeyboardEvent.KEY_DOWN, xKeyDown);
function xKeyDown(eventObject:KeyboardEvent):void {
  var nKeyCode:int = eventObject.keyCode;
  var bShiftKey:Boolean = eventObject.shiftKey;
  xMove(nKeyCode, bShiftKey);
}
function xMove(nKeyCode:int, bShiftKey:Boolean):void {
  switch (nKeyCode) {
    case Keyboard.LEFT :
      x -= xGetPixels(bShiftKey);
      break;
    case Keyboard.RIGHT :
      x += xGetPixels(bShiftKey);
      break;
    case Keyboard.UP :
      y -= xGetPixels(bShiftKey);
      break;
    case Keyboard.DOWN :
      y += xGetPixels(bShiftKey);
      break;
  }
}
function xGetPixels(bShiftKey:Boolean):int {
  var nPixels:int = bShiftKey ? nShiftMove : nMove;
  return nPixels;
}

caseステートメントの最後、つまり次のcaseステートメントの直前にそれぞれbreakステートメントが記述されている。したがって、一つのcaseステートメントの処理を終えれば、次のcaseステートメントに移らずに、switchステートメントから抜けるのである。なお、最後のcaseステートメントには、厳密にはbreakステートメントは不要だ。しかし、後で処理を追加する可能性もあるので、念のために書き加えてある。

[ムービープレビュー]を確かめると、スクリプト1と同じように、矢印キーで1ピクセル、[shift]キーを加えると10ピクセルずつインスタンスが動く。switchステートメントを使った方が、キーコード(nKeyCode)の値を各caseステートメントの値と比較して処理するという構成が明らかになる。

図2 キーコードの判定をswitchステートメントで書替えたフレームアクション
図2 キーコードの判定をswitchステートメントで書替えたフレームアクション

さて、次回は同じキーボードによる操作を、さらに別の構成で書いてみる。配列(Arrayインスタンス)を使うことにより、条件判定なしに処理する。配列はさまざまに応用できる可能性があるので、ぜひ覚えておきたい。

今回解説した次のサンプルファイルがダウンロードできます。

おすすめ記事

記事・ニュース一覧