準備就寢前,突然想玩玩小時候的彈珠台 (柏青哥)遊戲,上網查了一下,居然找不到可以馬上開玩的柏青哥Game。
那只好借助AI 的生成式大神的力量,快速產生一個。
至Gemini (思考型)+建立圖像,
1.prompt:
產生如一張柏青哥 機台的圖,這張圖是一台非常經典的昭和時期(約 1970 年代)的「三洋(Sanyo)」手打式柏青哥機台,主題是「Three Ocean」。
它的最大特色在於:
左側發射軌道:球不是直接出現在上面,而是從左下角被「打」上去的。特定的入賞口結構:中間有一個大役物(像是臉譜或飛機的造型),下方有三個類似鬱金香(Tulip)的開闔式接球座(黑/紅/白)。
手感控制:需要控制發射力道,太弱球上不去,太強會直接打到右邊死區。
產生一個火焰和鬱金香形象的機台。
產生的圖如下:

- 將圖上傳至 gemini,加上 prompt:
撰寫以上面圖像的柏青哥 機台網頁開發的遊戲<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>霓虹火焰柏青哥 (Neon Fire Pachinko)</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #050505;
color: white;
font-family: 'Segoe UI', Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
height: 100vh;
overflow: hidden;
}
/* 機台外殼 */
#game-wrapper {
position: relative;
margin-top: 20px;
/* 模擬圖中的黑色鋼琴烤漆外框與紅色光暈 */
border: 20px solid #111;
border-radius: 30px 30px 10px 10px;
box-shadow:
0 0 10px #000,
inset 0 0 50px rgba(255, 0, 50, 0.5), /* 內部紅光 */
0 0 40px rgba(255, 0, 50, 0.3); /* 外部紅光 */
background: #000;
}
/* 遊戲主畫面 - 模擬圖中的藍紅漸層 */
#game-container {
background: radial-gradient(circle at 50% 40%,
#001a33 0%, /* 中心深藍 */
#003366 30%, /* 中層藍 */
#000000 60%, /* 過渡黑 */
#660000 80%, /* 外層暗紅 */
#ff0000 100% /* 邊緣亮紅 */
);
border-radius: 10px;
overflow: hidden;
}
/* 閃爍特效 (中獎時觸發) */
@keyframes flashEffect {
0% { filter: brightness(1); }
50% { filter: brightness(1.5) hue-rotate(90deg); }
100% { filter: brightness(1); }
}
.flash {
animation: flashEffect 0.2s linear 2;
}
/* 抬頭顯示器 (HUD) */
#ui-layer {
position: absolute;
top: 20px;
right: 20px;
text-align: right;
pointer-events: none;
z-index: 10;
}
.hud-box {
background: rgba(0, 0, 0, 0.6);
border: 1px solid #00ccff;
padding: 5px 15px;
border-radius: 4px;
margin-bottom: 5px;
box-shadow: 0 0 10px #00ccff;
}
.hud-label { font-size: 10px; color: #00ccff; letter-spacing: 1px; }
.hud-value { font-size: 24px; font-weight: bold; color: #fff; text-shadow: 0 0 5px #fff; }
/* 控制面板 */
#control-panel {
margin-top: 20px;
padding: 15px 30px;
background: linear-gradient(to bottom, #222, #111);
border-radius: 15px;
border-top: 2px solid #333;
display: flex;
align-items: center;
gap: 30px;
box-shadow: 0 10px 20px rgba(0,0,0,0.8);
}
/* 力道旋鈕 */
.knob-container {
display: flex;
flex-direction: column;
align-items: center;
}
input[type=range] {
width: 200px;
height: 8px;
-webkit-appearance: none;
background: #333;
border-radius: 5px;
outline: none;
border: 1px solid #555;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 24px;
height: 24px;
border-radius: 50%;
background: #ff0055; /* 霓虹紅 */
cursor: pointer;
box-shadow: 0 0 10px #ff0055;
border: 2px solid #fff;
}
/* 發射按鈕 */
.launch-btn {
width: 70px;
height: 70px;
border-radius: 50%;
border: 3px solid #fff;
background: radial-gradient(circle, #ff0000, #990000);
color: white;
font-weight: bold;
font-size: 16px;
cursor: pointer;
box-shadow: 0 0 15px #ff0000;
transition: transform 0.1s;
text-shadow: 0 2px 0 #000;
}
.launch-btn:active {
transform: scale(0.92);
box-shadow: 0 0 5px #ff0000;
}
/* 下方紅色接球盤 */
.tray {
margin-top: -15px;
width: 300px;
height: 40px;
background: linear-gradient(to bottom, #cc0000, #660000);
border-radius: 0 0 20px 20px;
border: 2px solid #440000;
box-shadow: 0 5px 10px rgba(0,0,0,0.5);
z-index: 5;
}
/* 得分飄浮字 */
.score-popup {
position: absolute;
font-weight: 900;
font-size: 28px;
color: #fff;
-webkit-text-stroke: 1px #ff0055;
pointer-events: none;
animation: floatUp 0.8s ease-out forwards;
z-index: 100;
text-shadow: 0 0 10px #ff0055;
}
@keyframes floatUp {
0% { transform: translateY(0) scale(0.5); opacity: 0; }
20% { transform: translateY(-10px) scale(1.2); opacity: 1; }
100% { transform: translateY(-50px) scale(1); opacity: 0; }
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
</head>
<body>
<div id="game-wrapper">
<div id="ui-layer">
<div class="hud-box">
<div class="hud-label">WIN</div>
<div class="hud-value" id="win-display">0</div>
</div>
<div class="hud-box">
<div class="hud-label">CREDITS</div>
<div class="hud-value" id="balls-display">100</div>
</div>
</div>
<div id="game-container"></div>
</div>
<div class="tray"></div>
<div id="control-panel">
<div class="knob-container">
<label style="color:#aaa; font-size:12px; margin-bottom:8px; letter-spacing:1px;">POWER CONTROL</label>
<input type="range" id="power-slider" min="20" max="65" value="42" step="1">
<div style="display:flex; justify-content:space-between; width:100%; font-size:10px; color:#555; margin-top:5px;">
<span>MIN</span>
<span>MAX</span>
</div>
</div>
<button class="launch-btn" id="fire-btn" onclick="launchBall()">PUSH</button>
</div>
<script>
const Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Bodies = Matter.Bodies,
Composite = Matter.Composite,
Events = Matter.Events,
Body = Matter.Body,
Vector = Matter.Vector;
// 提高物理計算迭代次數,防止球高速穿牆
const engine = Engine.create({
positionIterations: 12,
velocityIterations: 10
});
const world = engine.world;
engine.gravity.y = 1.1; // 稍微增加重力,讓球掉落更有感
const width = 450;
const height = 650;
const render = Render.create({
element: document.getElementById('game-container'),
engine: engine,
options: {
width: width,
height: height,
wireframes: false,
background: 'transparent' // 使用 CSS 背景
}
});
const walls = [];
// --- 1. 機台邊界與導流結構 ---
// 邊框
walls.push(Bodies.rectangle(width/2, -60, width, 100, { isStatic: true, render: {fillStyle: '#111'} })); // 頂
walls.push(Bodies.rectangle(width+15, height/2, 30, height, { isStatic: true, render: {fillStyle: '#111'} })); // 右
walls.push(Bodies.rectangle(-15, height/2, 30, height, { isStatic: true, render: {fillStyle: '#111'} })); // 左
// 左側發射軌道內壁 (半透明紫色,配合霓虹風格)
const trackInner = Bodies.rectangle(55, height/2 + 80, 8, height - 160, {
isStatic: true,
render: { fillStyle: 'rgba(200, 0, 255, 0.4)' }
});
// **關鍵修正**:頂部導流三角 (Kicker)
// 確保球撞到頂部後一定往右彈
const topKicker = Bodies.rectangle(15, 15, 120, 20, {
isStatic: true,
angle: 0.7,
render: { fillStyle: '#ff0055' } // 亮紅色
});
// 頂部圓弧軌道 (裝飾與物理)
const topCurve = [];
for(let i=4; i<18; i++) {
let angle = Math.PI + (i * 0.1);
let px = 200 + Math.cos(angle) * 160;
let py = 200 + Math.sin(angle) * 160;
if (px > 60 && px < 350 && py < 200) {
// 使用發光的藍色小圓點模擬 LED
topCurve.push(Bodies.circle(px, py, 4, {
isStatic: true,
render: { fillStyle: '#00ccff', strokeStyle: '#fff', lineWidth: 1 }
}));
}
}
// 底部死區 (Drain)
const drain = Bodies.rectangle(width/2, height + 40, width, 60, { isStatic: true, isSensor: true, label: 'drain' });
Composite.add(world, [...walls, trackInner, topKicker, ...topCurve, drain]);
// --- 2. 釘子 (Nails) ---
// 模擬釘子排列
const pins = [];
function createPin(x, y) {
return Bodies.circle(x, y, 2, {
isStatic: true,
restitution: 0.5,
render: { fillStyle: '#e6e6e6' } // 銀色釘子
});
}
for(let row=0; row<14; row++) {
for(let col=0; col<16; col++) {
let x = 70 + col * 22; // 避開左側軌道
let y = 140 + row * 25;
if(row % 2 === 0) x += 11; // 交錯排列
// 避開中央大獎區
if (x > 140 && x < 310 && y > 200 && y < 380) continue;
// 避開軌道區
if (x < 65) continue;
// 隨機微調位置,增加物理隨機性
x += (Math.random() - 0.5) * 4;
pins.push(createPin(x, y));
}
}
Composite.add(world, pins);
// --- 3. 入賞口 (Pockets) ---
// 通用入賞口產生器
function createPocket(x, y, type, score) {
const color = type === 'fire' ? '#ff3300' : (type === 'tulip' ? '#ff0055' : '#00ccff');
// 兩側擋板 (模擬鬱金香花瓣)
const w1 = Bodies.rectangle(x - 14, y - 8, 6, 25, { isStatic: true, angle: -0.3, render: { fillStyle: color } });
const w2 = Bodies.rectangle(x + 14, y - 8, 6, 25, { isStatic: true, angle: 0.3, render: { fillStyle: color } });
// 底部感應器
const sensor = Bodies.rectangle(x, y + 5, 20, 10, {
isStatic: true, isSensor: true, label: 'pocket',
plugin: { score: score, type: type },
render: { fillStyle: '#000' }
});
// 裝飾光圈
const deco = Bodies.circle(x, y-5, 12, {
isStatic: true, isSensor: true,
render: {
fillStyle: color,
opacity: 0.5
}
});
return [w1, w2, sensor, deco];
}
// A. 中央火焰大獎 (Fire Center) - 圖中上方那個圓形
const centerFeature = Bodies.circle(width/2, 280, 45, {
isStatic: true, isSensor: true, label: 'pocket',
plugin: { score: 100, type: 'fire' },
render: {
fillStyle: '#ff2200', // 火焰紅
strokeStyle: '#ffcc00', // 金邊
lineWidth: 4
}
});
// 中央大獎周圍的保護釘與裝飾
const centerGuardL = Bodies.rectangle(width/2 - 55, 280, 8, 60, { isStatic: true, angle: -0.1, render: {fillStyle: '#003366'} });
const centerGuardR = Bodies.rectangle(width/2 + 55, 280, 8, 60, { isStatic: true, angle: 0.1, render: {fillStyle: '#003366'} });
Composite.add(world, [centerFeature, centerGuardL, centerGuardR]);
// B. 下方鬱金香 (Tulips) - 紅色
Composite.add(world, createPocket(width/2, 530, 'tulip', 50)); // 正下方
// C. 兩側小獎 (Wings) - 藍色
Composite.add(world, createPocket(110, 450, 'wing', 15)); // 左
Composite.add(world, createPocket(width - 110, 450, 'wing', 15)); // 右
// --- 4. 遊戲邏輯 ---
let balls = 100;
let win = 0;
const ballsDisplay = document.getElementById('balls-display');
const winDisplay = document.getElementById('win-display');
const fireBtn = document.getElementById('fire-btn');
const gameContainer = document.getElementById('game-container');
function launchBall() {
if (balls <= 0) {
alert("CREDITS EMPTY! (沒球了)");
return;
}
balls--;
ballsDisplay.innerText = balls;
// 按鈕動畫
fireBtn.style.transform = "scale(0.9)";
setTimeout(() => fireBtn.style.transform = "scale(1)", 100);
// 球體生成:銀色金屬質感
const startX = 25;
const startY = height - 80;
const ball = Bodies.circle(startX, startY, 5.5, {
restitution: 0.6,
friction: 0.001, // 低摩擦
frictionAir: 0.00, // 發射瞬間無空氣阻力
density: 0.08, // 重金屬感
label: 'ball',
render: {
fillStyle: '#eee',
strokeStyle: '#999',
lineWidth: 1
}
});
Composite.add(world, ball);
// 發射力道計算
const sliderVal = parseFloat(document.getElementById('power-slider').value);
// 加上隨機誤差模擬真實彈簧
const randomVar = (Math.random() - 0.5) * 2;
const power = sliderVal + randomVar;
// 物理向量:強大的垂直力道 + 適度的水平推力
const forceY = -(power * 0.00075); // 係數微調
const velocityX = 4.0; // 強制水平速度,配合頂部 Kicker
// 設定初速與空氣阻力恢復
Body.setVelocity(ball, { x: velocityX, y: -20 }); // 給予初速防止卡住
Body.applyForce(ball, ball.position, { x: 0, y: forceY });
// 0.6秒後恢復空氣阻力,讓球掉落時比較自然
setTimeout(() => {
if(ball) ball.frictionAir = 0.01;
}, 600);
}
// --- 5. 碰撞與計分系統 ---
Events.on(engine, 'collisionStart', (event) => {
event.pairs.forEach((pair) => {
const bodyA = pair.bodyA;
const bodyB = pair.bodyB;
checkScore(bodyA, bodyB);
checkScore(bodyB, bodyA);
checkDrain(bodyA, bodyB);
checkDrain(bodyB, bodyA);
});
});
function checkScore(ball, target) {
if (ball.label === 'ball' && target.label === 'pocket') {
const points = target.plugin.score;
const type = target.plugin.type;
// 更新分數
win += points;
balls += points;
winDisplay.innerText = win;
ballsDisplay.innerText = balls;
// 視覺特效
triggerFlash();
showPopup(ball.position.x, ball.position.y, points, type);
// 移除球
Composite.remove(world, ball);
}
}
function checkDrain(ball, target) {
if (ball.label === 'ball' && target.label === 'drain') {
Composite.remove(world, ball);
}
}
// 背景閃爍特效
function triggerFlash() {
gameContainer.classList.remove('flash');
void gameContainer.offsetWidth; // 強制重繪
gameContainer.classList.add('flash');
}
// 得分飄浮數字
function showPopup(x, y, points, type) {
const el = document.createElement('div');
el.className = 'score-popup';
el.innerText = points;
// 根據類型設定顏色
let color = '#fff';
if (type === 'fire') color = '#ffcc00'; // 金色
else if (type === 'tulip') color = '#ff0055'; // 紅色
else color = '#00ccff'; // 藍色
el.style.left = (x + 20) + 'px';
el.style.top = (y - 20) + 'px';
el.style.color = color;
el.style.textShadow = `0 0 10px ${color}`;
document.getElementById('game-wrapper').appendChild(el);
setTimeout(() => el.remove(), 800);
}
// 鍵盤控制 (空白鍵)
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') launchBall();
});
// 啟動引擎
Render.run(render);
const runner = Runner.create();
Runner.run(runner, engine);
</script>
</body>
</html>
用notepad 將網頁語法存成: game.html,
畫面如下:

另一版本如下圖:

結語
*Gemini產生這類小遊戲,幾乎一次搞定,很少會有語法錯誤的情形,
同樣用ChatGPT 就有點花時間,多次Prompt 語句修正和平台console除錯,才生成類似的結果。
*其實以工程師的角度,AI協助生成程式,幫了不少大忙,減少了不少除錯和系統分析的時間。


