ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【RPG(ロールプレイングゲーム)篇】 戦闘シーンの「攻撃」コマンドで複数の中なら一体の敵キャラを選択する(戦闘突入直前まで)

enchant.js
enchant.js / Ubiquitous Entertainment Inc.

 ”ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【RPG(ロールプレイングゲーム)篇】 戦闘シーンに複数の敵キャラを表示する”の記事で敵キャラも複数表示できるようになったし、”ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【RPG(ロールプレイングゲーム)篇】 戦闘シーンに戦闘用コマンド一覧(攻撃/特技/道具/防御/逃走)を表示する”の記事で戦闘用のコマンドも表示したし、今度は「攻撃」コマンドで対象の敵キャラを選択するところまでを実現してみよう。戦闘にはまだ突入しないぞ。その直前までだ。

■敵キャラ選択時のエフェクトを考える

 敵キャラを選択する際の視覚的なエフェクトを考えてみよう。

 選択といっても攻撃対象の「確定」ではなく、どれにしようかな~と選んでいるときの、敵キャラにフォーカスが当たっているときのエフェクトだ。まず、完成時のキャプチャを見てほしい。

enchant141

  1.フォーカスした敵の頭上に「target!」と橙色で表示する
  2.フォーカスした敵を半透明にする

 というエフェクトに今回はしてみた。どうだろう? スキル(技・魔法)の実現の際に、敵キャラを「モノクロ」や「セピア」へ色を変更しようと考えているが、その方法はまた別の機会に解説する。

 今回はエフェクトをどうやって持たせるか、が焦点なので、まず、どの敵キャラを選択しているか、というのを示す関数を用意した。以下の「enemyGroup.select = function( index )」(168行目)だ。

[javascript firstline=”161″ highlight=”165,166,167,168,178,179,180,191,192,193,194,198,199,200,201,205,206,207,208″ title=”battle.js – function createEnemyGroup( areaInfo )”]
enemyGroup.x = (BATTLE_SCREEN_WIDTH – enemyGroup.width) / 2; // グループを画面のセンターへ配置.
enemyGroup.total = enemyGroup.childNodes.length; // 敵キャラの総数を設定.
enemyGroup._selectIndex = 0; // 敵キャラの初期選択位置.

/**
* 敵キャラを選択する関数.
*/
enemyGroup.select = function( index ) {
enemyGroup.childNodes[ enemyGroup._selectIndex ].opacity = 1.0; // 通常表示に戻す.
if ( enemyGroup.total < enemyGroup.childNodes.length ) { // "target!"が表示されている場合は消す.
enemyGroup.removeChild( enemyGroup.childNodes[ enemyGroup.childNodes.length – 1 ] );
}
if ( 0 > index ) {
index = enemyGroup.childNodes.length – 1; // 左端から右端へ.
} else if ( (enemyGroup.childNodes.length – 1) < index ) {
index = 0; // 右端から左端へ.
}
enemyGroup._selectIndex = index; // 敵キャラの選択位置を更新.
enemyGroup.childNodes[ enemyGroup._selectIndex ].opacity = 0.5; // 選択表示に変更(半透明).
var attackLabel = new Label( "target!" ); // "target!"を頭に表示する.
attackLabel.font = "20px PixelMplus10";
attackLabel.color = ‘#ff6501’;
attackLabel.x = enemyGroup.childNodes[ index ].x – 16;
attackLabel.y = enemyGroup.childNodes[ index ].y – 32;
attackLabel.width = enemyGroup.childNodes[ index ].width + 32;
attackLabel.textAlign = "center";
enemyGroup.addChild( attackLabel ); // グループに追加.
return enemyGroup._selectIndex;
}

/**
* 次の敵キャラを選択する関数.
*/
enemyGroup.selectNext = function() {
return enemyGroup.select( enemyGroup._selectIndex + 1 );
}

/**
* 前の敵キャラを選択する関数.
*/
enemyGroup.selectPrev = function() {
return enemyGroup.select( enemyGroup._selectIndex – 1 );
}

/**
* 敵キャラの選択をキャンセルする関数.
*/
enemyGroup.selectCancel = function() {
enemyGroup.childNodes[ enemyGroup._selectIndex ].opacity = 1.0; // 通常表示に戻す.
if ( enemyGroup.total < enemyGroup.childNodes.length ) { // "target!"が表示されている場合は消す.
enemyGroup.removeChild( enemyGroup.childNodes[ enemyGroup.childNodes.length – 1 ] );
}
return enemyGroup._selectIndex;
}

return enemyGroup;
}
[/javascript]

 引数で要求した敵キャラへのフォーカス位置を「enemyGroup._selectIndex」(178行目)で記憶するようにして、その位置に対して、Labelで「target!」と表示するのと(180行目)、「opacity」で半透明を実現している(179行目)。

 選択をやめる、キャンセルする場合は「enemyGroup.selectCancel = function()」(208行目)をコールすることで半透明を元に戻すのと、LabelをremoveChildで削除する。

 左右キーで次へ次へフォーカスを移動するのにいちいち選択関数の引数にindexを渡すのは面倒なので、そんな時は「enemyGroup.selectNext = function()」(194行目)、「enemyGroup.selectPrev = function()」(201行目)の関数で実現する。右キーを押下されたら前者をコールして、左キーを押下されたら後者をコールする。呼び出し元は単純になると思う。

■バトル状態を定義してコマンド選択でバトル状態を切り替える

 「コマンド入力」とか「特技選択中」とか「道具選択中」とか、制御を切り替える単位となるこれらを「バトル状態」として定義して、制御を分かり易くしていく。ひとまずは以下があれば足りるだろう。

[javascript firstline=”12″ highlight=”” title=”battle.js”]
/**
* バトル状態.
*/
var BATTLE_STATE = {
COMMAND_INPUT: 0, // コマンド入力中.
ATTACK_TARGET_SELECT: 1, // 攻撃対象選択中.
SKILL_SELECT: 2, // 特技選択中.
ITEM_SELECT: 3, // 道具選択中.
}
[/javascript]

 あとは「Aボタン」を押下する毎に、この「バトル状態」を切り替えていく。

 以下は「攻撃」「特技」「道具」「防御」「逃走」にカーソルを当てた状態で「Aボタン」を押下した場合の制御だ。「攻撃」以外は今回の記事ではまだ制御を行わないので、メッセージを表示するようにしている。コマンド入力中のプレイヤーの名前を表示するのも解説は別途とする。

 前述した敵キャラ選択の関数をコールして(293行目)、選択したキャラをメッセージウィンドウに表示している(294行目)。

[javascript firstline=”287″ highlight=”289,290,291,292,293,294,295,296,297,298,299,300,301,302,303″ title=”main.js – function createScene()”]
// Aボタン押下(DOWN)リスナー.
scene.onabuttondown = function() {
switch ( scene.state ) { // バトル状態に応じて処理を分ける.
case BATTLE_STATE.COMMAND_INPUT: // バトル状態が「コマンド入力中」.
if ( true == cmd1.isHighlight() ) { // 「攻撃」.
scene.state = BATTLE_STATE.ATTACK_TARGET_SELECT; // バトル状態を「攻撃対象選択中」へ変更.
var i = enemyGroup.select( 0 ); // 左端の敵キャラを選択要求.
msg.setText( enemyGroup.childNodes[ i ].getName(), "" ); // 選択された敵キャラの名前をメッセージに表示.
} else if ( true == cmd2.isHighlight() ) { // 「特技」.
msg.setText( "は", "戦闘中の特技を覚えていない!" );
} else if ( true == cmd3.isHighlight() ) { // 「道具」.
msg.setText( "は", "道具を持っていない!" );
} else if ( true == cmd4.isHighlight() ) { // 「防御」.
msg.setText( "は", "防御できない!" );
} else if ( true == cmd5.isHighlight() ) { // 「逃走」.
msg.setText( "は", "逃走できない!" );
}
break;
default:
break;
}
}
[/javascript]

enchant141
enchant144
enchant145
enchant147
enchant146

 以下は「Bボタン」押下時の制御だ。バトル状態を「攻撃対象選択中」から「コマンド入力中」へ戻している。そして必要なくなったメッセージウィンドウを非表示にしている。

[javascript firstline=”310″ highlight=”312,313,314,315,316,317,318,319,320″ title=”main.js – function createScene()”]
// Bボタン押下(DOWN)リスナー.
scene.onbbuttondown = function() {
switch ( scene.state ) { // バトル状態に応じて処理を分ける.
case BATTLE_STATE.ATTACK_TARGET_SELECT: // バトル状態が「攻撃対象選択中」.
scene.state = BATTLE_STATE.COMMAND_INPUT; // バトル状態を「コマンド入力中」へ戻す.
enemyGroup.selectCancel(); // 敵キャラの選択をキャンセル.
msg.setVisible( false ); // メッセージウィンドウを非表示にする.
break;
default:
break;
}
}

scene.state = BATTLE_STATE.COMMAND_INPUT;

// 作成したシーンを返却.
return scene;
}
[/javascript]

 メッセージウィンドウを非表示にする為に「MessageWindow.visible = false;」としても効果はない。Groupクラスにvisibleは存在しないからだ。なので、「setVisible()」という関数を以下のように自作している(404行目)。

[javascript firstline=”382″ highlight=”404,405,406,407,408″ title=”main.js – var MessageWindow = enchant.Class.create( enchant.Group, {“]
setText: function( text1, text2 ) {
this.autoText.length = 0;
this.childNodes[ 1 ].text = text1; // メッセージ文字列の更新.
this.childNodes[ 2 ].text = text2; // メッセージ文字列の更新.
this.setVisible( true );
},
setAutoText: function( text1, text2 ) {
this.autoText.push( [ text1, text2 ] ); // 自動送り用メッセージに登録.
},
startAutoText: function() {
this._showAutoText( this ); // 自動送り用メッセージの表示.
this.setVisible( true );
},
_showAutoText: function( me ) {
if ( 0 == me.autoText.length ) { // 自動送り用メッセージが無くなったら終了.
return;
}
var at = me.autoText.shift(); // 自動送り用メッセージの取得.
me.childNodes[ 1 ].text = at[ 0 ]; // メッセージ文字列の更新.
me.childNodes[ 2 ].text = at[ 1 ]; // メッセージ文字列の更新.
setTimeout( me._showAutoText, 400, me ); // 400msでメッセージを自動送り.
},
setVisible: function( visible ) {
this.childNodes[ 0 ].visible = visible;
this.childNodes[ 1 ].visible = visible;
this.childNodes[ 2 ].visible = visible;
}
});
[/javascript]
enchant143

■左右キーで敵キャラを選択する場合

 不要かな~と思ったが、左右キーで選択する敵キャラを切り替える実装も、念の為、載せておく。

[javascript firstline=”244″ highlight=”265,266,267,268,295,296,297,298″ title=”main.js – function createScene()”]
// 右キー押下(DOWN)リスナー.
scene.onrightbuttondown = function() {
switch ( scene.state ) {
case BATTLE_STATE.COMMAND_INPUT:
if ( true == cmd1.isHighlight() ) {
cmd1.setHighlight( false );
cmd2.setHighlight( true );
} else if ( true == cmd2.isHighlight() ) {
cmd2.setHighlight( false );
cmd3.setHighlight( true );
} else if ( true == cmd3.isHighlight() ) {
cmd3.setHighlight( false );
cmd4.setHighlight( true );
} else if ( true == cmd4.isHighlight() ) {
cmd4.setHighlight( false );
cmd5.setHighlight( true );
} else if ( true == cmd5.isHighlight() ) {
cmd5.setHighlight( false );
cmd1.setHighlight( true );
}
break;
case BATTLE_STATE.ATTACK_TARGET_SELECT:
var i = enemyGroup.selectNext();
msg.setText( enemyGroup.childNodes[ i ].getName(), "" );
break;
default:
break;
}
}

// 左キー押下(DOWN)リスナー.
scene.onleftbuttondown = function() {
switch ( scene.state ) {
case BATTLE_STATE.COMMAND_INPUT:
if ( true == cmd1.isHighlight() ) {
cmd1.setHighlight( false );
cmd5.setHighlight( true );
} else if ( true == cmd2.isHighlight() ) {
cmd2.setHighlight( false );
cmd1.setHighlight( true );
} else if ( true == cmd3.isHighlight() ) {
cmd3.setHighlight( false );
cmd2.setHighlight( true );
} else if ( true == cmd4.isHighlight() ) {
cmd4.setHighlight( false );
cmd3.setHighlight( true );
} else if ( true == cmd5.isHighlight() ) {
cmd5.setHighlight( false );
cmd4.setHighlight( true );
}
break;
case BATTLE_STATE.ATTACK_TARGET_SELECT:
var i = enemyGroup.selectPrev();
msg.setText( enemyGroup.childNodes[ i ].getName(), "" );
break;
default:
break;
}
}
[/javascript]
enchant142

(アシベズヘア@ashibehair_m

╋ 関連記事 ━━━

  • ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【RPG(ロールプレイングゲーム)篇】 戦闘シーンにバーチャルボタン(Aボタン/Bボタン/Xボタン/Yボタン)を表示する
  • ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【RPG(ロールプレイングゲーム)篇】 戦闘シーンに表示するメッセージを自動送りできるようにする
  • ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【RPG(ロールプレイングゲーム)篇】 文字列に「8bitファミコン風のWEBフォント(漢字も使える!フリー!)」を採用する
  • ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【RPG(ロールプレイングゲーム)篇】 戦闘シーンにステータスゲージ(HPゲージ)を表示する
  • ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【RPG(ロールプレイングゲーム)篇】 戦闘シーンにステータスウィンドウ(状態表示枠)を表示する
  • ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【RPG(ロールプレイングゲーム)篇】 戦闘シーンに切り替える
  • ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【導入篇】 バーチャルボタン(Aボタン/Bボタン/Xボタン/Yボタン)を表示してみる
  • ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【導入篇】 キャラクター画像をバーチャルパッド(十字方向キーパッド)で動かしてみる
  • ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【導入篇】 キャラクター画像を表示してみる
  • ゲーム開発をenchant.js(HTML5 + JavaScript)で! 【導入篇】 enchant.jsのダウンロードと開発準備
  • コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です