効果音(SE)一式 + 加入特別SE
実装内容
-
共通SE管理用オブジェクトを追加
-
playSE(name) 関数で統一的に再生
-
加入時は以下の2段階構成
-
通常加入SE
-
少し遅れて「特別加入SE」
var SE = {};
var seEnabled = true;
var seVolume = 0.6; // 0.0~1.0
function initSE(){
SE.move = document.getElementById("seMove");
SE.talk = document.getElementById("seTalk");
SE.open = document.getElementById("seOpen");
SE.decide = document.getElementById("seDecide");
SE.cancel = document.getElementById("seCancel");
SE.item = document.getElementById("seItem");
SE.save = document.getElementById("seSave");
SE.boat = document.getElementById("seBoat");
SE.battle = document.getElementById("seBattle");
SE.clear = document.getElementById("seClear");
SE.vanish = document.getElementById("seVanish");
SE.join = document.getElementById("seJoin");
SE.joinSp = document.getElementById("seJoinSp");
Object.values(SE).forEach(a=>{
if(a){ a.volume = seVolume; }
});
}
function playSE(name){
if(!seEnabled) return;
const a = SE[name];
if(!a) return;
try{
a.pause();
a.currentTime = 0;
a.volume = seVolume;
a.play();
}catch(e){
}
}
function playJoinSpecial(){
// 通常加入SE → 少し遅らせて特別加入SE
playSE("join");
setTimeout(()=>playSE("joinSp"), 220);
}
function init(){
cv=document.getElementById("field");
gc=cv.getContext("2d");
if('imageSmoothingEnabled' in gc) gc.imageSmoothingEnabled=false;
<audio id="seMove" src="semove.mp3" preload="auto"></audio>
<audio id="seTalk" src="setalk.mp3" preload="auto"></audio>
<audio id="seOpen" src="seopen.mp3" preload="auto"></audio>
<audio id="seDecide" src="sedecide.mp3" preload="auto"></audio>
<audio id="seCancel" src="secancel.mp3" preload="auto"></audio>
<audio id="seItem" src="seitem.mp3" preload="auto"></audio>
<audio id="seSave" src="sesave.mp3" preload="auto"></audio>
<audio id="seBoat" src="seboat.mp3" preload="auto"></audio>
<audio id="seBattle" src="sebattle.mp3" preload="auto"></audio>
<audio id="seClear" src="seclear.mp3" preload="auto"></audio>
<audio id="seVanish" src="sevanish.mp3" preload="auto"></audio>
<audio id="seJoin" src="sejoin.mp3" preload="auto"></audio>
<audio id="seJoinSp" src="sejoinsp.mp3" preload="auto"></audio>
メニュー右パネルのスクロール(仲間/アイテム)
実装内容
-
スクロール用変数を追加
-
表示数を超えた場合は、表示範囲を切り替えて描画
-
現在位置を
操作仕様
-
メニュー表示中に左右キーでスクロール
-
対象は「仲間」「アイテム」選択時のみ
// メニュー
if(gameMode==='menu'){
if(code===38){ menuIndex=(menuIndex+menuItems.length-1)%menuItems.length; fieldpaint(); return; }
if(code===40){ menuIndex=(menuIndex+1)%menuItems.length; fieldpaint(); return; }
// ★追加:右パネルスクロール(←→)
const current = menuItems[menuIndex];
const maxLines = 11;
if(code===37 || code===39){
const dir = (code===37)? -1 : 1;
if(current==="仲間"){
const maxScroll = Math.max(0, party.length - maxLines);
partyScroll = Math.max(0, Math.min(maxScroll, partyScroll + dir));
playSE("move");
fieldpaint();
return;
}
if(current==="アイテム"){
const maxScroll = Math.max(0, items.length - maxLines);
itemScroll = Math.max(0, Math.min(maxScroll, itemScroll + dir));
playSE("move");
fieldpaint();
return;
}
}
if(code===27){ playSE("cancel"); gameMode='play'; fieldpaint(); return; }
if(code===13||code===88){ playSE("decide"); handleMenuSelect(menuItems[menuIndex]); return; }
return;
}
ボス戦の確認 + 長いカットシーン
実装内容
条件
演出内容
-
数ページに分かれた戦闘描写
-
テキスト送りによる緊張感の演出
-
最後に撃破処理へ移行
ゲーム体験への効果
-
ボス戦が「物語上の山場」として強調される
-
評価システムとストーリーが自然に結びつく
3体の撃破後消滅(骸骨剣士/骸骨騎士/ゴースト)
実装内容
-
各NPCに専用フラグを用意
-
defeated_skeletonSword
-
defeated_skeletonKnight
-
defeated_ghost
-
フラグが立つと
イベント発生時
-
条件を満たすと撃破/成仏
-
専用メッセージ表示
-
アイテム取得
-
消滅SEを再生
ボス撃破 → 王に報告 → エンディング
役割
ボス撃破をゴールにせず、物語としての締めを用意する。
実装内容
流れ
-
ダンジョンボス撃破
-
城へ戻る
-
王に報告
-
最終評価+エンディング表示
ゲーム体験への効果
-
「倒して終わり」ではない余韻を残す
-
集めた仲間や達成度を振り返る導線になる
評価ランク SSS〜E(A以上でボス戦可能)
役割
仲間集め・イベント達成を数値化して評価する中核システム。
実装内容
ボス戦との関係
-
ランク A以上でのみボス戦可能
-
低ランクでは挑戦自体ができない
ゲーム体験への効果
-
「どれだけ準備したか」が明確に反映される
-
やり込み要素として機能する
const evalFlags = [
"bossCleared",
"skeletonKingDefeated",
"defeated_skeletonSword",
"defeated_ghost"
];
let memberScore = 0;
for(const n of joinableMembers){
if(inParty(n)) memberScore++;
}
let flagScore = 0;
for(const f of evalFlags){
if(hasFlag(f)) flagScore++;
}
const score = memberScore + flagScore;
const maxScore = joinableMembers.length + evalFlags.length;
const ratio = maxScore > 0 ? (score / maxScore) : 0;
let rank = "E";
if(ratio >= 0.95) rank = "SSS";
else if(ratio >= 0.85) rank = "SS";
else if(ratio >= 0.70) rank = "S";
else if(ratio >= 0.55) rank = "A";
else if(ratio >= 0.40) rank = "B";
else if(ratio >= 0.25) rank = "C";
else if(ratio >= 0.10) rank = "D";
else rank = "E";
return { score, rank };
}
function finalEvaluate(){
const {score,rank} = calcFinalEvaluation();
showChoice(
"エンディング",
"ダンジョンボスは倒され、島に静寂が戻った。\n\n" +
"あなたの最終評価は: "+rank+
"\nスコア:"+score+
"\n\n集めた仲間やこなした試練の数で評価が変化する。\n" +
"タイトルへ戻ります。",
["タイトルへ戻る"],
(i)=>{
backToTitle();
}
);
}
セーブ/ロード + タイトル画面
実装内容
-
セーブデータを localStorage に保存
-
保存内容
-
タイトル画面を追加
操作
-
セーブ済みデータがあれば「続きから」が選択可能
-
いつでも再開できる設計
まとめ
今回の更新では、
-
演出(SE・カットシーン)
-
評価システム
-
世界の変化(消滅・エンディング)
-
遊びやすさ(UI・セーブ)
参考文献・引用サイト
ぴぽや倉庫
ドット絵世界
DOT ILLOST
効果音ラボ