実験#72:お楽しみボックスの中身を探る実験(お楽しみボックスシミュレーター)

※本コンテンツは、金銭的価値・当たり/ハズレ・ギャンブル性を含まない
ランダム生成のゲームです。
実際の金銭取引やギャンブル行為とは一切関係ありません。

■72個目 「お楽しみボックスシミュレーター」

こんにちは、AIと作る100のゲーム実験室の みー です。(*^_^*)/

今回は、みんながワクワクする「開封の瞬間」をテーマにした
ランダム生成ゲームを作ってみました。

お正月の福袋のような“当たり/ハズレ”ではなく、
純粋に中身が毎回変わる楽しさだけを味わえる実験ゲームです。

🎁 今回のこだわりポイント

  • 開ける瞬間のワクワク感
  • 1000種類以上の豊富なアイテムバリエーション
  • 毎回ちがう組み合わせが出てくる楽しさ

「お楽しみボックス」を開けると、
ランダムに選ばれた5つのアイテムが表示されます。

どんな組み合わせになるかは毎回違うので、
ちょっとした“ミニ実験”のような気持ちで楽しめます。(^v^)

🏷 アイテムのカテゴリ

アイテムは、世界観に合わせて6つのカテゴリに分かれています。
金銭的な価値ではなく、ゲーム内の雰囲気づくりのための分類です。

  • スペシャルアイテム
  • レアアイテム
  • 良いアイテム
  • ふつうアイテム
  • ユニークアイテム
  • ジョークアイテム

それぞれの例を少し紹介すると……

● スペシャルアイテム

・無人島の模型 ・宇宙旅行のパンフレット ・伝説の聖剣(おもちゃ)

● レアアイテム

・最新スマートフォンのミニチュア ・松阪牛のぬいぐるみ ・高級自転車の模型

● 良いアイテム

・ノイズキャンセリングイヤホン風キーホルダー ・全自動コーヒーメーカーのミニ模型 ・国産うなぎの食品サンプル

● ふつうアイテム

・特選コーヒー豆のパッケージ風カード ・人気ボードゲームのミニチップ ・今治タオルの布サンプル

● ユニークアイテム

・マスター特製ステッカー ・謎の木彫りの熊(ミニサイズ) ・派手な柄の靴下(イラスト)

● ジョークアイテム

・道端の石ころ(イラスト) ・ちぎれた輪ゴム(イラスト)

などなど……。(^^;)

🎉 開封演出も盛りだくさん

お楽しみボックスを開けると、
5つのアイテムが「バババン!」と表示される演出が入っています。

さらに、アイテムの組み合わせによって
背景の色や演出が少し変わる仕掛けもあります。

  • スペシャルアイテムが多いとキラキラ演出
  • ユニークアイテムが多いとちょっとゆるい演出
  • ジョークアイテムが多いとコミカル演出

視覚的にも楽しい仕上がりになっています。(^v^)

🌈 まずは世界観を楽しんでね

操作方法は記事の後半で紹介しますので、
まずはこの“お楽しみボックス”の世界観を
ゆっくり味わっていただけたら嬉しいです。(^v^人)

■ AIとのやりとりで面白かった部分

● ゲーム仕様の相談からスタート

みー:(^v^) 今日もゲームを作ります。HTML形式で動くゲーム。

今回は「お楽しみボックスシミュレーター」の提案です。

  • 1000種類のアイテム
  • レア度の幅が広いアイテム構成
  • 1ボックスにつき5アイテム
  • 毎回ちがう組み合わせが出るランダム生成
  • 開封すると5つのアイテムが文字で表示
  • アイテムの組み合わせによって演出が変わる

こんな感じのワクワクするゲームを作りたいです。

AI: いらっしゃい!今日も来てくれたんだね。
まずは「ボックス文化」の雑学をひとつ──(雑学パート)

そして、あなたのアイデア通りに1000アイテムを用意しておいたよ。
レア度のバランスも調整済みさ。

● アイテムの幅をもっと広げたい

みー:(=v=) 商品名の種類をもっと増やせるかな?
レア度の高い“特別アイテム”も、ほんの少しだけ入れたいです。

AI: じゃあ今日の雑学は「小さな宝物」の話を──(雑学パート)

要望通り、

  • スペシャルアイテム
  • ジョークアイテム

を極小確率で追加しておいたよ。

● 演出の強化

みー:(^v^) 特別な組み合わせが出た時に、紙吹雪を降らせたいです。
スペシャルアイテムが多い時は、特別な色の紙吹雪で。

AI: 今日の雑学は「紙吹雪の語源」を──(雑学パート)

スペシャルアイテムが多い時はキラキラ紙吹雪、
ユニークアイテムが多い時はゆるい紙吹雪が舞うようにしたよ。

● コミカル演出も入れたい

みー:(めゅ)_ コミカル演出も入れましょう。
ジョークアイテムが出たら、ちょっと笑える演出で。

AI: 今日の小話は「失敗から生まれた発明」──(雑学パート)

ジョークアイテムが出た時の“コミカル演出”を追加したよ。
画面が少し暗くなったり、ゆるい効果音が鳴ったりするよ。


■ 実際の動作

● ゲームのスタート画面

(画像:スタート画面)

お楽しみボックスを開くボタンを押すと、
ボックスがガサガサ揺れるアニメーションが入り、
「何が出るかな?」というワクワク感が高まります。

● ボックス開封の瞬間

(画像:ボックス開封画面)


ボックスが開くと、
ランダムに選ばれた5つのアイテムが「ババン!」と表示されます。
毎回ちがう組み合わせになるので、
小さなサプライズのような楽しさがあります。

● アイテムの組み合わせによる演出

(画像:ゆるい演出)


ユニークアイテムが多い時は、
背景にゆるい雨が降る演出が入ります。
ちょっとしたコミカルさがあって楽しい雰囲気です。

(画像:キラキラ演出)

スペシャルアイテムが多い時は、
画面いっぱいに紙吹雪が舞い上がる“お祝い演出”になります。
一気に華やかなムードに。

(画像:特別演出)

さらに、特別な組み合わせが出た時は、
少し豪華な色の紙吹雪が降る“スペシャル演出”も用意しています。



■ コードのポイント

今回の記事では、AI と相談しながら作った
「お楽しみボックスシミュレーター」 の HTML コードを公開します。

このコードをそのまま保存するだけで、
あなたのPCでもすぐに遊べます。

ブラウザだけで動く、とてもシンプルなゲームなので、
気軽に試してみてくださいね。

▼ 遊ぶまでの手順

①PC の「メモ帳」(※Windowsの場合)や  
 Mac の「テキストエディット」など、テキストエディタを開きます。

②下のコードをコピーして貼り付けます。

③「otanosimi.html」など、好きな名前で保存します。
 (※拡張子は .html にしてください)

④保存したファイルをブラウザで開けば、すぐに遊べます。

 

■「お楽しみボックスシミュレーター」操作方法♪

操作はとってもシンプル! ボタンをぽちぽち押すだけです。(^v^)

ステップ1:ボックスを開く準備をする

ゲームを開始すると、画面中央に可愛い
「🎁」アイコンと 大きな 「ボックスを開く」 ボタンが表示されます。

このボタンをクリックしてください。

ステップ2:ボックスを開ける!

ボタンを押すと画面が切り替わり、
「🛍️」アイコンと 「開封する」 ボタンが登場します。

心の準備ができたら、このボタンをクリック(タップ)!

すると…… ボックスがガタガタと揺れ始めます。 w(゜o゜)w

約1.5秒ほどの「開封中…」演出。
ここが一番ワクワクする瞬間です。(・人・)

ステップ3:中身を確認して、もう一度!

開封演出が終わると、
ランダムに選ばれた5つのアイテムが バババン! と表示されます。

毎回ちがう組み合わせになるので、
小さなサプライズのような楽しさがあります。(^^)

■ 組み合わせに応じた演出

  • スペシャルアイテムが多い時:紙吹雪が舞う“お祝い演出” 🎉
  • ユニークアイテムが多い時:ゆるい雨が降るコミカル演出 ☔
  • ジョークアイテムが多い時:画面が少し暗くなる“ゆるい演出” 💀

どの演出になるかは、アイテムの組み合わせ次第です。

■ 最後に

いかがでしたか?(^^*) 操作はとってもシンプルで、
ボタンをぽちぽち押すだけ。

その裏では、1000個のアイテムから何が選ばれるか、
小さなドラマが毎回生まれています。(=v=*)

ぜひ、あなたの お気に入りの組み合わせ
見つけてみてくださいね!(^_^)ノ

“コードは長いので折りたたんでいます。必要な方は開いてご覧ください。”

▼ここからコード▼(クリックで開く)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>お楽しみボックスシミュレーター</title>
<style>
body {
text-align: center;
background-color: #f0f8ff;
font-family: 'Hiragino Maru Gothic ProN', 'Comic Sans MS', sans-serif;
margin: 0;
padding: 20px;
color: #333;
overflow: hidden;
transition: background-color 0.5s, color 0.5s;
}
#game-outer-container {
position: relative;
max-width: 500px;
margin: 0 auto;
}
#effect-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 100;
}
#game-container {
background-color: #fff;
border: 4px solid #ff4500;
border-radius: 15px;
padding: 30px;
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
position: relative;
z-index: 10;
transition: all 0.5s;
}
h1 {
color: #ff4500;
font-size: 24px;
transition: color 0.5s;
}
.bag-icon {
font-size: 100px;
margin: 20px 0;
cursor: pointer;
transition: transform 0.2s;
}
.bag-icon:hover {
transform: scale(1.1);
}
.shake {
animation: shake 0.5s infinite;
}
@keyframes shake {
0% { transform: translate(1px, 1px) rotate(0deg); }
10% { transform: translate(-1px, -2px) rotate(-5deg); }
20% { transform: translate(-3px, 0px) rotate(5deg); }
30% { transform: translate(3px, 2px) rotate(0deg); }
40% { transform: translate(1px, -1px) rotate(5deg); }
50% { transform: translate(-1px, 2px) rotate(-5deg); }
60% { transform: translate(-3px, 1px) rotate(0deg); }
70% { transform: translate(3px, 1px) rotate(-5deg); }
80% { transform: translate(-1px, -1px) rotate(5deg); }
90% { transform: translate(1px, 2px) rotate(0deg); }
100% { transform: translate(1px, -2px) rotate(-5deg); }
}
button {
background-color: #ff8c00;
color: white;
border: none;
padding: 15px 30px;
font-size: 18px;
border-radius: 8px;
cursor: pointer;
font-weight: bold;
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
}
button:hover {
background-color: #ff7f50;
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
#result-area {
display: none;
margin-top: 20px;
}
.item-list {
list-style-type: none;
padding: 0;
text-align: left;
background: #fffafa;
border: 2px dashed #ffa07a;
padding: 15px;
border-radius: 10px;
transition: background 0.5s, border-color 0.5s;
}
.item {
font-size: 16px;
margin-bottom: 10px;
border-bottom: 1px solid #ccc;
padding-bottom: 5px;
display: flex;
justify-content: space-between;
}
.total-price {
font-size: 28px;
font-weight: bold;
margin: 20px 0;
}
.win {
color: #dc143c;
animation: pop 0.5s ease-out;
}
.lose {
color: #4169e1;
}
.legendary {
color: #ffd700;
font-weight: bold;
text-shadow: 1px 1px 2px #000;
}
.trash {
color: #a9a9a9;
}
.message {
font-size: 22px;
font-weight: bold;
margin-bottom: 20px;
}
@keyframes pop {
0% { transform: scale(0.5); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
.hidden {
display: none;
}
/* どん底モードのスタイル */
body.rock-bottom-mode {
background-color: #0a0a0a;
color: #555;
}
body.rock-bottom-mode #game-container {
background-color: #1a1a1a;
border-color: #333;
box-shadow: 0 0 20px rgba(0,0,0,0.8);
animation: dropDown 1s ease-in forwards;
}
body.rock-bottom-mode h1 {
color: #666;
}
body.rock-bottom-mode .item-list {
background: #111;
border-color: #333;
}
body.rock-bottom-mode .lose {
color: #8b0000;
text-shadow: 2px 2px 4px #000;
}
@keyframes dropDown {
0% { transform: translateY(0) scale(1); filter: grayscale(0); }
50% { transform: translateY(20px) scale(0.98); filter: grayscale(0.5); }
100% { transform: translateY(50px) scale(0.95); filter: grayscale(1); opacity: 0.9; }
}
</style>
</head>
<body>
<div id="game-outer-container">
<canvas id="effect-canvas"></canvas>
<div id="game-container">
<h1>🛍️ お楽しみボックスシミュレーター</h1>
<p>中身は5つのアイテム!神引きか、それとも底なしの絶望か…</p>
<p style="font-size: 0.8em; color: #888;">※ボタンを押すと音が鳴ります</p>
<div id="shop-area">
<div class="bag-icon">🎁</div>
<button id="buy-btn">運試し!</button>
</div>
<div id="open-area" class="hidden">
<div class="bag-icon" id="target-bag">🛍️</div>
<button id="open-btn">お楽しみボックスをを開ける!</button>
</div>
<div id="result-area">
<h3>✨ お楽しみボックスの中身 ✨</h3>
<ul class="item-list" id="item-list"></ul>
<div class="total-price" id="total-price"></div>
<div class="message" id="result-message"></div>
<button id="retry-btn">もう一度挑戦する</button>
</div>
</div>
</div>
<script>
// --- 8bitサウンド生成システム(Web Audio API) ---
const AudioContext = window.AudioContext || window.webkitAudioContext;
let audioCtx;
let bgmInterval;
let bgmStep = 0;
let isBgmPlaying = false;
// レトロな波形(矩形波)で音を鳴らす
function playTone(freq, type, duration, vol=0.1) {
if (!audioCtx) return;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = type; // 'square' でファミコン風
osc.frequency.setValueAtTime(freq, audioCtx.currentTime);
gain.gain.setValueAtTime(vol, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + duration);
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start();
osc.stop(audioCtx.currentTime + duration);
}
// BGM再生
function startBGM() {
if (!audioCtx) {
audioCtx = new AudioContext();
}
if (audioCtx.state === 'suspended') audioCtx.resume();
if (isBgmPlaying) return;
isBgmPlaying = true;
// ちょっと気の抜けたお店のBGMループ
const melody = [261.63, 0, 329.63, 0, 392.00, 392.00, 523.25, 0, 392.00, 0, 329.63, 0, 261.63, 0, 0, 0];
bgmInterval = setInterval(() => {
let note = melody[bgmStep % melody.length];
if (note > 0) playTone(note, 'square', 0.15, 0.03); // BGMは少し音量小さめ
bgmStep++;
}, 200);
}
function stopBGM() {
clearInterval(bgmInterval);
isBgmPlaying = false;
}
// 各種効果音
function playBuySE() {
playTone(880, 'square', 0.1, 0.1); // ピッ
}
function playDrumRollSE() {
// ドコドコドコという期待感を煽る音
let count = 0;
let roll = setInterval(() => {
playTone(150 + Math.random()*50, 'square', 0.05, 0.1);
count++;
if (count > 25) clearInterval(roll);
}, 50);
}
function playWinSE() {
// ファンファーレ風
playTone(523.25, 'square', 0.1, 0.1); // C
setTimeout(() => playTone(659.25, 'square', 0.1, 0.1), 150); // E
setTimeout(() => playTone(783.99, 'square', 0.4, 0.1), 300); // G
}
function playGodSE() {
// 神引きの激しいアルペジオ
for(let i=0; i<10; i++) {
setTimeout(() => playTone(523.25 + i*100, 'square', 0.1, 0.1), i*80);
}
}
function playLoseSE() {
// 残念な下降音
playTone(392.00, 'square', 0.2, 0.1); // G
setTimeout(() => playTone(349.23, 'square', 0.2, 0.1), 250); // F
setTimeout(() => playTone(329.63, 'square', 0.5, 0.1), 500); // E
}
function playDespairSE() {
// 絶望の低音
playTone(100, 'sawtooth', 1.0, 0.2); // 重いブー音
setTimeout(() => playTone(80, 'sawtooth', 1.5, 0.2), 300);
}
// --- エフェクトシステム(紙吹雪 & 雨) ---
class EffectSystem {
constructor(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.particles = [];
this.effectType = 'none';
this.animationId = null;
this.resize();
window.addEventListener('resize', () => this.resize());
}
resize() {
this.canvas.width = this.canvas.parentElement.offsetWidth;
this.canvas.height = this.canvas.parentElement.offsetHeight;
}
start(type) {
this.stop();
this.effectType = type;
if (type === 'none') return;
this._createParticles();
this._loop();
}
stop() {
if (this.animationId) {
cancelAnimationFrame(this.animationId);
this.animationId = null;
}
this.particles = [];
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
_createParticles() {
let count = 100;
if (this.effectType === 'gold') count = 150;
if (this.effectType === 'rain') count = 150;
const colorful = ['#FFC0CB', '#FF69B4', '#FF1493', '#ADFF2F', '#7CFC00', '#00FFFF', '#1E90FF', '#FFD700'];
const gold = ['#FFD700', '#DAA520', '#B8860B', '#F4A460', '#FFE4B5'];
const rain = ['rgba(100, 149, 237, 0.6)', 'rgba(70, 130, 180, 0.6)', 'rgba(176, 196, 222, 0.6)'];
for (let i = 0; i < count; i++) {
let p = {
x: Math.random() * this.canvas.width,
y: Math.random() * this.canvas.height - this.canvas.height,
opacity: 1
};
if (this.effectType === 'rain') {
p.sizeX = 2;
p.sizeY = Math.random() * 15 + 10;
p.color = rain[Math.floor(Math.random() * rain.length)];
p.speedX = Math.random() * 0.5 - 0.25;
p.speedY = Math.random() * 10 + 15;
p.angle = 0;
p.spin = 0;
} else {
let colors = this.effectType === 'gold' ? gold : colorful;
p.sizeX = Math.random() * 8 + 4;
p.sizeY = p.sizeX;
p.color = colors[Math.floor(Math.random() * colors.length)];
p.speedX = Math.random() * 2 - 1;
p.speedY = Math.random() * 3 + 2;
p.angle = Math.random() * Math.PI * 2;
p.spin = Math.random() * 0.2 - 0.1;
}
this.particles.push(p);
}
}
_updateParticles() {
for (let i = 0; i < this.particles.length; i++) {
const p = this.particles[i];
p.x += p.speedX;
p.y += p.speedY;
p.angle += p.spin;
if (this.effectType !== 'rain') {
p.opacity -= 0.002;
}
if (p.y > this.canvas.height) {
if (this.effectType === 'rain') {
p.y = -p.sizeY;
p.x = Math.random() * this.canvas.width;
} else if (p.opacity < 0) {
this.particles.splice(i, 1);
i--;
}
}
}
}
_drawParticles() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.particles.forEach(p => {
this.ctx.save();
this.ctx.globalAlpha = p.opacity;
this.ctx.translate(p.x, p.y);
this.ctx.rotate(p.angle);
this.ctx.fillStyle = p.color;
this.ctx.fillRect(-p.sizeX / 2, -p.sizeY / 2, p.sizeX, p.sizeY);
this.ctx.restore();
});
}
_loop() {
this._updateParticles();
this._drawParticles();
if (this.particles.length > 0 || this.effectType === 'rain') {
this.animationId = requestAnimationFrame(() => this._loop());
} else {
this.animationId = null;
}
}
}
// アイテムプールの生成
const itemPool = [];
const categories = [
{ name: "神", min: 999999, max: 999999, prob: 0.001, class: "legendary", items: ["無人島", "宇宙旅行ペアチケット", "伝説の聖剣", "世界一周クルーズ券"] },
{ name: "超絶レア", min: 100000, max: 300000, prob: 0.009, class: "win", items: ["幻の純金製コーヒーミル", "ハワイ旅行ペアチケット", "最新ゲーミングPCフルセット", "高級ブランドの腕時計", "謎の天才画家の絵画", "高級ホームシアターセット", "プロ用一眼レフカメラ"] },
{ name: "大当たり", min: 30000, max: 99900, prob: 0.09, class: "", items: ["最新スマートフォン", "松阪牛1頭分(部位セット)", "ロボット掃除機最上位モデル", "オーダーメイドスーツお仕立券", "高級電動アシスト自転車", "有名温泉ペア宿泊券", "高級羽毛布団"] },
{ name: "当たり", min: 10000, max: 29900, prob: 0.20, class: "", items: ["ノイズキャンセリングイヤホン", "高級フレンチペア食事券", "全自動コーヒーメーカー", "有名デザイナーの椅子", "国産うなぎ蒲焼10尾", "高級和牛すき焼きセット", "コードレス掃除機", "美容家電セット"] },
{ name: "普通", min: 3000, max: 9900, prob: 0.30, class: "", items: ["特選コーヒー豆1kg", "おしゃれなペアマグカップ", "人気のボードゲーム", "アロマディフューザー", "今治タオル高級セット", "ご当地レトルトカレーセット", "高級オリーブオイル", "Bluetoothスピーカー", "モバイルバッテリー"] },
{ name: "ハズレ", min: 100, max: 2900, prob: 0.399, class: "", items: ["マスターの特製ステッカー", "うまい棒1年分", "謎の木彫りの熊", "消しゴム詰め合わせ", "ただのタワシ", "肩たたき券", "ポケットティッシュ100個", "よくわからない置物", "大量の輪ゴム", "派手な柄の靴下"] },
{ name: "絶望", min: 1, max: 1, prob: 0.001, class: "trash", items: ["道端の石ころ", "ちぎれた輪ゴム", "誰かのサインの切れ端", "使用済み切手", "期限切れのクーポン"] }
];
for(let i = 0; i < 1000; i++) {
let rand = Math.random();
let cumulativeProb = 0;
let selectedTier;
for (let tier of categories) {
cumulativeProb += tier.prob;
if (rand < cumulativeProb) {
selectedTier = tier;
break;
}
}
let price = selectedTier.min === selectedTier.max ? selectedTier.min : Math.floor((Math.random() * (selectedTier.max - selectedTier.min) + selectedTier.min) / 100) * 100;
let itemName = selectedTier.items[Math.floor(Math.random() * selectedTier.items.length)];
itemPool.push({ name: itemName, price: price, class: selectedTier.class });
}
// 要素の取得
const shopArea = document.getElementById('shop-area');
const openArea = document.getElementById('open-area');
const resultArea = document.getElementById('result-area');
const buyBtn = document.getElementById('buy-btn');
const openBtn = document.getElementById('open-btn');
const retryBtn = document.getElementById('retry-btn');
const targetBag = document.getElementById('target-bag');
const itemList = document.getElementById('item-list');
const totalPriceEl = document.getElementById('total-price');
const resultMessage = document.getElementById('result-message');
const effectCanvas = document.getElementById('effect-canvas');
const effects = new EffectSystem(effectCanvas);
buyBtn.addEventListener('click', () => {
playBuySE();
startBGM(); // オーディオコンテキストの起動とBGM開始
shopArea.classList.add('hidden');
openArea.classList.remove('hidden');
});
openBtn.addEventListener('click', () => {
targetBag.classList.add('shake');
openBtn.disabled = true;
openBtn.textContent = "開封中...";
stopBGM(); // 開封中はBGMを止めてドラムロール
playDrumRollSE();
setTimeout(() => {
targetBag.classList.remove('shake');
openArea.classList.add('hidden');
showResults();
}, 1500);
});
function showResults() {
resultArea.style.display = 'block';
itemList.innerHTML = '';
let total = 0;
let hasDespair = false;
const shuffled = [...itemPool].sort(() => 0.5 - Math.random());
const selectedItems = shuffled.slice(0, 5);
selectedItems.forEach(item => {
if (item.price === 1) hasDespair = true;
const li = document.createElement('li');
li.className = 'item';
const nameSpan = document.createElement('span');
nameSpan.textContent = item.name;
if (item.class) nameSpan.classList.add(item.class);
const priceSpan = document.createElement('span');
priceSpan.textContent = `${item.price.toLocaleString()}円`;
if (item.class) priceSpan.classList.add(item.class);
li.appendChild(nameSpan);
li.appendChild(priceSpan);
itemList.appendChild(li);
total += item.price;
});
totalPriceEl.textContent = `総額: ${total.toLocaleString()}円`;
const cost = 50000;
if (hasDespair) {
document.body.classList.add('rock-bottom-mode');
totalPriceEl.className = 'total-price lose';
resultMessage.textContent = `💀 絶望の淵へようこそ… 全てを失った気分だね…`;
resultMessage.className = 'message lose';
effects.start('none');
playDespairSE();
}
else if (total >= 999999) {
totalPriceEl.className = 'total-price win';
resultMessage.textContent = `🌟 神引き!!! 伝説を目撃したね! 🌟`;
resultMessage.className = 'message win';
effects.start('gold');
playGodSE();
}
else if (total > cost) {
totalPriceEl.className = 'total-price win';
resultMessage.textContent = `🎉 大勝利! ${ (total - cost).toLocaleString() }円の得だね! 🎉`;
resultMessage.className = 'message win';
effects.start(total > 200000 ? 'gold' : 'colorful');
playWinSE();
}
else if (total === cost) {
totalPriceEl.className = 'total-price';
resultMessage.textContent = "奇跡のトントン! 損はしてないよ!";
resultMessage.className = 'message';
effects.start('none');
playBuySE();
}
else {
totalPriceEl.className = 'total-price lose';
resultMessage.textContent = `💸 痛恨! ${ (cost - total).toLocaleString() }円の損… 冷たい雨が心に染みるね。`;
resultMessage.className = 'message lose';
effects.start('rain');
playLoseSE();
}
}
retryBtn.addEventListener('click', () => {
playBuySE();
startBGM(); // 再度BGMをスタート
resultArea.style.display = 'none';
shopArea.classList.remove('hidden');
openBtn.disabled = false;
openBtn.textContent = "福袋を開ける!";
document.body.classList.remove('rock-bottom-mode');
effects.stop();
});
</script>
</body>
</html>



■ 今日の学び

今回は、このゲームを作る中で感じた、
私なりの「学び」についてお話ししたいと思います。d(^^o)

■ “中身が分からないワクワク感”の魅力(=v=*)

昔から、袋や箱を開けるときの
「何が入っているんだろう?」というワクワク感が大好きなんです。

最近は中身が最初から分かるセット商品も増えましたが、
やっぱり私は、開ける瞬間のドキドキが一番楽しいなぁと思っていて……。

そこで今回は、 中身が毎回ランダムに変わる“お楽しみボックス”の面白さ
ゲームとして表現してみました。

■ ランダム生成の“絶妙なバランス”(^艸^)

ゲームとしての楽しさを出すために、
アイテムの種類やレア度のバランスを工夫しました。

  • 1000種類のアイテムを用意
  • レア度の高いアイテムは極小確率
  • ジョークアイテムも少しだけ混ぜる
  • 組み合わせによって演出が変わる

この「ちょっとしたサプライズ感」が、
毎回の開封を楽しくしてくれます。(^^)

■ 何度でも開けたくなる魅力(≧▽≦*)

実際にプレイしてみて感じたのは……

  • 「お気に入りの組み合わせが出るまで、もう一回開けたい!」
  • 「さっきはジョークアイテムが多かったけど、次はどうかな?」

という、 つい何度も開けたくなる不思議な魅力でした。(^^;)

「何が出るか分からない」という体験は、
ゲームになるとこんなにも楽しいんだなぁと実感しました。

■ 現実の“お楽しみボックス”の思い出(^_^)~

ところで、みなさんは現実で
「中身が分からない袋や箱」を開けた思い出、何かありますか?

私は雑貨屋さんのセット商品が大好きで……
生活雑貨からガーデニンググッズまで、 本当にいろいろ入っていました。

中には「あちゃ〜(^^;)」というユニークなアイテムもあって……

  • チョコレートの香りの入浴剤(@@;)
  • 金色のスリッパ(=°Д°=)

今思えば、そんな“使いどころに困るもの”も含めて、
後で笑い話になるのが楽しいんですよね。(=v=*)

■ ついに……レアアイテムが出ました!

何度か開封を繰り返していたのですが、 ついにその瞬間が訪れました。

・・・30分ほど遊んで、ようやくレア度の高いアイテムが出ました。

(画像:レアアイテムの画像)

思わず「やったー!」と声が出ちゃいました。(≧▽≦*)

この“いつ出るか分からないワクワク感”こそ、
お楽しみボックスの魅力だなぁと感じました。

■ 次回は、
地味な趣味と思われがちな、盆栽をゲームにしてみました。

時間をかけて、自分だけの盆栽を育てていくゲームです。

実際の成長スピードの 何百倍 もの速さで成長する松の木を、

  • 枝の形を整えたり
  • 余分な葉を取ったり
  • 枝ぶりを調整したり

そんな“手入れ”をしながら育てていきます。

次回もぜひ遊びに来てくださいね。(*^v^)ノシ

▶ 次の実験はこちら  
  人の手による自然の制御)「盆栽職人~松の造形~」



 ✨今日も最後まで読んでくださって、ありがとうございます。
みーの実験室は、みなさんの応援で元気に動いています。(*^v^*)

~このブログについて~

AIと一緒に遊び、
100の実験でゲームを育てるブログ

🌈初めての方へ
🌱このブログについて
🌳実験一覧
🍃プライバシーポリシー
🐣未記事ゲーム展示室


AIと作る100のゲーム実験室(*^v^*)をもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む