
游戏
每主配置:一个棋子(代表“奴隶”)
核心玩法: 主人投骰子对弈!主人轮流掷骰子,移动自己的奴隶棋子。落地后立即执行该格的调教要求**(主人对奴隶下达并监督)。
胜利条件: 第一个让奴隶棋子到达或超过终点的主人获胜,其奴隶“毕业”!其他主人继续玩到全部完成(可多人同时冲刺,超刺激)。
规则亮点(确保趣味性强 + 穿插前进后退):
- 纯非性:所有任务只有服从、服务、姿势、轻纪律、宠物扮演、口头赞美、身体小挑战,无任何性行为。
- 安全第一:全程SSC(安全、理智、同意),随时喊“红灯”停止,强度可自行调节。
- 趣味设计:任务幽默、互动、带仪式感,像在玩“真人版奴隶养成游戏”。
- 前进/后退穿插:部分格子奖励“主人开心,奴隶加飞”,部分格子惩罚“训练失败,奴隶倒退”,增加策略与笑点。
详细调教要求(落地即执行,完成后看括号里的移动效果):
- 奴跪下为自己的主人进行足部崇拜(舔脚、吸脚趾),持续骰子点数×10秒。
- 奴为对方奴戴上项圈并牵行一圈。
- 奴自扇屁股(轻拍或重拍),点数×2下,同时抵消对方一次物理攻击。
- 奴用舌头为自己的主人清洁鞋子或脚底,持续骰子点数×5秒。
- 奴给对方奴戴眼罩,亲吻对方脖子10秒。
- 奴摆出M字腿姿势暴露给两位主人观看,维持骰子点数×5秒。
- 奴为自己的主人提供跪式口交服务(模拟),持续骰子点数×5秒。
- 奴临时“反客为主”,命令对方奴跪下叫“主人”点子数声。
- 奴自绑双手(用丝带或手铐),抵消对方一次前进。
- 奴用蜡烛滴蜡在自己大腿(安全位置),滴数=骰子点数×2。
- 奴为对方奴进行轻度鞭打(软鞭或手掌),次数对应骰子点数。
- 奴临时支配对方奴舔自己脚,持续骰子点数×15秒。
- 奴摆出宠物姿势(四肢着地、汪汪叫),持续骰子点数X2并额外移动1格。
- 奴狗叫并摇臀,次数=骰子点数×2。
- 奴强制对方奴舔自己的脚趾,持续骰子点数×10秒。
- 奴表演缓慢脱衣舞给所有人看,完成后可让对方主人少掷一次骰。
- 奴自夹乳头(用夹子或手指),夹住骰子点数×10秒。
- 奴为自己的主人提供骑乘式服务,持续骰子点数×10秒。
- 奴把对方奴绑成龟甲缚姿势展示,维持骰子点数×20秒。
- 奴跪下高潮边缘控制(自摸但不能高潮)。
- 奴为两位主人同时口侍手指(模拟口交),每人点数秒。
- 奴让对方奴骑在自己背上绕圈走1圈。
- 奴自打耳光(轻度),次数=骰子点数×3,同时获得一次额外掷骰机会。
- 奴跪下为自己的主人献上“宠物式”摩擦大腿,维持骰子点数×10秒。
- 奴表演“乞求高潮”姿势(双手举高、跪地恳求),持续骰子点数×5秒。
- 奴摆出后入式姿势让主人轻拍,拍数=骰子点数×5。
- 奴临时支配对方奴为自己做口交姿势展示,持续骰子点数×15秒。
- 奴表演“乞求高潮”姿势(双手举高、跪地恳求),持续骰子点数×5秒。
- 奴为自己的主人献上深喉服务(模拟),持续骰子点数X5秒。
- 奴命令对方奴爬到自己胯下亲吻,持续骰子点数×20秒。
- 奴跪下为自己的主人献上“宠物式”摩擦大腿,持续骰子点数×10秒。
- 奴表演“乞求高潮”姿势(双手举高、跪地恳求),持续骰子点数×5秒。
- 奴让对方奴为自己做足部按摩,持续骰子点数×20秒。
- 奴把对方奴按倒轻度骑乘,持续骰子点数×10秒。
- 奴自扇私密部位(轻拍),次数=骰子点数×4,同时对方少掷一次骰。
- 奴命令对方奴学狗叫并舔自己手指。
- 奴摆出完全暴露的“展示姿势”给所有人评分,点数越高维持越久;若获好评,可让本队额外前进骰子点数格。
- 奴表演“乞求高潮”姿势(双手举高、跪地恳求),持续骰子点数×5秒。
这个设计完全围绕“多主多奴调教”展开,每一格都是主人对奴隶的真实小训练,同时主人之间用骰子对弈竞争,趣味性爆棚!
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>趣乐飞行棋</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background: linear-gradient(145deg, #1e2b3c 0%, #0f1a24 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Segoe UI', Roboto, system-ui, -apple-system, sans-serif;
padding: 20px;
overflow-x: hidden;
position: relative;
}
.game-container {
max-width: 1300px;
width: 100%;
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(4px);
border-radius: 60px 60px 40px 40px;
padding: 30px 30px 40px;
box-shadow: 0 30px 40px -15px rgba(0,0,0,0.6), inset 0 1px 3px rgba(255,255,255,0.1);
border: 1px solid rgba(255,255,255,0.06);
transition: filter 0.2s ease;
position: relative;
z-index: 1;
}
/* 掷骰动画遮罩 */
.dice-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
backdrop-filter: blur(5px);
z-index: 999;
display: flex;
justify-content: center;
align-items: center;
visibility: hidden;
opacity: 0;
transition: opacity 0.3s ease, visibility 0s 0.3s;
}
.dice-overlay.show {
visibility: visible;
opacity: 1;
transition: opacity 0.3s ease, visibility 0s 0s;
}
.big-dice {
width: 200px;
height: 200px;
background: white;
border-radius: 50px;
display: flex;
justify-content: center;
align-items: center;
font-size: 140px;
font-weight: 800;
box-shadow: 0 20px 0 #b57c1a, 0 40px 40px black, 0 0 0 8px #ffd966, 0 0 0 12px #ffb703;
animation: dicePop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards, diceSpin 0.6s ease-in-out;
transform-origin: center;
color: #2d1f00;
background: linear-gradient(145deg, #fff8e0, #ffe39c);
border: 4px solid #ffb703;
text-shadow: 8px 8px 0 rgba(0,0,0,0.2);
}
@keyframes dicePop {
0% { transform: scale(0.2) rotate(-20deg); opacity: 0; }
50% { transform: scale(1.1) rotate(5deg); opacity: 1; }
100% { transform: scale(1) rotate(0deg); opacity: 1; }
}
@keyframes diceSpin {
0% { transform: rotateX(0deg) rotateY(0deg); }
25% { transform: rotateX(180deg) rotateY(90deg); }
50% { transform: rotateX(360deg) rotateY(180deg); }
75% { transform: rotateX(540deg) rotateY(270deg); }
100% { transform: rotateX(720deg) rotateY(360deg); }
}
/* 胜利动画遮罩 */
.victory-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
backdrop-filter: blur(8px);
z-index: 2000;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
visibility: hidden;
opacity: 0;
transition: opacity 0.5s ease, visibility 0s 0.5s;
pointer-events: none;
}
.victory-overlay.show {
visibility: visible;
opacity: 1;
transition: opacity 0.5s ease, visibility 0s 0s;
pointer-events: all;
}
.victory-content {
text-align: center;
animation: victoryPop 1s ease-out;
}
.victory-emoji {
font-size: 120px;
filter: drop-shadow(0 0 30px gold);
margin-bottom: 20px;
animation: victoryFloat 2s infinite;
}
.victory-text {
font-size: 80px;
font-weight: 900;
color: #ffd966;
text-shadow: 0 0 20px #ffb703, 0 0 40px #ff8c00, 4px 4px 0 #b57c1a;
letter-spacing: 8px;
margin-bottom: 30px;
animation: victoryGlow 1.5s infinite;
}
.victory-sub {
font-size: 40px;
color: white;
text-shadow: 0 0 15px cyan;
}
.restart-btn {
background: #f5c542;
border: none;
font-size: 32px;
padding: 20px 60px;
border-radius: 80px;
font-weight: 800;
color: #1d2c3a;
box-shadow: 0 10px 0 #b57c1a, 0 5px 30px gold;
cursor: pointer;
margin-top: 50px;
transition: 0.1s linear;
border: 3px solid white;
}
.restart-btn:active {
transform: translateY(6px);
box-shadow: 0 4px 0 #b57c1a, 0 8px 30px orange;
}
@keyframes victoryPop {
0% { transform: scale(0.2); opacity: 0; }
80% { transform: scale(1.1); }
100% { transform: scale(1); opacity: 1; }
}
@keyframes victoryFloat {
0% { transform: translateY(0px); }
50% { transform: translateY(-20px); }
100% { transform: translateY(0px); }
}
@keyframes victoryGlow {
0% { text-shadow: 0 0 20px #ffd966, 0 0 40px #ffb703, 4px 4px 0 #b57c1a; }
50% { text-shadow: 0 0 40px #ffd966, 0 0 80px #ffb703, 4px 4px 0 #b57c1a; }
100% { text-shadow: 0 0 20px #ffd966, 0 0 40px #ffb703, 4px 4px 0 #b57c1a; }
}
/* 彩带画布 */
#confetti-canvas {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 1999;
}
/* 棋盘轨道 */
.board-rail {
background: #2d3f4e;
padding: 25px 30px;
border-radius: 180px 180px 60px 60px;
box-shadow: inset 0 -5px 0 #1c2935, inset 0 5px 10px #3f5568, 0 15px 20px #0b1219;
border-bottom: 3px solid #ffd966;
transition: filter 0.2s;
}
.grid-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding: 0 15px;
}
.player-tag {
display: flex;
align-items: center;
gap: 12px;
background: #253544;
padding: 10px 30px 10px 20px;
border-radius: 50px;
box-shadow: inset 0 1px 4px #101b24, 0 6px 0 #0e1a22;
border-bottom: 2px solid #ffe484;
}
.red-die, .blue-die {
width: 48px;
height: 48px;
background: white;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
font-weight: 800;
box-shadow: 0 5px 0 #a0a0a0, 0 8px 10px black;
transition: 0.1s ease;
}
.red-die { background: #ff7675; color: #440000; border: 2px solid #ffd0a4; }
.blue-die { background: #74b9ff; color: #003f6f; border: 2px solid #b3e0ff; }
.turn-indicator {
font-size: 18px;
font-weight: 600;
background: #2f4253;
color: #ffd966;
padding: 10px 30px;
border-radius: 40px;
letter-spacing: 1px;
box-shadow: inset 0 -2px 0 #1a2933;
}
/* 格子轨道 */
.track {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 15px 0 5px;
}
.cell {
width: calc(100% / 13 - 6px);
min-width: 70px;
height: 90px;
background: #edf2f7;
margin: 3px;
border-radius: 20px 12px 12px 12px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow: 0 8px 0 #8b9aab, 0 12px 15px -5px #04131f;
transition: all 0.15s;
color: #1a2b36;
font-weight: 600;
position: relative;
cursor: help;
border: 2px solid #f7e05e;
padding: 5px 2px;
text-align: center;
}
.cell:hover {
transform: translateY(-4px);
box-shadow: 0 12px 0 #7b8a9b, 0 18px 20px -5px #020b12;
background: #fff7cf;
border-color: #ffb347;
}
.cell-number {
font-size: 13px;
background: #2b404e;
color: white;
width: 28px;
line-height: 22px;
border-radius: 30px;
margin-top: -20px;
margin-bottom: 4px;
font-weight: 700;
box-shadow: inset 0 -2px 0 #15262e;
}
.cell-icon {
font-size: 22px;
line-height: 1;
filter: drop-shadow(0 3px 2px rgba(0,0,0,0.3));
display: flex;
align-items: center;
gap: 4px;
}
.cell-desc {
font-size: 9px;
font-weight: 500;
background: #ffffffc4;
padding: 3px 5px;
border-radius: 30px;
color: #0b1a24;
max-width: 95%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-top: 3px;
box-shadow: inset 0 1px 3px #cddae4;
}
/* 格子内小图片 */
.cell-img {
max-width: 20px;
max-height: 20px;
border-radius: 4px;
margin-left: 2px;
vertical-align: middle;
}
/* 棋子标记 */
.piece {
font-size: 26px;
line-height: 1;
position: absolute;
bottom: -10px;
right: -6px;
text-shadow: 0 4px 3px black;
filter: drop-shadow(0 0 4px gold);
}
.red-piece {
color: #e63946;
left: 2px;
bottom: -6px;
}
.blue-piece {
color: #1e6f9f;
right: 2px;
bottom: -6px;
}
/* 控制区域 */
.control-panel {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 35px;
background: #1c2b37d9;
border-radius: 90px;
padding: 18px 30px;
border: 1px solid #ffe270;
box-shadow: 0 15px 20px #060d13;
}
.dice-area {
display: flex;
gap: 30px;
align-items: center;
}
.dice-box {
background: #2f404e;
border-radius: 30px;
padding: 10px 25px;
display: flex;
align-items: center;
gap: 15px;
}
.roll-btn {
background: #f5c542;
border: none;
font-size: 32px;
padding: 12px 35px;
border-radius: 80px;
font-weight: 800;
color: #1d2c3a;
box-shadow: 0 10px 0 #b57c1a, 0 5px 20px black;
transition: 0.05s linear;
cursor: pointer;
letter-spacing: 2px;
position: relative;
overflow: hidden;
}
.roll-btn:active {
transform: translateY(6px);
box-shadow: 0 4px 0 #b57c1a, 0 8px 15px black;
}
.roll-btn.disabled {
opacity: 0.5;
pointer-events: none;
filter: grayscale(0.6);
}
.roll-btn::after {
content: '';
position: absolute;
top: -50%;
left: -60%;
width: 200%;
height: 200%;
background: rgba(255,255,255,0.3);
transform: rotate(30deg);
transition: left 0.3s;
}
.roll-btn:active::after {
left: 100%;
}
.action-log {
background: #0f1f2b;
border-radius: 60px;
padding: 15px 30px;
color: #ffdb8e;
font-size: 18px;
font-weight: 600;
max-width: 450px;
border-left: 6px solid #ffbe3f;
box-shadow: inset 0 2px 8px black;
}
.tooltip-custom {
position: fixed;
background: #1e2f3d;
color: #faeac2;
padding: 14px 20px;
border-radius: 30px 30px 30px 8px;
font-size: 15px;
font-weight: 500;
max-width: 350px;
box-shadow: 0 15px 20px #020a10, 0 0 0 2px #fdc62e;
backdrop-filter: blur(6px);
border: 1px solid #ffcf7a;
pointer-events: none;
z-index: 1000;
line-height: 1.5;
transition: opacity 0.2s;
opacity: 0;
}
.tooltip-img {
max-width: 100%;
max-height: 100px;
border-radius: 12px;
margin-top: 8px;
border: 2px solid #ffd966;
display: block;
}
.footer-note {
text-align: center;
color: #b7cdde;
margin-top: 20px;
font-size: 14px;
}
.flash-effect {
animation: flash 0.4s 2;
}
@keyframes flash {
0% { background-color: rgba(255,215,0,0.1); }
50% { background-color: rgba(255,215,0,0.4); }
100% { background-color: rgba(255,215,0,0.1); }
}
</style>
</head>
<body>
<!-- 巨型骰子弹窗 -->
<div id="diceOverlay" class="dice-overlay">
<div id="bigDice" class="big-dice">⚀</div>
</div>
<!-- 胜利动画遮罩 -->
<div id="victoryOverlay" class="victory-overlay">
<div class="victory-content">
<div id="victoryEmoji" class="victory-emoji">🏆</div>
<div id="victoryText" class="victory-text">红方胜利</div>
<div class="victory-sub">🎉 恭喜到达终点 🎉</div>
<button class="restart-btn" id="restartBtn">再 玩 一 局</button>
</div>
</div>
<!-- 彩带画布 -->
<canvas id="confetti-canvas"></canvas>
<div class="game-container" id="gameContainer">
<!-- 棋盘头 显示红蓝状态 -->
<div class="grid-header">
<div class="player-tag">
<span class="red-die" id="redDice">⚀</span>
<span style="color:#ffb9b9; font-weight:600;">红方</span>
</div>
<div class="turn-indicator" id="turnIndicator">🔴 红方回合</div>
<div class="player-tag">
<span style="color:#b3deff; font-weight:600;">蓝方</span>
<span class="blue-die" id="blueDice">⚀</span>
</div>
</div>
<!-- 棋盘格 52格 动态绘制 -->
<div class="board-rail" id="boardTrack"></div>
<!-- 控制栏 -->
<div class="control-panel">
<div class="dice-area">
<div class="dice-box">
<span style="color:white; font-size:20px;">🎲 本轮</span>
<span id="diceResult" style="font-size:48px; font-weight:800; color:#ffe189;">0</span>
</div>
<button class="roll-btn" id="rollBtn">掷 骰</button>
</div>
<div class="action-log" id="actionMessage">
点击掷骰开始 🎲
</div>
</div>
<div class="footer-note">✨ 率先抵达终点者获胜 ✨</div>
</div>
<!-- 自定义悬浮tooltip -->
<div id="cellTooltip" class="tooltip-custom"></div>
<script>
(function() {
// ---------- 游戏配置 ----------
const TOTAL_CELLS = 61;
const WINNING_CELL = TOTAL_CELLS - 1;
// 52个格子详情(索引0~51)包含图片示例
const cellDetails = [
{ emoji: '🏁', desc: '起点 · 全体集合', game: '起点', img: 'https://picsum.photos/50/50?random=1' },
{ emoji:'🐶', desc: '学狗叫', game:'奴狗叫并摇臀,次数=骰子点数×2'},
{ emoji:'💃',desc: '即兴舞蹈', game:'奴表演缓慢脱衣舞给所有人看,完成后可让对方主人少掷一次骰'},
{ emoji:'🙇♀️',desc: '奴自夹乳头',game: '奴自夹乳头(用夹子或手指),夹住骰子点数×10秒'},
{ emoji:'🐎', desc: '奴为主人提供骑乘服务', game:'奴为自己的主人提供骑乘式服务,持续骰子点数×10秒'},
{ emoji:'👨👨👧', desc: '口侍手指',game: '奴为两位主人同时口侍手指(模拟口交),每人点数秒'},
{ emoji:'3️⃣', desc: '前进3步',game: '运气真好!直接前进3步', move: 3},
{ emoji:'🍌',desc: '深喉服务,前进2步', game:'奴为自己的主人献上深喉服务(模拟),持续骰子点数X5秒', move: 2},
{ emoji:'🔙',desc: '后退4步',game: '不小心退后3步', move: -3},
{ emoji:'🕺', desc: '蹲立',game: '奴表演蹲立,维持骰子点数×5秒', img: 'https://picsum.photos/50/50?random=54'},
{ emoji:'🐎', desc: '让对方奴骑', game:'奴让对方奴骑在自己背上绕圈走1圈'},
{ emoji:'🙇♀️',desc: '对方奴侍奉', game:'奴命令对方奴爬到自己胯下亲吻,持续骰子点数×20秒'},
{ emoji:'🐧',desc: '企鹅走路',game: '像企鹅一样走(后退1步)', move: -1},
{ emoji:'🍪', desc: '零食奖励',game:'前进1步 (奖励零食)', move: 1},
{ emoji:'🦀', desc: '螃蟹步',game: '横着走(后退3步)', move: -3},
{ emoji:'👣',desc: '足部崇拜', game:'奴跪下为自己的主人进行足部崇拜(舔脚、吸脚趾),持续骰子点数×10秒'},
{ emoji:'🐕🚶', desc: '项圈牵行', game:'奴为对方奴戴上项圈并牵行一圈'},
{ emoji:'🙇♀️', desc: '前进4步', game:'冲刺3步', move: 3},
{ emoji:'🙋♀️',desc: '自扇屁股',game: '奴自扇屁股(轻拍或重拍),点数×2下,同时抵消对方一次物理攻击'},
{ emoji:'👣', desc: '清洁脚底',game: '奴用舌头为自己的主人清洁鞋子或脚底,持续骰子点数×5秒'},
{ emoji:'💏',desc: '亲吻同类', game:'奴给对方奴戴眼罩,亲吻对方脖子10秒'},
{ emoji:'🕺', desc: 'M字展示',game: '奴摆出M字腿姿势暴露给主人观看,维持骰子点数×5秒', img: 'https://picsum.photos/50/50?random=54'},
{ emoji:'🔙',desc: '后退3步', game:'哎哟,退3步', move: -3},
{ emoji:'🍌',desc: '跪侍主人', game:'奴为自己的主人提供跪式口交服务(模拟),持续骰子点数×5秒'},
{ emoji:'🎁', desc: '惊喜礼物',game: '前进2步', move: 2},
{ emoji:'🕯️',desc: '滴蜡', game:'奴用蜡烛滴蜡在自己大腿(安全位置),滴数=骰子点数×2'},
{ emoji:'🙋♀️',desc: '鞭打同类',game: '奴为对方奴进行轻度鞭打(软鞭或手掌),次数对应骰子点数'},
{ emoji:'🐕🦺',desc: '宠物姿势', game:'奴摆出宠物姿势(四肢着地、汪汪叫),持续骰子点数X2并额外移动1格', move: 1},
{ emoji:'🦶',desc: '同类舔脚', game:'奴临时支配对方奴舔自己脚,持续骰子点数×15秒'},
{ emoji:'🕺', desc: '检查',game: '奴表演检查体位,维持骰子点数×5秒', img: 'hhttps://picsum.photos/50/50?random=54'},
{ emoji:'🐌',desc: '慢吞吞', game:'后退1步', move: -1},
{ emoji:'🐎', desc: '主人骑行',game: '奴为自己的主人提供骑乘式服务,持续骰子点数×10秒'},
{ emoji:'🤟', desc: '边缘', game:'奴跪下高潮边缘控制(自摸但不能高潮),获得前进4步', move: 4},
{ emoji:'👑',desc: '国王游戏', game:'命令任意一个奴学狗叫点数声'},
{ emoji:'💔',desc: '奴一败涂地',game: '后退3步', move: -3},
{ emoji:'🚀',desc: '火箭', game:'前进4步', move: 4},
{ emoji:'👨👩👧',desc: '支配', game:'奴临时支配对方奴为自己做口交姿势展示,姿势数=骰子点数'},
{ emoji:'🕺', desc: '侯责的奴',game: '奴摆出侯责姿势,维持骰子点数×5秒,根据效果主人给予责罚和奖励零食', img: 'https://picsum.photos/50/50?random=54'},
{ emoji:'💏',desc: '亲吻同类', game:'奴给对方奴戴眼罩,亲吻对方脖子10秒'},
{ emoji:'🐕', desc: '狗狗撒尿', game:'狗狗生动形象表演抬腿撒尿', img: 'https://picsum.photos/50/50?random=54'},
{ emoji:'🐢',desc: '乌龟', game:'后退2步', move: -2},
{ emoji:'👨👨👧',desc: '口手侍手指',game: '奴为两位主人同时口手侍手指(模拟口交),每人点数秒'},
{ emoji:'🤹',desc: '对方奴侍奉',game: '奴命令对方奴爬到自己胯下亲吻,持续骰子点数×20秒'},
{ emoji:'🔙',desc: '奴的错',game: '严重失误后退4步', move: -4},
{ emoji:'🎯',desc: '靶心', game:'前进2步', move: 2},
{ emoji:'🍕',desc: '奖励零食',game: '前进1步', move: 1},
{ emoji:'🥤',desc: '宠物行动',game: '奴跪下为自己的主人献上“宠物式”摩擦大腿,持续骰子点数×10秒。'},
{ emoji:'🐉', desc: '舞龙', game:'前进3步', move: 3},
{ emoji:'🙎',desc: '支配同类', game:'奴让对方奴为自己做足部按摩,持续骰子点数×20秒'},
{ emoji:'🌋', desc: '火山喷发', game:'后退4步', move: -4},
{ emoji:'🏆',desc: '奴是主的骄傲', game:'前进4步', move: 4},
{ emoji:'🕺', desc: '一切都是奴的错',game: '奴摆出面壁鞭刑姿势,主人鞭打×2下,根据效果主人赏赐零食安抚', img: 'https://picsum.photos/50/50?random=54'},
{ emoji:'🐎',desc: '骑狗', game:'奴把对方奴按倒轻度骑乘,持续骰子点数×10秒'},
{ emoji:'🙋♀️', desc: '奴的自责',game: '奴自扇私密部位(轻拍),次数=骰子点数×4'},
{ emoji:'🔙', desc: '后退1步', game:'小退一步',move: -1},
{ emoji:'🐕',desc: '遛狗', game:'前进2步', move: 2},
{ emoji:'🙋♀️',desc: '鞭打同类',game: '奴为对方奴进行轻度鞭打(软鞭或手掌),次数对应骰子点数'},
{ emoji:'👆',desc: '舔指', game:'奴命令对方奴学狗叫并舔自己手指'},
{ emoji:'🙇♀️',desc: '奴的乞求',game: '奴表演“乞求高潮”姿势(双手举高、跪地恳求),持续骰子点数×5秒', img: 'https://picsum.photos/50/50?random=54'},
{ emoji:'🎢',desc: '过山车', game:'前进1步', move: 1},
{ emoji:'🏁', desc: '终点冲刺', game:'恭喜到达终点!'} ,
];
// 保证刚好52格
while (cellDetails.length < TOTAL_CELLS) {
cellDetails.push({ emoji: '🎲', desc: '随机表演', game: '自由发挥一个才艺', img: 'https://picsum.photos/50/50?random=54' });
}
// 截断前52个
const finalCells = cellDetails.slice(0, TOTAL_CELLS);
// ---------- 游戏状态 ----------
let redPos = 0;
let bluePos = 0;
let currentTurn = 'red';
let diceValue = 0;
let gameActive = true;
let isRolling = false;
let winner = null; // 'red' 或 'blue'
// DOM元素
const boardEl = document.getElementById('boardTrack');
const redDiceEl = document.getElementById('redDice');
const blueDiceEl = document.getElementById('blueDice');
const diceResultSpan = document.getElementById('diceResult');
const turnIndicator = document.getElementById('turnIndicator');
const actionMsg = document.getElementById('actionMessage');
const rollBtn = document.getElementById('rollBtn');
const tooltip = document.getElementById('cellTooltip');
const diceOverlay = document.getElementById('diceOverlay');
const bigDice = document.getElementById('bigDice');
const gameContainer = document.getElementById('gameContainer');
const victoryOverlay = document.getElementById('victoryOverlay');
const victoryEmoji = document.getElementById('victoryEmoji');
const victoryText = document.getElementById('victoryText');
const restartBtn = document.getElementById('restartBtn');
// 彩带
const canvas = document.getElementById('confetti-canvas');
const ctx = canvas.getContext('2d');
let width, height;
let particles = [];
let animationId = null;
function resizeCanvas() {
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width;
canvas.height = height;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
class Particle {
constructor() {
this.x = Math.random() * width;
this.y = Math.random() * height - height;
this.size = Math.random() * 8 + 4;
this.speedY = Math.random() * 5 + 3;
this.speedX = Math.random() * 2 - 1;
this.color = `hsl(${Math.random() * 360}, 80%, 60%)`;
}
update() {
this.y += this.speedY;
this.x += this.speedX;
if (this.y > height) {
this.y = -this.size;
this.x = Math.random() * width;
}
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.size, this.size * 0.4);
}
}
function startConfetti() {
particles = [];
for (let i = 0; i < 150; i++) {
particles.push(new Particle());
}
if (animationId) cancelAnimationFrame(animationId);
function animate() {
ctx.clearRect(0, 0, width, height);
particles.forEach(p => {
p.update();
p.draw();
});
animationId = requestAnimationFrame(animate);
}
animate();
}
function stopConfetti() {
if (animationId) {
cancelAnimationFrame(animationId);
animationId = null;
}
ctx.clearRect(0, 0, width, height);
}
// 检查胜利
function checkVictory() {
if (!gameActive) return false;
if (redPos === WINNING_CELL) {
winner = 'red';
gameActive = false;
showVictory('red');
return true;
} else if (bluePos === WINNING_CELL) {
winner = 'blue';
gameActive = false;
showVictory('blue');
return true;
}
return false;
}
function showVictory(player) {
victoryEmoji.textContent = player === 'red' ? '🔴' : '🔵';
victoryText.textContent = player === 'red' ? '红方胜利' : '蓝方胜利';
victoryOverlay.classList.add('show');
startConfetti();
rollBtn.classList.add('disabled');
}
function hideVictory() {
victoryOverlay.classList.remove('show');
stopConfetti();
}
// 绘制棋盘
function renderBoard() {
let html = '<div class="track">';
finalCells.forEach((cell, idx) => {
let pieces = '';
if (redPos === idx) pieces += '<span class="piece red-piece" style="left:2px;">🔴</span>';
if (bluePos === idx) pieces += '<span class="piece blue-piece" style="right:2px;">🔵</span>';
if (redPos === idx && bluePos === idx) {
pieces = '<span class="piece red-piece" style="left:2px;">🔴</span><span class="piece blue-piece" style="right:2px;">🔵</span>';
}
const imgHtml = cell.img ? `<img src="${cell.img}" class="cell-img" alt="img">` : '';
html += `<div class="cell" data-index="${idx}" data-emoji="${cell.emoji}" data-desc="${cell.desc}" data-game="${cell.game}" data-move="${cell.move ?? ''}" data-img="${cell.img || ''}">
<span class="cell-number">${idx+1}</span>
<span class="cell-icon">${cell.emoji}${imgHtml}</span>
<span class="cell-desc">${cell.desc}</span>
${pieces}
</div>`;
});
html += '</div>';
boardEl.innerHTML = html;
document.querySelectorAll('.cell').forEach(cell => {
cell.addEventListener('mouseenter', showTooltip);
cell.addEventListener('mouseleave', hideTooltip);
});
}
function showTooltip(e) {
const cell = e.currentTarget;
const idx = cell.dataset.index;
const data = finalCells[idx];
const moveText = data.move ? (data.move > 0 ? ` 🚩前进 ${data.move} 步` : ` 🔙后退 ${Math.abs(data.move)} 步`) : ' · 表演格';
const imgHtml = data.img ? `<img src="${data.img}" class="tooltip-img" alt="格子图片">` : '';
tooltip.style.opacity = '1';
tooltip.style.left = (e.pageX + 20) + 'px';
tooltip.style.top = (e.pageY - 40) + 'px';
tooltip.innerHTML = `<strong style="color:#ffd966">${data.emoji} 格子 ${+idx+1} · ${data.desc}</strong><br>${data.game} ${moveText}${imgHtml}`;
}
function hideTooltip() {
tooltip.style.opacity = '0';
}
function updateUI() {
const diceMap = ['⚀', '⚁', '⚂', '⚃', '⚄', '⚅'];
redDiceEl.textContent = diceMap[Math.floor(Math.random() * 6)];
blueDiceEl.textContent = diceMap[Math.floor(Math.random() * 6)];
turnIndicator.innerHTML = !gameActive ? '⏸️ 游戏结束' : (currentTurn === 'red' ? '🔴 红方回合 · 掷骰吧' : '🔵 蓝方回合 · 掷骰吧');
redDiceEl.style.border = currentTurn === 'red' && gameActive ? '4px solid #ffb703' : '2px solid #afafaf';
blueDiceEl.style.border = currentTurn === 'blue' && gameActive ? '4px solid #ffb703' : '2px solid #afafaf';
}
function applyCellEffect(player) {
const pos = player === 'red' ? redPos : bluePos;
const cell = finalCells[pos];
let moveDelta = cell.move || 0;
if (moveDelta !== 0) {
if (moveDelta > 5) moveDelta = 5;
if (moveDelta < -5) moveDelta = -5;
actionMsg.innerText += ` · 触发了${moveDelta>0?'前进':'后退'} ${Math.abs(moveDelta)} 步`;
if (player === 'red') {
let newPos = redPos + moveDelta;
newPos = Math.min(TOTAL_CELLS-1, Math.max(0, newPos));
redPos = newPos;
} else {
let newPos = bluePos + moveDelta;
newPos = Math.min(TOTAL_CELLS-1, Math.max(0, newPos));
bluePos = newPos;
}
} else {
actionMsg.innerText += ` · 任务:${cell.desc}`;
}
renderBoard();
}
async function animateDice(finalValue) {
return new Promise((resolve) => {
diceOverlay.classList.add('show');
const diceFaces = ['⚀', '⚁', '⚂', '⚃', '⚄', '⚅'];
let spinCount = 0;
const spinInterval = setInterval(() => {
const randomFace = diceFaces[Math.floor(Math.random() * 6)];
bigDice.textContent = randomFace;
spinCount++;
if (spinCount > 8) {
clearInterval(spinInterval);
bigDice.textContent = diceFaces[finalValue - 1];
bigDice.style.animation = 'none';
bigDice.offsetHeight;
bigDice.style.animation = 'dicePop 0.3s ease, diceSpin 0.5s ease';
setTimeout(() => {
diceOverlay.classList.remove('show');
resolve();
}, 600);
}
}, 80);
});
}
async function handleRoll() {
if (!gameActive || isRolling) return;
isRolling = true;
rollBtn.classList.add('disabled');
const dice = Math.floor(Math.random() * 6) + 1;
diceValue = dice;
diceResultSpan.textContent = dice;
await animateDice(dice);
const player = currentTurn;
const playerName = player === 'red' ? '红方' : '蓝方';
actionMsg.innerText = `${playerName} 掷出 ${dice} 点 · `;
if (player === 'red') {
let newPos = redPos + dice;
if (newPos >= TOTAL_CELLS) newPos = TOTAL_CELLS - 1;
redPos = newPos;
} else {
let newPos = bluePos + dice;
if (newPos >= TOTAL_CELLS) newPos = TOTAL_CELLS - 1;
bluePos = newPos;
}
actionMsg.innerText += `移动到格子 ${player === 'red'? redPos+1 : bluePos+1}`;
renderBoard();
applyCellEffect(player);
// 检查胜利
if (checkVictory()) {
renderBoard();
updateUI();
isRolling = false;
return;
}
currentTurn = currentTurn === 'red' ? 'blue' : 'red';
updateUI();
renderBoard();
gameContainer.classList.add('flash-effect');
setTimeout(() => gameContainer.classList.remove('flash-effect'), 500);
isRolling = false;
rollBtn.classList.remove('disabled');
}
function restartGame() {
redPos = 0;
bluePos = 0;
currentTurn = 'red';
gameActive = true;
winner = null;
diceResultSpan.textContent = '0';
actionMsg.innerText = '新的一局!红方先掷骰';
hideVictory();
renderBoard();
updateUI();
rollBtn.classList.remove('disabled');
}
// 事件绑定
rollBtn.addEventListener('click', handleRoll);
restartBtn.addEventListener('click', restartGame);
document.addEventListener('mousemove', (e) => {
if (tooltip.style.opacity === '1') {
tooltip.style.left = (e.pageX + 20) + 'px';
tooltip.style.top = (e.pageY - 40) + 'px';
}
});
// 启动
restartGame();
})();
</script>
</body>
</html>
