/* JavaScript版RPGイベント戦闘処理 2010-12-31 創作プログラミングの街 */ KEYFLAG_SELECT = 1; KEYFLAG_UP = 2; KEYFLAG_DOWN = 4; KEYFLAG_LEFT = 8; KEYFLAG_RIGHT = 16; // メッセージ表示ウインドウクラス var MessageWindow = function() { // 表示位置 var x, y; // 表示サイズ var width, height; // 枠の太さ var borderWidth; // テキスト領域の幅 var drawWidth; // テキスト領域の高さ var drawHeight; // テキスト領域左上端座標 var drawX, drawY; // テキスト領域余白 var textPadding; // テキスト var pages = null; // フォント var font; // 行の高さ var lineHeight; var lineNum; // ウインドウ状態 var status; var STATUS_NONE; var STATUS_PUTTING; var STATUS_PAGEWAIT; var STATUS_EXITWAIT; // 表示中情報 var drawingPage; var drawingLine; var drawingChar; // キー解放待機フラグ var keyWait; // 処理時間カウント var actionCount; // 表示フラグ var display; // 初期化 this.init = function() { // フォントに等幅14ピクセルを指定 this.font = "14px monospace"; // 行高さ設定 this.lineHeight = 16; // ウインドウ枠幅設定 this.borderWidth = 1; // テキスト領域余白設定 this.textPadding = 2; this.drawingPage = 0; this.drawingLine = 0; this.drawingChar = 0; this.STATUS_NONE = 0; this.STATUS_PUTTING = 1; this.STATUS_PAGEWAIT = 2; this.STATUS_EXITWAIT = 3; this.STATUS_EXIT = 4; this.status = this.STATUS_NONE; this.actionCount = 0; this.keyWait = false; this.display = false; } // Canvas上表示位置設定 this.setPosition = function(x, y) { // ウインドウ描画位置設定 this.x = x; this.y = y; // テキスト描画位置設定 this.drawX = x + this.borderWidth + this.textPadding; this.drawY = y + this.borderWidth + this.textPadding; } // ウインドウサイズ設定 this.setSize = function(w, h) { this.width = w; this.height = h; // テキスト領域描画幅算出 this.drawWidth = w - (this.borderWidth + this.textPadding) * 2; // テキスト領域高さ算出 this.drawHeight = h - (this.borderWidth + this.textPadding) * 2; // テキスト領域の描画可能行数算出 this.lineNum = Math.floor(this.drawHeight / this.lineHeight); } // 表示テキスト設定 this.setText = function(text, context) { context.font = this.font; this.pages = new Array(); if (text == null || text.length < 1) { return; } var i = 0 var line = ''; var pos = 0; var lines = new Array(); // テキスト描画領域の横幅に合わせて各行のテキスト作成 while (pos < text.length) { var pageFlag = false; // 改行指定が入るか横幅がテキスト領域を超えるまで文字追加 while (pos < text.length && context.measureText(line + text.charAt(pos)).width < this.drawWidth) { // <:br>タグなら改行し現在位置をタグの次の文字へ if (text.indexOf('<:br>', pos) == pos) { pos += 5; break; } // <:page>タグなら改ページ記号を挿入 if (text.indexOf('<:page>', pos) == pos) { pos += 7; pageFlag = true; break; } line = line + text.charAt(pos++); } // 文字列を追加 lines.push(line); if (pageFlag) { lines.push("\f"); } line = ''; } var lineIndex = 0; do { // ページ毎のテキスト行配列作成 var pageLines = new Array(); // 最終ページ if ((lines.length - lineIndex) <= this.lineNum) { for (i = lineIndex;i < lines.length;i++) { pageLines.push(lines[i]); } lineIndex = lines.length; } else { var pageLineIndex = 0; while ((lineIndex < lines.length) && (pageLineIndex++ < (this.lineNum - 1))) { if (lines[lineIndex].charAt(0) == "\f") { lineIndex++; break; } pageLines.push(lines[lineIndex]); lineIndex++; } } if (pageLines.length > 0) { this.pages.push(pageLines); } } while (lineIndex < lines.length); } // 表示 this.show = function() { // 表示フラグをセット this.display = true; // 表示状態を初期化 this.drawingPage = 0; this.drawingLine = 0; this.drawingChar = 0; this.status = this.STATUS_PUTTING; this.keyWait = false; } // 非表示 this.hide = function() { // 表示フラグをリセット this.display = false; } // 描画 this.draw = function(context) { if (!this.display) { return; } // ウインドウ領域全体を白でクリア context.fillStyle = '#ffffff'; context.fillRect(this.x, this.y, this.width, this.height); // 枠を残して黒でクリア context.fillStyle = '#000000'; context.fillRect(this.x + this.borderWidth, this.y + this.borderWidth, this.width - this.borderWidth * 2, this.height - this.borderWidth * 2); // テキスト描画設定 context.font = this.font; context.fillStyle = '#ffffff'; context.textBaseline = 'top'; if (this.pages == null || this.pages.length < 1) { return; } var i; // 各行のテキストを描画 for (i = 0;i < this.drawingLine;i++) { if (this.pages[this.drawingPage][i]) { context.fillText(this.pages[this.drawingPage][i], this.drawX, this.drawY + i * this.lineHeight); } } if (this.pages[this.drawingPage][this.drawingLine]) { context.fillText(this.pages[this.drawingPage][this.drawingLine].substring(0, this.drawingChar), this.drawX, this.drawY + i * this.lineHeight); } // ページ表示完了時に次ページがあれば次ページ案内を表示 if (this.status == this.STATUS_PAGEWAIT && (this.actionCount % 20) > 10) { context.beginPath(); // ウインドウ下部に三角形のパスを設定 context.moveTo(this.drawX + (this.drawWidth / 2) - 6, 2 + this.drawY + (this.lineNum - 1) * this.lineHeight); context.lineTo(this.drawX + (this.drawWidth / 2) + 6, 2 + this.drawY + (this.lineNum - 1) * this.lineHeight); context.lineTo(this.drawX + (this.drawWidth / 2), 14 + this.drawY + (this.lineNum - 1) * this.lineHeight); context.closePath(); context.fillStyle = '#ffffff'; // 設定したパスを塗りつぶす context.fill(); } } this.action = function(key) { this.actionCount++; if (this.pages == null || this.pages.length < 1) { return false; } // キー解放待機中なら戻る if (this.keyWait) { if (key == 0) { this.keyWait = false; } else { return true; } } switch (this.status) { // 文字表示中 case this.STATUS_PUTTING: this.drawingChar++; // キーが押されたらページ最後まで一気に表示 if (key == 1) { this.drawingChar = this.pages[this.drawingPage][this.drawingLine].length - 1; this.drawingLine = this.pages[this.drawingPage].length - 1; this.keyWait = true; return true; } if (!this.pages[this.drawingPage]) { this.status = this.STATUS_PAGEWAIT; drawingPage++; } else { // 行の最後まで表示したら次の行/ページ、または終了待機へ if (this.pages[this.drawingPage][this.drawingLine].length < this.drawingChar) { // ページ全体の表示が終わったら次ページ遷移/終了待機 if (this.drawingLine == this.pages[this.drawingPage].length - 1) { if (this.drawingPage == this.pages.length - 1) { this.status = this.STATUS_EXITWAIT; } else { this.status = this.STATUS_PAGEWAIT; } } else { // 表示対象を次の行へ this.drawingLine++; // 描画文字位置を行頭へ this.drawingChar = 0; } } } break; // 次ページ待機中 case this.STATUS_PAGEWAIT: // キーが押されたら次ページへ if (key == 1) { this.drawingPage++; this.drawingLine = 0; this.drawingChar = 0; this.status = this.STATUS_PUTTING; this.keyWait = true; } break; // 終了待機 case this.STATUS_EXITWAIT: // キーが押されたら非表示に if (key == 1) { this.status = this.STATUS_EXIT; return false; } break; } return true; } // テキスト全体の表示が終わったか? this.isTextEnd = function() { if (this.status == this.STATUS_PUTTING || this.status == this.STATUS_PAGEWAIT) { return false; } return true; } // 表示終了状態か? this.isTextEnd = function() { return this.status == this.STATUS_EXIT; } } // 選択ダイアログクラス var SelectDialog = function() { // 表示位置 var x, y; // 表示サイズ var width, height; // 枠の太さ var borderWidth; // テキスト領域の幅 var drawWidth; // テキスト領域の高さ var drawHeight; // テキスト領域左上端座標 var drawX, drawY; // テキスト領域余白 var textPadding; // 選択肢 var items = null; // フォント var font; // 行の高さ var lineHeight; // ウインドウ状態 var status; var STATUS_NONE; var STATUS_SELECTED; // キー解放待機フラグ var upKeyWait; var downKeyWait; // 表示フラグ var display; // カーソル位置 var index; // 初期化 this.init = function() { // フォントに等幅14ピクセルを指定 this.font = "14px monospace"; // 行高さ設定 this.lineHeight = 18; // ウインドウ枠幅設定 this.borderWidth = 1; // テキスト領域余白設定 this.textPadding = 2; this.STATUS_NONE = 0; this.STATUS_SELECTED = 1; this.status = this.STATUS_NONE; this.upKeyWait = 0; this.downKeyWait = 0; this.display = false; this.index = 0; this.setPosition(0, 0); } this.reset = function() { this.status = this.STATUS_NONE; this.upKeyWait = 0; this.downKeyWait = 0; this.index = 0; } // Canvas上表示位置設定 this.setPosition = function(x, y) { // ウインドウ描画位置設定 this.x = x; this.y = y; // テキスト描画位置設定 this.drawX = x + this.borderWidth + this.textPadding; this.drawY = y + this.borderWidth + this.textPadding; } // ウインドウサイズ設定 this.setDrawingSize = function(w, h) { this.width = w + (this.borderWidth + this.textPadding) * 2; this.height = h + (this.borderWidth + this.textPadding) * 2; } // 表示テキスト設定 this.setItems = function(items, context) { var i; this.items = new Array(); if (items && items.length > 0) { for (i = 0;i < items.length;i++) { this.items[i] = new String(items[i]); } } context.font = this.font; var maxWidth = 0; // 選択肢文字列中の最大描画幅を取得 for (i = 0;i < items.length;i++) { if (context.measureText(items[i]).width > maxWidth) { maxWidth = context.measureText(items[i]).width; } } // 選択肢の描画サイズに合わせてウインドウサイズ設定 this.setDrawingSize(maxWidth + 18, this.lineHeight * items.length); } // 表示 this.show = function() { // 表示フラグをセット this.display = true; this.status = this.STATUS_NONE; this.keyWait = false; } // 非表示 this.hide = function() { // 表示フラグをリセット this.display = false; } // 描画 this.draw = function(context) { if (!this.display) { return; } // ウインドウ領域全体を白でクリア context.fillStyle = '#ffffff'; context.fillRect(this.x, this.y, this.width, this.height); // 枠を残して黒でクリア context.fillStyle = '#000000'; context.fillRect(this.x + this.borderWidth, this.y + this.borderWidth, this.width - this.borderWidth * 2, this.height - this.borderWidth * 2); // テキスト描画設定 context.font = this.font; context.fillStyle = '#ffffff'; context.textBaseline = 'top'; if (this.items == null || this.items.length < 1) { return; } // 各行のテキストを描画 for (i = 0;i < this.items.length;i++) { context.fillText(this.items[i], this.drawX + 16, this.drawY + i * this.lineHeight + 2); } context.fillStyle = '#ffffff'; context.beginPath(); // 現在の選択インデックスの位置に三角形のパスを設定 context.moveTo(this.drawX + 2, this.drawY + this.index * this.lineHeight + 3); context.lineTo(this.drawX + 2, this.drawY + this.index * this.lineHeight + 14); context.lineTo(this.drawX + 11, this.drawY + this.index * this.lineHeight + 8); context.closePath(); // 設定したパスを塗りつぶす context.fill(); } this.action = function(key) { if (this.items == null || this.items.length < 1) { return false; } switch (this.status) { case this.STATUS_NONE: // 上方向キー処理待機状態更新 if (this.upKeyWait > 0) { if ((key & KEYFLAG_UP) == 0) { // 上キーが離されたら処理待機終了 this.upKeyWait = 0; } else { this.upKeyWait--; } } // 下方向キー処理待機状態更新 if (this.downKeyWait > 0) { if ((key & KEYFLAG_DOWN) == 0) { // 下キーが離されたら処理待機終了 this.downKeyWait = 0; } else { this.downKeyWait--; } } // リターンキー押下 if ((key & KEYFLAG_SELECT) != 0) { // 選択状態に this.status = this.STATUS_SELECTED; return false; } // 上キー押下 if (this.upKeyWait == 0 && (key & KEYFLAG_UP) != 0 && this.index > 0) { // 選択インデックスを一つ上へ this.index--; // 同一キー押下処理待機ウエイト設定 this.upKeyWait = 10; } // 下キー押下 if (this.downKeyWait == 0 && (key & KEYFLAG_DOWN) != 0 && this.index < this.items.length - 1) { // 選択インデックスを一つ下へ this.index++; // 同一キー押下処理待機ウエイト設定 this.downKeyWait = 10; } break; } return true; } } // HTML出力 document.write('
'); document.write(''); document.write('
'); document.write('
'); document.write('
'); document.write('
'); document.write('イベントスクリプトソース
'); document.write(''); document.write('
'); // 開始フラグ var testStart = false; // 現在位置 var x = 60; var y = 63; // スクロール状態 var scrollState = 0; // スクロール方向 var scrollDirect = 0; // スクロール位置 var scrollPos = 0; // スクロール速度 var scrollSpeed = 2; var dx = 0; var dy = 0; // マップデータ配列 var map = new Array(); var mapAtt = new Array(); var eventList = new Array(); // マップチップサイズ var tip_width = 32; var tip_height = 32; // マップサイズ var map_cols = 100; var map_rows = 100; // 表示領域サイズ(チップ数) var view_cols = 13; var view_rows = 13; var view_top = -Math.floor(view_cols / 2); var view_left = -Math.floor(view_rows / 2); var view_right = Math.floor(view_cols / 2); var view_bottom = Math.floor(view_rows / 2); var chrPosX = Math.floor(view_cols / 2); var chrPosY = Math.floor(view_rows / 2); // 表示領域サイズ var view_width = view_cols * tip_width; var view_height = view_rows * tip_height; // 表示Canvas var viewCanvas = document.getElementById('view_canvas'); var viewContext; // マップ描画Canvas(非表示) var mapCanvas = document.getElementById('map_canvas'); var mapContext; // リソース画像から生成するImageオブジェクト var partsImage; var chrImage; var evcharImage; // キー状態フラグ var keyFlag = 0; var DIR_UP = KEYFLAG_UP; var DIR_DOWN = KEYFLAG_DOWN; var DIR_LEFT = KEYFLAG_LEFT; var DIR_RIGHT = KEYFLAG_RIGHT; // ゲームの処理状態 var gameState; var GAMESTATE_WALK = 0; var GAMESTATE_EVENT = 1; // 現在処理中のスクリプト var eventScriptItems; // スクリプト変数格納配列 var eventVars; // スクリプト変数最大番号 var VAL_MAX_INDEX = 99; var eventItemIndex = 0; var eventExecCode; var eventExecArg; // イベント処理の処理状況 var eventProcess; var EVENTPROCESS_FETCH = 1; var EVENTPROCESS_PROCESS = 2; var EVENTPROCESS_END = 3; // 現在処理中のイベントコード var eventProcessItem; var EVENTCODE_ERROR = -1; var EVENTCODE_NONE = 0; var EVENTCODE_GETVAR = 1; var EVENTCODE_SETVAR = 2; var EVENTCODE_MESSAGE = 10; var EVENTCODE_SELECT = 11; var EVENTCODE_SHOWIMAGE = 12; var EVENTCODE_SETBGM = 13; var EVENTCODE_BATTLE = 14; var EVENTCODE_EQ = 30; var EVENTCODE_NE = 31; var EVENTCODE_LT = 32; var EVENTCODE_LE = 33; var EVENTCODE_GT = 34; var EVENTCODE_GE = 35; var EVENTCODE_IF = 40; var EVENTCODE_ELSE = 41; var EVENTCODE_ENDIF = 42; // イベントコード処理の状態 var eventProcessStage; var EVENTPROCESSSTAGE_MESSAGE_VIEW = 1; var EVENTPROCESSSTAGE_MESSAGE_EXIT = 2; var EVENTPROCESSSTAGE_SELECT_VIEW = 3; var EVENTPROCESSSTAGE_SELECT_EXIT = 4; var EVENTPROCESSSTAGE_SHOWIMAGE_LOADING = 5; var EVENTPROCESSSTAGE_SHOWIMAGE_LOADED = 6; var EVENTPROCESSSTAGE_SHOWIMAGE_VIEW = 7; var EVENTPROCESSSTAGE_SHOWIMAGE_EXIT = 8; var EVENTPROCESSSTAGE_BATTLE = 10; var EVENTPROCESSSTAGE_BATTLE_EXIT = 11; // 現在処理中のイベント var gameEvent = null; // イベントで表示するメッセージ表示ウインドウ var eventMessageBox = null; var eventSelectDlg = null; var battleState var BATTLESTATE_NONE = 0; var BATTLESTATE_START_INIT = 1; var BATTLESTATE_START_MESSAGE = 2; var BATTLESTATE_START_EXIT = 3; var BATTLESTATE_COMMAND_IN = 4; var BATTLESTATE_COMMAND = 5; var BATTLESTATE_COMMAND_SELECTED = 6; var BATTLESTATE_BATTLE = 7; var BATTLESTATE_BATTLE_END = 8; var BATTLESTATE_END = 9; var BATTLESTATE_EXIT = 10; var BATTLEIMAGE_WIDTH = 128; var BATTLEIMAGE_HEIGHT = 128; var battleCommandSelect = null; var battleMessage = null; var bgmPlayer = null; var eventIfLevel = 0; var eventImage = null; var eventImageX = 0; var eventImageY = 0; // イベント情報クラス var EventItem = function(chr, x, y, passFlag, script){ // 表示するキャラクタ番号 this.chr = chr; // イベント位置 this.x = x; this.y = y; // 通過フラグ this.passFlag = passFlag; // イベントで実行するスクリプト this.script = script; } init(); function init() { var i; var j; // Canvasが利用できなければ戻る if (!mapCanvas.getContext) { return; } var i; var j; // マップデータ初期化 for (i = 0;i < map_rows;i++) { for (j = 0;j < map_cols;j++) { map[j + i * map_cols] = 0; mapAtt[j + i * map_cols] = 0; } } // 乱数でマップデータ作成 for (i = view_rows;i < map_rows - view_rows;i++) { for (j = view_cols;j < map_cols - view_cols;j++) { map[j + i * map_cols] = 4 + Math.floor(Math.random() * 5); } } // イベント情報配列作成 eventList = new Array(); for (i = 0;i < 128;i++) { eventList[i] = null; } // イベント変数配列作成 eventVars = new Array(); // イベント変数配列初期化 for (i = 0;i <= VAL_MAX_INDEX;i++) { eventVars[i] = 0; } loadGameData(); document.getElementById("scriptView").value = ""; // Canvasのコンテキスト取得 viewContext = viewCanvas.getContext('2d'); mapContext = mapCanvas.getContext('2d'); // マップ用地形パーツ画像読み込み partsImage = new Image(); partsImage.src = 'evbattle_parts.png'; // キャラクタ用透過png画像読み込み chrImage = new Image(); chrImage.src = 'evbattle_chr.png'; // イベントキャラクタ用透過png画像読み込み evcharImage = new Image(); evcharImage.src = 'evbattle_evchar.gif'; // スクロールテスト領域にキーイベントハンドラを追加 document.getElementById("testArea").onkeydown = keydownHandler; document.getElementById("testArea").onkeyup = keyupHandler; // 開始ボタンを有効化 document.getElementById("testBtn").disabled = false; gameState = GAMESTATE_WALK; battleState = BATTLESTATE_NONE; battleMessage = new MessageWindow(); battleMessage.init(); battleMessage.setSize(tip_width * (view_cols - 2), tip_height * 5); battleMessage.setPosition(tip_width, tip_height * (view_rows - 6)); } function loadGameData() { var i; var j; // テスト用イベント作成 eventList[1] = new EventItem(1, 60, 60, false, 'message("メッセージ文字列表示テスト<:br><:br><:br><:br>改ページテスト<:page>メッセージウインドウは、画面中央下に一キャラクタ分のスペースをおいて配置。<:br><:br>改行テスト<:br>イベント処理中は、決定キーでメッセージウインドウの操作を行います。<:br><:br>メッセージ連続表示時に決定キーで全行表示、改ページ待機時に決定キーで次ページへ移動、表示完了後に決定キーでウインドウを閉じます。")' + "\n" + 'battle(1)' + "\n" + 'message("戦闘終了")'); eventList[2] = new EventItem(2, 61, 60, false, 'message("BGMを再生しますか?")' + "\n" + 'select(0,"はい いいえ")' + "\n" + "\n" + 'if(eq(getVar(0),0))' + "\n" + "\n" + ' select(1,"市場の朝 落ち葉の月夜")' + "\n" + "\n" + ' if(eq(getVar(1),0))' + "\n" + ' setBgm("itiba")' + "\n" + ' endif()' + "\n" + "\n" + ' if(eq(getVar(1),1))' + "\n" + ' setBgm("otiba")' + "\n" + ' endif()' + "\n" + "\n" + ' message("BGMを設定しました")' + "\n" + "\n" + 'else()' + "\n" + ' message("ではBGM設定は行いません")' + "\n" + 'endif()' + "\n" + "\n" + 'message("画像表示テストを行います")' + "\n" + 'showImage("evbattle.jpg")' + "\n" + 'message("テスト完了")'); // eventList[2] = new EventItem(2, 61, 60, false, 'message("選択ダイアログ表示テスト")' + "\n" + 'select("選択肢1 選択肢2 選択肢3 選択肢4")' + "\n" + 'message("画像表示テスト")' + "\n" + 'showImage("mapevs.jpg")'); // テスト用イベント周辺に草原配置 for (i = 58;i < 63;i++) { for (j = 58;j < 64;j++) { map[j + i * map_cols] = 4; } } // テスト用イベント周辺に石畳配置 map[59 + 59 * map_cols] = 1; map[60 + 59 * map_cols] = 8; map[61 + 59 * map_cols] = 8; map[62 + 59 * map_cols] = 1; map[59 + 60 * map_cols] = 8; map[60 + 60 * map_cols] = 8; map[61 + 60 * map_cols] = 8; map[62 + 60 * map_cols] = 8; map[59 + 61 * map_cols] = 1; map[60 + 61 * map_cols] = 8; map[61 + 61 * map_cols] = 8; map[62 + 61 * map_cols] = 1; // マップ属性情報に通過不可の地形を記録 for (i = 0;i < map_rows;i++) { for (j = 0;j < map_cols;j++) { if (map[j + i * map_cols] < 4) { mapAtt[j + i * map_cols] = 0x80; } } } } // 開始ボタンクリック時 function start() { // 開始ボタンを無効化 document.getElementById("testBtn").disabled = true; drawScrollCanvas(x, y, 0); draw(); loop(); } // メインループ function loop() { // ゲーム状態に応じた処理 switch (gameState) { // 通常(移動)状態 case GAMESTATE_WALK: walk(); break; // イベント処理中 case GAMESTATE_EVENT: event(); break; } // 描画 draw(); // 一定時間後に再びloop()実行 setTimeout("loop()", 20); } // 通常(移動可能)状態の処理 function walk() { switch (scrollState) { // 非スクロール時 case 0: switch (keyFlag) { // 上キー押下 case DIR_UP: // 進行方向への接触検査 if (toutch(x, y - 1)) { dir = DIR_UP; dx = 0; dy = -1; scrollPos = 0; drawScrollCanvas(x, y, dir); scrollState = 1; } break; // 下キー押下 case DIR_DOWN: // 進行方向への接触検査 if (toutch(x, y + 1)) { dir = DIR_DOWN; dx = 0; dy = 1; scrollPos = 0; drawScrollCanvas(x, y, dir); scrollState = 1; } break; // 左キー押下 case DIR_LEFT: // 進行方向への接触検査 if (toutch(x - 1, y)) { dir = DIR_LEFT; dx = -1; dy = 0; scrollPos = 0; drawScrollCanvas(x, y, dir); scrollState = 1; } break; // 右キー押下 case DIR_RIGHT: // 進行方向への接触検査 if (toutch(x + 1, y)) { dir = DIR_RIGHT; dx = 1; dy = 0; scrollPos = 0; drawScrollCanvas(x, y, dir); scrollState = 1; } break; } break; // スクロール中 case 1: scrollPos += scrollSpeed; // スクロール位置更新 if (scrollPos == tip_width) { x += dx; y += dy; // スクロール終了時に同方向キー押下中で移動可能なら続いて移動 if (keyFlag == dir && toutch(x + dx, y + dy)) { scrollPos = 0; drawScrollCanvas(x, y, dir); } else { scrollState = 0; } } break; } } // イベント処理 function event() { // イベント処理状態に応じた処理 switch (eventProcess) { // イベントコード取り込み case EVENTPROCESS_FETCH: eventProcessItem = eventScriptItems[eventItemIndex]; switch (eventProcessItem.code) { // 変数に値を代入 case EVENTCODE_SETVAR: // 代入する変数インデックス varIndex = getVal(eventProcessItem.args[0]); // 代入する値 val = getVal(eventProcessItem.args[1]); if (varIndex == Number.NaN || val == Number.NaN || varIndex < 0 || varIndex > VAL_MAX_INDEX) { return; } eventVars[varIndex] = val; eventProcess = EVENTPROCESS_END; break; // IF文 case EVENTCODE_IF: eventIfLevel++; var ifLevel = 1; // 引数で指定された条件の判定 if (getBoolean(eventProcessItem.args[0])) { // 条件を満たしていればそのまま次のコマンドへ eventProcess = EVENTPROCESS_END; } else { // IF文終了かELSEまで飛ばす while (ifLevel > 0 && ++eventItemIndex < eventScriptItems.length) { // 現在のif文に対応するelseがあればそこへ移行 if (eventScriptItems[eventItemIndex].code == EVENTCODE_ELSE && ifLevel == 1) { break; } // IF文の中のIF文を飛ばす switch (eventScriptItems[eventItemIndex].code) { case EVENTCODE_IF: ifLevel++; break; case EVENTCODE_ENDIF: ifLevel--; break; } } eventProcess = EVENTPROCESS_END; } break; // ELSE文(IF文真部分実行後のみここに来るためELSEブロックは実行しない) case EVENTCODE_ELSE: var ifLevel = 1; // 現在のIF文終了まで飛ばす while (ifLevel > 0 && ++eventItemIndex < eventScriptItems.length) { // 現在のELSEブロック中のIF文を飛ばす switch (eventScriptItems[eventItemIndex].code) { case EVENTCODE_IF: ifLevel++; break; case EVENTCODE_ENDIF: ifLevel--; break; } } eventProcess = EVENTPROCESS_END; break; // IF文終了 case EVENTCODE_ENDIF: eventProcess = EVENTPROCESS_END; break; // メッセージ表示 case EVENTCODE_MESSAGE: // コマンド引数(表示文字列)取得 var messageArg = getArgString(eventProcessItem.args[0]); // メッセージウインドウ作成 eventMessageBox = new MessageWindow(); eventMessageBox.init(); // サイズ設定 eventMessageBox.setSize(tip_width * (view_cols - 2), tip_height * 5); // ゲーム画面中央に配置 eventMessageBox.setPosition(tip_width, tip_height * (view_rows - 6)); // 表示文字列設定 eventMessageBox.setText(messageArg, viewCanvas.getContext('2d')); // 可視状態に eventMessageBox.show(); // イベント状態をメッセージ表示中に eventProcess = EVENTPROCESS_PROCESS; eventProcessCode = EVENTCODE_MESSAGE; eventProcessStage = EVENTPROCESSSTAGE_MESSAGE_VIEW; break; // 選択メニュー case EVENTCODE_SELECT: // 結果を格納する変数番号取得 var argVar = getVal(eventProcessItem.args[0]); // コマンド引数(選択し文字列)取得 var argSelect = getArgString(eventProcessItem.args[1]); // 選択ダイアログ作成 eventSelectDlg = new SelectDialog(); eventSelectDlg.init(); // タブ区切りで格納されている選択肢を分離 var items = argSelect.split("\t"); // 選択肢設定 eventSelectDlg.setItems(items, viewCanvas.getContext('2d')); // ゲーム画面中央に配置 eventSelectDlg.setPosition((view_width - eventSelectDlg.width) / 2, (view_height - eventSelectDlg.height) / 2); eventSelectDlg.show(); // イベント状態を選択ダイアログ表示中に eventProcess = EVENTPROCESS_PROCESS; eventProcessCode = EVENTCODE_SELECT; eventProcessStage = EVENTPROCESSSTAGE_SELECT_VIEW; break; // 画像表示 case EVENTCODE_SHOWIMAGE: // コマンド引数(画像ファイルパス)取得 var argImage = getArgString(eventProcessItem.args[0]); // イベント状態を画像読み込み中に eventProcess = EVENTPROCESS_PROCESS; eventProcessCode = EVENTCODE_SHOWIMAGE; eventProcessStage = EVENTPROCESSSTAGE_SHOWIMAGE_LOADING; // Imageオブジェクト設定 eventImage = new Image(); // 画像の読み込みが完了したらイベント状態を画像読み込み完了に eventImage.onload = function() { eventProcessStage = EVENTPROCESSSTAGE_SHOWIMAGE_LOADED; } // 画像読み込み開始 eventImage.src = argImage; break; // BGM設定 case EVENTCODE_SETBGM: // コマンド引数(音声ファイル名)取得 var argBgm = getArgString(eventProcessItem.args[0]); var bgmType = null; if (bgmPlayer != null) { bgmPlayer.pause(); delete bgmPlayer; } bgmPlayer = new Audio(''); if (bgmPlayer.canPlayType("audio/ogg") == "maybe" || bgmPlayer.canPlayType("audio/ogg") == "probably") { bgmType = "ogg"; } if (bgmPlayer.canPlayType("audio/mp3") == "maybe" || bgmPlayer.canPlayType("audio/mp3") == "probably") { bgmType = "mp3"; } bgmPlayer.src = argBgm + '.' + bgmType; bgmPlayer.addEventListener("ended", function() { bgmPlayer.currentTime = 0; bgmPlayer.play(); }, false); bgmPlayer.play(); eventProcess = EVENTPROCESS_END; break; // 戦闘 case EVENTCODE_BATTLE: eventProcessCode = EVENTCODE_BATTLE; eventProcessStage = EVENTPROCESSSTAGE_BATTLE; battleState = BATTLESTATE_START_INIT; eventProcess = EVENTPROCESS_PROCESS; break; } break; // イベントコマンド処理中 case EVENTPROCESS_PROCESS: switch (eventProcessCode) { // メッセージ表示 case EVENTCODE_MESSAGE: switch (eventProcessStage) { case EVENTPROCESSSTAGE_MESSAGE_VIEW: // メッセージ表示ウインドウの処理が終わったらイベント終了へ if (!eventMessageBox.action(keyFlag)) { eventProcessStage = EVENTPROCESSSTAGE_MESSAGE_EXIT; } break; case EVENTPROCESSSTAGE_MESSAGE_EXIT: if ((keyFlag & KEYFLAG_SELECT) == 0) { eventProcess = EVENTPROCESS_END; // メッセージ表示ウインドウを削除 delete eventMessageBox; eventMessageBox = null; } break; } break; // 選択ダイアログ case EVENTCODE_SELECT: switch (eventProcessStage) { case EVENTPROCESSSTAGE_SELECT_VIEW: // 選択ダイアログの処理が終わったらイベント終了へ if (!eventSelectDlg.action(keyFlag)) { // 結果を格納する変数番号取得 var argVar = getVal(eventProcessItem.args[0]); // 選択結果を変数に格納 if (argVar >= 0 || argVar <= VAL_MAX_INDEX) { eventVars[argVar] = eventSelectDlg.index; } eventProcessStage = EVENTPROCESSSTAGE_SELECT_EXIT; } break; case EVENTPROCESSSTAGE_SELECT_EXIT: if ((keyFlag & KEYFLAG_SELECT) == 0) { eventProcess = EVENTPROCESS_END; // 選択ダイアログを削除 delete eventSelectDlg; eventSelectDlg = null; } break; } break; // 画像表示 case EVENTCODE_SHOWIMAGE: switch (eventProcessStage) { // 画像読み込み完了 case EVENTPROCESSSTAGE_SHOWIMAGE_LOADED: // 中央に配置するため表示位置計算 eventImageX = (view_width - eventImage.width) / 2; eventImageY = (view_height - eventImage.height) / 2; eventProcessStage = EVENTPROCESSSTAGE_SHOWIMAGE_VIEW; break; // 画像表示中 case EVENTPROCESSSTAGE_SHOWIMAGE_VIEW: // リターンキーで終了処理待機状態へ if ((keyFlag & KEYFLAG_SELECT) != 0) { eventProcessStage = EVENTPROCESSSTAGE_SHOWIMAGE_EXIT; } break; // 表示処理終了待機 case EVENTPROCESSSTAGE_SHOWIMAGE_EXIT: // リターンキーが離されたら終了 if ((keyFlag & 1) == 0) { eventProcess = EVENTPROCESS_END; // Imageオブジェクトを破棄 delete eventImage; eventImage = null; } break; } break; // 戦闘 case EVENTCODE_BATTLE: switch (eventProcessStage) { case EVENTPROCESSSTAGE_BATTLE: // 戦闘処理 if (!battle()) { eventProcessStage = EVENTPROCESSSTAGE_BATTLE_EXIT; } break; case EVENTPROCESSSTAGE_BATTLE_EXIT: // リターンキーが離されたら戦闘終了 if ((keyFlag & 1) == 0) { // 次のコマンドへ eventProcess = EVENTPROCESS_END; } break; } break; } break; // イベント実行終了 case EVENTPROCESS_END: if (++eventItemIndex < eventScriptItems.length) { eventProcess = EVENTPROCESS_FETCH; } else { // ゲームを通常状態へ gameState = GAMESTATE_WALK; } break; } } function battle() { switch (battleState) { case BATTLESTATE_START_INIT: battleMessage.setText("敵と遭遇", viewCanvas.getContext('2d')); battleMessage.show(); battleState = BATTLESTATE_START_MESSAGE; break; case BATTLESTATE_START_MESSAGE: battleMessage.action(keyFlag & 1); if (battleMessage.isTextEnd() && (keyFlag & 1) == 0) { battleState = BATTLESTATE_START_EXIT; } break; case BATTLESTATE_START_EXIT: battleState = BATTLESTATE_COMMAND_IN; battleCommandSelect = new SelectDialog(); battleCommandSelect.init(); battleCommandSelect.setItems(["攻撃", "退避"], viewCanvas.getContext('2d')); battleCommandSelect.setPosition((view_width - battleCommandSelect.width) / 2, (view_height - battleCommandSelect.height) / 2); battleCommandSelect.show(); break; case BATTLESTATE_COMMAND_IN: if ((keyFlag & KEYFLAG_SELECT) == 0) { battleCommandSelect.reset(); battleMessage.setText("", viewCanvas.getContext('2d')); battleState = BATTLESTATE_COMMAND; } break; case BATTLESTATE_COMMAND: // 選択ダイアログの処理が終わったら戦闘処理へ if (!battleCommandSelect.action(keyFlag)) { battleState = BATTLESTATE_COMMAND_SELECTED; } break; case BATTLESTATE_COMMAND_SELECTED: if ((keyFlag & KEYFLAG_SELECT) == 0) { switch (battleCommandSelect.index) { case 0: battleState = BATTLESTATE_BATTLE; break; case 1: battleState = BATTLESTATE_END; battleMessage.setText("離脱成功 ", viewCanvas.getContext('2d')); break; } } break; case BATTLESTATE_BATTLE: battleMessage.setText("戦闘処理 ", viewCanvas.getContext('2d')); battleState = BATTLESTATE_BATTLE_END; break; case BATTLESTATE_BATTLE_END: if ((keyFlag & KEYFLAG_SELECT) != 0) { battleState = BATTLESTATE_COMMAND_IN; } break; case BATTLESTATE_END: // 決定キーが離されたら戦闘処理終了待機へ if ((keyFlag & KEYFLAG_SELECT) == 0) { battleState = BATTLESTATE_EXIT; } break; case BATTLESTATE_EXIT: // ゲームを通常状態へ if ((keyFlag & KEYFLAG_SELECT) != 0) { battleState = BATTLESTATE_NONE; // gameState = GAMESTATE_EVENT; return false; } break; } return true; } // スクリプトで有効な文字列を取得 function getArgString(arg) { // 先頭と末尾の空白文字削除 var text = chop(arg); // ""で囲まれていない文字列は無効 if (text == null || text.length < 3 || text.charAt(0) != '"' || text.charAt(text.length - 1) != '"') { return null; } // ""の間の文字列を取得 var str = text.substring(1, text.length - 1); return str; } // 文字列が数字か検査 function isNum(arg) { var i; // 空文字列なら偽 if (arg == null || arg.length < 1) { return false; } str = new String(arg); // 先頭の-を除く if (str.charAt(0) == '-') { str = str.substr(1); } if (arg == null || arg.length < 1) { return false; } // 0-9以外の文字が出てきたら偽 for (i = 0;i < str.length;i++) { if (str.charAt(i) < '0' || str.charAt(i) > '9') { return false; } } // 最後まで条件違反がなければ真 return true; } // 文字列を数値評価 function getVal(arg) { // 数字文字列ならその値を返す if (isNum(arg)) { return parseInt(arg, 10); } // 文字列をコマンドとして解析 var command = parseCommand(arg); // 文字列がgetVar(変数の値取得)コマンドならその値を評価 if (command.code == EVENTCODE_GETVAR) { // 変数番号を取得 var index = getVal(command.args[0]); // 指定番号が変数番号の範囲になければ異常値 if (index == Number.NaN || index < 0 || index > VAL_MAX_INDEX) { return Number.NaN; } // 変数の値を返す return eventVars[index]; } return Number.NaN; } // 文字列の条件式の真偽を評価 function getBoolean(arg) { var command = parseCommand(arg); switch (command.code) { // eq()関数(等しい時に真) case EVENTCODE_EQ: // 引数として渡された左辺値と右辺値を評価 var leftVal = getVal(command.args[0]); var rightVal = getVal(command.args[1]); // 評価不能な値なら無条件にfalse if (leftVal == Number.NaN || rightVal == Number.NaN) { return false; } return leftVal == rightVal; // ne()関数(等しくない時に真) case EVENTCODE_NE: // 引数として渡された左辺値と右辺値を評価 var leftVal = getVal(command.args[0]); var rightVal = getVal(command.args[1]); // 評価不能な値なら無条件にfalse if (leftVal == Number.NaN || rightVal == Number.NaN) { return false; } return leftVal != rightVal; } } // マップの指定位置へ接触検査 function toutch(x, y) { var event = getEvent(x, y); // 指定位置にイベントがなくて通過可能ならtrueを返す if (event == null && mapAtt[x + y * map_cols] == 0) { return true; } // イベントがなくて通過不可ならfalseを返す if (event == null) { return false; } document.getElementById('scriptView').value = event.script; // 指定位置のイベントスクリプトのコマンドを取得 eventScriptItems = getScriptItems(event.script); if (eventScriptItems == null) { return; } // イベント処理へ移行 gameEvent = event; eventItemIndex = 0; gameState = GAMESTATE_EVENT; eventProcess = EVENTPROCESS_FETCH; return event.passFlag; } // 指定位置のイベントを取得 function getEvent(x, y) { var i; // イベント格納配列を走査し、指定位置のイベントがあれば返す for (i = 0;i < eventList.length;i++) { if (eventList[i] != null && eventList[i].x == x && eventList[i].y == y) { return eventList[i]; } } return null; } // スクリプトソースからコマンド配列を作成 function getScriptItems(src) { var i; if (src == null || src.length < 1) { return null; } // 改行を\nに統一 var script = src.replace("\r\n", "\n"); script = src.replace("\r", "\n"); // 各行を配列に格納 var lines = script.split("\n"); var commandList = new Array(); // 各行のコマンドを作成 for (i = 0;i < lines.length;i++) { var lineItem = parseCommand(lines[i]); if (lineItem.code != EVENTCODE_NONE) { commandList.push(lineItem); } } return commandList; } // スクリプト文字列からコマンド情報オブジェクトを作成 function parseCommand(str) { var i; var result = new Object(); result.script = str; // 先頭と末尾の空白文字を削除 var item = chop(str); if (item == null || item.length < 1 || item.indexOf("//") == 0) { result.code = EVENTCODE_NONE; } else { // 最初に(が出てくる位置を探索 var argIndex = item.indexOf("("); result.code = EVENTCODE_ERROR; if (argIndex > 0 && item.charAt(item.length - 1) == ')') { // (までをコマンドとして記録 var command = item.substring(0, argIndex); // ()内を引数として記録 var arg = chop(item.substring(argIndex + 1, item.length - 1)); // ,で引数を分離し引数配列に格納 if (arg != null && arg.length > 0) { var args = new Array(); var argItem = ''; var quoteIn = false; var funcLevel = 0; for (i = 0;i < arg.length;i++) { // "が出てきたら"フラグ反転 if (arg.charAt(i) == '"') { quoteIn = !quoteIn; } // ""外で()が出てきたら関数の処理 if (!quoteIn) { if (arg.charAt(i) == '(') { funcLevel++; } if (arg.charAt(i) == ')') { funcLevel--; } } if ((!quoteIn && funcLevel == 0 && arg.charAt(i) == ',') || i == arg.length - 1) { if (i == arg.length - 1) { argItem = argItem + arg.charAt(i); } args.push(chop(argItem)); argItem = ''; } else { argItem = argItem + arg.charAt(i); } } result.args = args; } else { result.args = null; } if (command == 'getVar' && args != null && args.length == 1) { result.code = EVENTCODE_GETVAR; } if (command == 'setVar' && args != null && args.length == 2) { result.code = EVENTCODE_SETVAR; } if (command == 'eq' && args != null && args.length == 2) { result.code = EVENTCODE_EQ; } if (command == 'ne' && args != null && args.length == 2) { result.code = EVENTCODE_NE; } if (command == 'message' && args != null && args.length == 1) { result.code = EVENTCODE_MESSAGE; } if (command == 'select' && args != null && args.length == 2) { result.code = EVENTCODE_SELECT; } if (command == 'showImage' && args != null && args.length == 1) { result.code = EVENTCODE_SHOWIMAGE; } if (command == 'setBgm' && args != null && args.length == 1) { result.code = EVENTCODE_SETBGM; } if (command == 'battle' && args != null && args.length == 1) { result.code = EVENTCODE_BATTLE; } if (command == 'if' && args != null && args.length == 1) { result.code = EVENTCODE_IF; } if (command == 'else') { result.code = EVENTCODE_ELSE; } if (command == 'endif') { result.code = EVENTCODE_ENDIF; } } } return result; } // 指定文字列の先頭と末尾にある空白文字を削除した文字列を返す function chop(str) { if (str == null || str.length < 1) { return null; } var result; var startIndex = 0; var lastIndex = str.length - 1; // 行頭から空白文字でない文字が出てくる位置を検索 while (startIndex < str.length && (str.charAt(startIndex) == ' ' || str.charAt(startIndex) == "\t")) { startIndex++; } // 空白文字のみの文字列ならnullを返す if (startIndex == str.length) { return null; } // 行末から空白文字でない文字が出てくる位置を検索 while (lastIndex >= 0 && (str.charAt(lastIndex) == ' ' || str.charAt(lastIndex) == "\t")) { lastIndex--; } return str.substring(startIndex, lastIndex + 1); } // スクロールキャンバス描画 function drawScrollCanvas(sx, sy, dir) { var i; var j; sx += view_left; sy += view_top; switch (dir) { // 新規描画 case 0: // マップ描画Canvasにスクロール範囲を描画 for (i = 0;i < view_rows;i++) { for (j = 0;j < view_cols;j++) { mapContext.drawImage(partsImage, (map[sx + j + (sy + i) * map_cols] % 4) * tip_width, Math.floor(map[sx + j + (sy + i) * map_cols] / 4) * tip_height, tip_width, tip_height, j * tip_width, i * tip_height, tip_width, tip_height); } } break; // 上スクロール case DIR_UP: // マップ描画Canvasにスクロール範囲を描画 for (i = 0;i < view_rows + 1;i++) { for (j = 0;j < view_cols;j++) { mapContext.drawImage(partsImage, (map[sx + j + (sy - 1 + i) * map_cols] % 4) * tip_width, Math.floor(map[sx + j + (sy - 1 + i) * map_cols] / 4) * tip_height, tip_width, tip_height, j * tip_width, i * tip_height, tip_width, tip_height); } } break; // 下スクロール case DIR_DOWN: // マップ描画Canvasにスクロール範囲を描画 for (i = 0;i < view_rows + 1;i++) { for (j = 0;j < view_cols;j++) { mapContext.drawImage(partsImage, (map[sx + j + (sy + i) * map_cols] % 4) * tip_width, Math.floor(map[sx + j + (sy + i) * map_cols] / 4) * tip_height, tip_width, tip_height, j * tip_width, i * tip_height, tip_width, tip_height); } } break; // 左スクロール case DIR_LEFT: // マップ描画Canvasにスクロール範囲を描画 for (i = 0;i < view_rows;i++) { for (j = 0;j < view_cols + 1;j++) { mapContext.drawImage(partsImage, (map[sx - 1 + j + (sy + i) * map_cols] % 4) * tip_width, Math.floor(map[sx - 1 + j + (sy + i) * map_cols] / 4) * tip_height, tip_width, tip_height, j * tip_width, i * tip_height, tip_width, tip_height); } } break; // 右スクロール case DIR_RIGHT: // マップ描画Canvasにスクロール範囲を描画 for (i = 0;i < view_rows;i++) { for (j = 0;j < view_cols + 1;j++) { mapContext.drawImage(partsImage, (map[sx + j + (sy + i) * map_cols] % 4) * tip_width, Math.floor(map[sx + j + (sy + i) * map_cols] / 4) * tip_height, tip_width, tip_height, j * tip_width, i * tip_height, tip_width, tip_height); } } break; } } // 表示Canvasに描画 function draw() { var i; // Canvasのコンテキスト取得 var viewContext = viewCanvas.getContext('2d'); var drawX = 0; var drawY = 0; if (dx > 0) { drawX = dx * scrollPos; } if (dx < 0) { drawX = tip_width + (dx * scrollPos); } if (dy > 0) { drawY = dy * scrollPos; } if (dy < 0) { drawY = tip_height + (dy * scrollPos); } // マップ描画Canvasを転送 viewContext.drawImage(mapCanvas, drawX, drawY, tip_width * view_cols, tip_height * view_rows, 0, 0, tip_width * view_cols, tip_height * view_rows); var ecx = 0; var ecy = 0; if (scrollState == 1) { if (dx < 0) { ecx = -drawX + tip_width; } else { ecx = -drawX; } if (dy < 0) { ecy = -drawY + tip_height; } else { ecy = -drawY; } } // イベントキャラクタ描画 for (i = 0;i < eventList.length;i++) { if (eventList[i] != null && eventList[i].chr > 0 && (eventList[i].x > x + view_left - 2) && (eventList[i].x < x + view_right + 2) && (eventList[i].y > y + view_top - 2) && (eventList[i].y < y + view_bottom + 2)) { viewContext.drawImage(evcharImage, ((eventList[i].chr - 1) % 4) * tip_width, Math.floor((eventList[i].chr - 1) / 4) * tip_height, tip_width, tip_height, ecx + (eventList[i].x - (x + view_left)) * tip_width, ecy + (eventList[i].y - (y + view_top)) * tip_height, tip_width, tip_height); } } // 主人公描画 viewContext.drawImage(chrImage, chrPosX * tip_width, chrPosY * tip_height); // イベント描画 if (gameState == GAMESTATE_EVENT && eventProcessItem) { switch (eventProcessItem.code) { case EVENTCODE_MESSAGE: if (eventProcessStage == EVENTPROCESSSTAGE_MESSAGE_VIEW) { eventMessageBox.draw(viewContext); } break; case EVENTCODE_SELECT: if (eventProcessStage == EVENTPROCESSSTAGE_SELECT_VIEW) { eventSelectDlg.draw(viewContext); } break; case EVENTCODE_SHOWIMAGE: if (eventProcessStage == EVENTPROCESSSTAGE_SHOWIMAGE_VIEW) { viewContext.drawImage(eventImage, eventImageX, eventImageY); } break; case EVENTCODE_BATTLE: // 戦闘描画 if (battleState != BATTLESTATE_NONE) { viewContext.fillStyle = '#ffffff'; viewContext.fillRect((view_width / 2) - (BATTLEIMAGE_WIDTH + 2) / 2, (view_height / 2) - (BATTLEIMAGE_HEIGHT + 2), BATTLEIMAGE_WIDTH, BATTLEIMAGE_HEIGHT); battleMessage.draw(viewContext); if (battleState == BATTLESTATE_COMMAND) { battleCommandSelect.draw(viewContext); } } break; } } } // キー押下イベント処理 function keydownHandler(e) { var code = 0; code = e.keyCode; // キー押下状態に応じてキーフラグ設定 switch (code) { // リターンキー case 13: e.preventDefault(); keyFlag |= KEYFLAG_SELECT; break; // 上キー case 38: e.preventDefault(); keyFlag |= KEYFLAG_UP; break; // 下キー case 40: e.preventDefault(); keyFlag |= KEYFLAG_DOWN; break; // 左キー case 37: e.preventDefault(); keyFlag |= KEYFLAG_LEFT; break; // 右キー case 39: e.preventDefault(); keyFlag |= KEYFLAG_RIGHT; break; } } // キー解放イベント処理 function keyupHandler(e) { var code = 0; code = e.keyCode; // キー押下状態に応じてキーフラグ設定 switch (code) { // リターンキー case 13: e.preventDefault(); keyFlag &= ~KEYFLAG_SELECT; break; // 上キー case 38: e.preventDefault(); keyFlag &= ~KEYFLAG_UP; break; // 下キー case 40: e.preventDefault(); keyFlag &= ~KEYFLAG_DOWN; break; // 左キー case 37: e.preventDefault(); keyFlag &= ~KEYFLAG_LEFT; break; // 右キー case 39: e.preventDefault(); keyFlag &= ~KEYFLAG_RIGHT; break; } }