572 lines
20 KiB
HTML
572 lines
20 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>🍲 地狱火锅 V3 - 谁是那块肉? 🍲</title>
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=ZCOOL+KuaiLe&display=swap');
|
|
|
|
:root {
|
|
--soup-red: #d63031;
|
|
--soup-dark: #8b0000;
|
|
--pot-gold: #fdcb6e;
|
|
--steam-white: rgba(255, 255, 255, 0.3);
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
background-color: #1a1a1a;
|
|
color: #fff;
|
|
font-family: 'ZCOOL KuaiLe', cursive, sans-serif;
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
overflow: hidden;
|
|
user-select: none;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 3rem;
|
|
color: var(--pot-gold);
|
|
text-shadow: 3px 3px 0px #000, 0 0 20px #ff4757;
|
|
margin-bottom: 10px;
|
|
z-index: 100;
|
|
}
|
|
|
|
.subtitle {
|
|
font-size: 1.2rem;
|
|
color: #fab1a0;
|
|
margin-bottom: 20px;
|
|
z-index: 100;
|
|
}
|
|
|
|
/* 火锅容器 */
|
|
.pot-container {
|
|
position: relative;
|
|
width: 600px;
|
|
height: 600px;
|
|
background: radial-gradient(circle, var(--soup-red) 0%, var(--soup-dark) 70%, #000 100%);
|
|
border: 20px solid #57606f;
|
|
border-radius: 50%;
|
|
box-shadow: inset 0 0 50px rgba(0,0,0,0.8), 0 0 30px rgba(214, 48, 49, 0.5);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* 锅中间的隔断(鸳鸯锅效果) */
|
|
.pot-divider {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 50%;
|
|
border: 8px solid #57606f;
|
|
pointer-events: none;
|
|
z-index: 5;
|
|
}
|
|
|
|
.pot-inner-rim {
|
|
position: absolute;
|
|
width: 90%;
|
|
height: 90%;
|
|
border: 2px solid rgba(255,255,255,0.1);
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* 沸腾气泡 */
|
|
.bubble {
|
|
position: absolute;
|
|
background: rgba(255, 255, 255, 0.2);
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
animation: boil-bubble 2s infinite ease-in;
|
|
}
|
|
|
|
@keyframes boil-bubble {
|
|
0% { transform: translateY(0) scale(0); opacity: 0.5; }
|
|
50% { opacity: 0.8; }
|
|
100% { transform: translateY(-100px) scale(1.5); opacity: 0; }
|
|
}
|
|
|
|
/* 蒸汽效果 */
|
|
.steam {
|
|
position: absolute;
|
|
width: 200px;
|
|
height: 200px;
|
|
background: radial-gradient(circle, var(--steam-white) 0%, transparent 70%);
|
|
border-radius: 50%;
|
|
filter: blur(20px);
|
|
pointer-events: none;
|
|
z-index: 20;
|
|
animation: steam-move 4s infinite linear;
|
|
}
|
|
|
|
@keyframes steam-move {
|
|
0% { transform: translate(-50%, -50%) scale(1); opacity: 0; }
|
|
50% { opacity: 0.5; }
|
|
100% { transform: translate(50%, -150%) scale(2); opacity: 0; }
|
|
}
|
|
|
|
/* 食材(学生头像) */
|
|
.ingredient {
|
|
position: absolute;
|
|
width: 80px;
|
|
height: 80px;
|
|
border-radius: 50%;
|
|
border: 4px solid var(--pot-gold);
|
|
background-color: #fff;
|
|
overflow: hidden;
|
|
box-shadow: 0 5px 15px rgba(0,0,0,0.5);
|
|
transition: transform 0.3s, opacity 0.5s, filter 0.5s;
|
|
cursor: pointer;
|
|
z-index: 10;
|
|
}
|
|
|
|
.ingredient img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.ingredient .label {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
background: rgba(0,0,0,0.7);
|
|
color: #fff;
|
|
font-size: 0.7rem;
|
|
text-align: center;
|
|
padding: 2px 0;
|
|
}
|
|
|
|
/* 选中状态 */
|
|
.ingredient.active {
|
|
transform: scale(1.2);
|
|
border-color: #fff;
|
|
box-shadow: 0 0 20px #fff;
|
|
z-index: 15;
|
|
}
|
|
|
|
/* 被捞走状态 */
|
|
.ingredient.removed {
|
|
transform: translateY(-200px) scale(0);
|
|
opacity: 0;
|
|
}
|
|
|
|
/* 控制按钮 */
|
|
#actionBtn {
|
|
margin-top: 30px;
|
|
padding: 15px 50px;
|
|
font-size: 1.8rem;
|
|
font-family: 'ZCOOL KuaiLe', cursive;
|
|
background: linear-gradient(to bottom, #ff7675, #d63031);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 50px;
|
|
cursor: pointer;
|
|
box-shadow: 0 10px 0 #8b0000, 0 15px 25px rgba(0,0,0,0.5);
|
|
transition: all 0.1s;
|
|
z-index: 100;
|
|
}
|
|
|
|
#actionBtn:active {
|
|
transform: translateY(5px);
|
|
box-shadow: 0 5px 0 #8b0000, 0 10px 15px rgba(0,0,0,0.5);
|
|
}
|
|
|
|
#actionBtn:disabled {
|
|
background: #636e72;
|
|
box-shadow: 0 5px 0 #2d3436;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* 结果展示层 */
|
|
#resultOverlay {
|
|
position: fixed;
|
|
top: 0; left: 0; width: 100%; height: 100%;
|
|
background: rgba(0,0,0,0.9);
|
|
display: none;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 1000;
|
|
animation: fadeIn 0.5s forwards;
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
|
|
.result-card {
|
|
background: #fff;
|
|
padding: 30px;
|
|
border-radius: 20px;
|
|
border: 10px solid var(--pot-gold);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
transform: scale(0);
|
|
animation: popIn 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275) 0.5s forwards;
|
|
}
|
|
|
|
@keyframes popIn {
|
|
to { transform: scale(1); }
|
|
}
|
|
|
|
.result-image {
|
|
width: 250px;
|
|
height: 250px;
|
|
border-radius: 50%;
|
|
border: 8px solid var(--soup-red);
|
|
object-fit: cover;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.result-name {
|
|
font-size: 3rem;
|
|
color: var(--soup-red);
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.result-title {
|
|
font-size: 1.5rem;
|
|
color: #636e72;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
#closeBtn {
|
|
padding: 10px 30px;
|
|
background: var(--soup-red);
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 10px;
|
|
font-size: 1.2rem;
|
|
cursor: pointer;
|
|
font-family: 'ZCOOL KuaiLe', cursive;
|
|
}
|
|
|
|
/* 吐槽弹幕 */
|
|
.danmu {
|
|
position: absolute;
|
|
white-space: nowrap;
|
|
font-size: 1.2rem;
|
|
color: #fab1a0;
|
|
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
|
|
pointer-events: none;
|
|
z-index: 50;
|
|
animation: danmu-move 5s linear forwards;
|
|
}
|
|
|
|
@keyframes danmu-move {
|
|
from { left: 100%; }
|
|
to { left: -100%; }
|
|
}
|
|
|
|
/* 筷子 */
|
|
.chopsticks {
|
|
position: absolute;
|
|
width: 10px;
|
|
height: 400px;
|
|
background: #747d8c;
|
|
border-radius: 5px;
|
|
z-index: 60;
|
|
pointer-events: none;
|
|
transform-origin: top center;
|
|
display: none;
|
|
}
|
|
|
|
.chopstick-left { transform: rotate(5deg); margin-left: -15px; }
|
|
.chopstick-right { transform: rotate(-5deg); margin-left: 15px; }
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<h1>🍲 地狱火锅 V3 🍲</h1>
|
|
<div class="subtitle">—— 今天的你,是什么口味的食材? ——</div>
|
|
|
|
<div class="pot-container" id="pot">
|
|
<div class="pot-divider"></div>
|
|
<div class="pot-inner-rim"></div>
|
|
<!-- 气泡和食材将在这里生成 -->
|
|
</div>
|
|
|
|
<div class="chopsticks" id="chopstickLeft"></div>
|
|
<div class="chopsticks" id="chopstickRight"></div>
|
|
|
|
<button id="actionBtn" onclick="startCooking()">开始开涮!</button>
|
|
|
|
<div id="resultOverlay">
|
|
<div class="result-card">
|
|
<img src="" class="result-image" id="resultImg">
|
|
<div class="result-name" id="resultName">???</div>
|
|
<div class="result-title" id="resultTitle">美味食材</div>
|
|
<button id="closeBtn" onclick="resetPot()">再涮一锅</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const totalStudents = 14;
|
|
const imagePath = './Result/';
|
|
const pot = document.getElementById('pot');
|
|
const ingredients = [];
|
|
const ingredientNames = [
|
|
"雪花肥牛", "极品毛肚", "脆皮肠", "手打虾滑", "鲜嫩脑花",
|
|
"爽口裙带菜", "魔芋丝", "功夫土豆片", "大刀腰片", "鸭血",
|
|
"千层肚", "贡菜", "水晶粉", "虎皮凤爪"
|
|
];
|
|
const funnyComments = [
|
|
"火开大点!", "别抢我的肉!", "这个同学一看就很嫩", "哎呀烫手!",
|
|
"锅底不够辣啊", "谁把香菜放进来了?", "救命,我要被煮熟了",
|
|
"捞我!捞我!", "还没熟呢,再等等", "这是天选之肉"
|
|
];
|
|
|
|
// 音效系统
|
|
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
|
function playSound(freq, type, duration, vol = 0.1) {
|
|
const osc = audioCtx.createOscillator();
|
|
const gain = audioCtx.createGain();
|
|
osc.type = type;
|
|
osc.frequency.setValueAtTime(freq, audioCtx.currentTime);
|
|
gain.gain.setValueAtTime(vol, audioCtx.currentTime);
|
|
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + duration);
|
|
osc.connect(gain);
|
|
gain.connect(audioCtx.destination);
|
|
osc.start();
|
|
osc.stop(audioCtx.currentTime + duration);
|
|
}
|
|
|
|
function playBoilSound() {
|
|
// 低频噪音模拟沸腾
|
|
const bufferSize = audioCtx.sampleRate * 2;
|
|
const buffer = audioCtx.createBuffer(1, bufferSize, audioCtx.sampleRate);
|
|
const data = buffer.getChannelData(0);
|
|
for (let i = 0; i < bufferSize; i++) {
|
|
data[i] = Math.random() * 2 - 1;
|
|
}
|
|
const noise = audioCtx.createBufferSource();
|
|
noise.buffer = buffer;
|
|
const filter = audioCtx.createBiquadFilter();
|
|
filter.type = 'lowpass';
|
|
filter.frequency.value = 100;
|
|
const gain = audioCtx.createGain();
|
|
gain.gain.value = 0.05;
|
|
noise.connect(filter);
|
|
filter.connect(gain);
|
|
gain.connect(audioCtx.destination);
|
|
noise.start();
|
|
return { noise, gain };
|
|
}
|
|
|
|
// 初始化食材
|
|
function init() {
|
|
for (let i = 1; i <= totalStudents; i++) {
|
|
const div = document.createElement('div');
|
|
div.className = 'ingredient';
|
|
div.id = `student-${i}`;
|
|
|
|
// 随机位置
|
|
const angle = Math.random() * Math.PI * 2;
|
|
const radius = Math.random() * 200;
|
|
const x = 300 + Math.cos(angle) * radius - 40;
|
|
const y = 300 + Math.sin(angle) * radius - 40;
|
|
|
|
div.style.left = x + 'px';
|
|
div.style.top = y + 'px';
|
|
|
|
const img = document.createElement('img');
|
|
img.src = `${imagePath}${i}.png`;
|
|
img.onerror = () => img.src = 'https://via.placeholder.com/80?text=Meat';
|
|
|
|
const label = document.createElement('div');
|
|
label.className = 'label';
|
|
label.innerText = ingredientNames[i-1];
|
|
|
|
div.appendChild(img);
|
|
div.appendChild(label);
|
|
pot.appendChild(div);
|
|
|
|
ingredients.push({
|
|
el: div,
|
|
x: x,
|
|
y: y,
|
|
vx: (Math.random() - 0.5) * 2,
|
|
vy: (Math.random() - 0.5) * 2,
|
|
angle: angle,
|
|
radius: radius,
|
|
removed: false
|
|
});
|
|
}
|
|
|
|
// 生成背景气泡
|
|
for (let i = 0; i < 20; i++) {
|
|
createBubble();
|
|
}
|
|
|
|
animate();
|
|
startDanmu();
|
|
}
|
|
|
|
function createBubble() {
|
|
const b = document.createElement('div');
|
|
b.className = 'bubble';
|
|
const size = Math.random() * 20 + 5;
|
|
b.style.width = size + 'px';
|
|
b.style.height = size + 'px';
|
|
b.style.left = Math.random() * 100 + '%';
|
|
b.style.top = Math.random() * 100 + '%';
|
|
b.style.animationDelay = Math.random() * 2 + 's';
|
|
pot.appendChild(b);
|
|
}
|
|
|
|
function createSteam() {
|
|
const s = document.createElement('div');
|
|
s.className = 'steam';
|
|
s.style.left = Math.random() * 100 + '%';
|
|
s.style.top = Math.random() * 100 + '%';
|
|
pot.appendChild(s);
|
|
setTimeout(() => s.remove(), 4000);
|
|
}
|
|
|
|
function startDanmu() {
|
|
setInterval(() => {
|
|
if (Math.random() > 0.3) return;
|
|
const d = document.createElement('div');
|
|
d.className = 'danmu';
|
|
d.innerText = funnyComments[Math.floor(Math.random() * funnyComments.length)];
|
|
d.style.top = (Math.random() * 60 + 20) + '%';
|
|
document.body.appendChild(d);
|
|
setTimeout(() => d.remove(), 5000);
|
|
}, 2000);
|
|
}
|
|
|
|
let isCooking = false;
|
|
let speedMultiplier = 1;
|
|
|
|
function animate() {
|
|
ingredients.forEach(item => {
|
|
if (item.removed) return;
|
|
|
|
item.x += item.vx * speedMultiplier;
|
|
item.y += item.vy * speedMultiplier;
|
|
|
|
// 边界碰撞(锅是圆的)
|
|
const dx = item.x + 40 - 300;
|
|
const dy = item.y + 40 - 300;
|
|
const dist = Math.sqrt(dx*dx + dy*dy);
|
|
|
|
if (dist > 250) {
|
|
const nx = dx / dist;
|
|
const ny = dy / dist;
|
|
// 反射向量
|
|
const dot = item.vx * nx + item.vy * ny;
|
|
item.vx = (item.vx - 2 * dot * nx) * 0.9;
|
|
item.vy = (item.vy - 2 * dot * ny) * 0.9;
|
|
// 修正位置防止卡住
|
|
item.x = 300 + nx * 249 - 40;
|
|
item.y = 300 + ny * 249 - 40;
|
|
}
|
|
|
|
item.el.style.left = item.x + 'px';
|
|
item.el.style.top = item.y + 'px';
|
|
});
|
|
requestAnimationFrame(animate);
|
|
}
|
|
|
|
async function startCooking() {
|
|
if (isCooking) return;
|
|
isCooking = true;
|
|
document.getElementById('actionBtn').disabled = true;
|
|
document.getElementById('actionBtn').innerText = "火热开涮中...";
|
|
|
|
if (audioCtx.state === 'suspended') audioCtx.resume();
|
|
const boilSound = playBoilSound();
|
|
|
|
// 加速阶段
|
|
for (let i = 0; i < 20; i++) {
|
|
speedMultiplier += 0.2;
|
|
await new Promise(r => setTimeout(r, 50));
|
|
if (i % 5 === 0) playSound(200 + i * 10, 'sine', 0.1);
|
|
}
|
|
|
|
// 陆续淘汰阶段
|
|
const activeIngredients = ingredients.filter(i => !i.removed);
|
|
const totalSteps = activeIngredients.length - 1;
|
|
|
|
for (let i = 0; i < totalSteps; i++) {
|
|
const currentActive = ingredients.filter(i => !i.removed);
|
|
const randomIndex = Math.floor(Math.random() * currentActive.length);
|
|
const toRemove = currentActive[randomIndex];
|
|
|
|
toRemove.removed = true;
|
|
toRemove.el.classList.add('removed');
|
|
|
|
playSound(150, 'triangle', 0.3, 0.2);
|
|
createSteam();
|
|
|
|
// 间隔时间逐渐拉长
|
|
await new Promise(r => setTimeout(r, 300 + i * 100));
|
|
}
|
|
|
|
// 最后的胜者
|
|
const winner = ingredients.find(i => !i.removed);
|
|
showResult(winner);
|
|
|
|
// 停止声音
|
|
boilSound.gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 1);
|
|
setTimeout(() => boilSound.noise.stop(), 1000);
|
|
}
|
|
|
|
function showResult(winner) {
|
|
const overlay = document.getElementById('resultOverlay');
|
|
const img = document.getElementById('resultImg');
|
|
const name = document.getElementById('resultName');
|
|
const title = document.getElementById('resultTitle');
|
|
|
|
const studentIdx = winner.el.id.split('-')[1];
|
|
img.src = `${imagePath}${studentIdx}.png`;
|
|
name.innerText = `天选之子: ${ingredientNames[studentIdx-1]}`;
|
|
|
|
const titles = ["真香!", "肉质鲜美!", "有点辣手", "极品食材", "嚼劲十足", "入口即化"];
|
|
title.innerText = titles[Math.floor(Math.random() * titles.length)];
|
|
|
|
overlay.style.display = 'flex';
|
|
playSound(523.25, 'square', 0.5, 0.2); // C5
|
|
setTimeout(() => playSound(659.25, 'square', 0.5, 0.2), 150); // E5
|
|
setTimeout(() => playSound(783.99, 'square', 1.0, 0.2), 300); // G5
|
|
}
|
|
|
|
function resetPot() {
|
|
document.getElementById('resultOverlay').style.display = 'none';
|
|
document.getElementById('actionBtn').disabled = false;
|
|
document.getElementById('actionBtn').innerText = "开始开涮!";
|
|
isCooking = false;
|
|
speedMultiplier = 1;
|
|
|
|
ingredients.forEach(item => {
|
|
item.removed = false;
|
|
item.el.classList.remove('removed');
|
|
// 随机重置位置
|
|
const angle = Math.random() * Math.PI * 2;
|
|
const radius = Math.random() * 200;
|
|
item.x = 300 + Math.cos(angle) * radius - 40;
|
|
item.y = 300 + Math.sin(angle) * radius - 40;
|
|
item.vx = (Math.random() - 0.5) * 2;
|
|
item.vy = (Math.random() - 0.5) * 2;
|
|
});
|
|
}
|
|
|
|
window.onload = init;
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|