<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>你喜欢上学吗? — 搞怪问答</title>
<style>
:root {
--bg: #fdf6e3;
--card-bg: #ffffff;
--text: #2c3e50;
--agree-color: #27ae60;
--agree-hover: #2ecc71;
--disagree-color: #e74c3c;
--disagree-hover: #ff6b5e;
--bubble-bg: #fff3cd;
--bubble-text: #856404;
--shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
--progress-bg: #e9ecef;
--progress-fill: #27ae60;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', 'Helvetica Neue', sans-serif;
background: linear-gradient(135deg, #fdf6e3 0%, #fceabb 25%, #f8d7a3 50%, #fdf6e3 75%, #e8f5e9 100%);
background-size: 400% 400%;
animation: bgShift 20s ease infinite;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
overflow-x: hidden;
user-select: none;
-webkit-user-select: none;
-webkit-tap-highlight-color: transparent;
cursor: default;
}
@keyframes bgShift {
0%,
100% {
background-position: 0% 50%;
}
25% {
background-position: 100% 0%;
}
50% {
background-position: 100% 100%;
}
75% {
background-position: 0% 100%;
}
}
/* 主容器 */
.main-container {
width: 100%;
max-width: 650px;
background: var(--card-bg);
border-radius: 28px;
box-shadow: var(--shadow), 0 0 0 1px rgba(0, 0, 0, 0.04);
padding: 40px 36px 36px;
position: relative;
overflow: visible;
transition: transform 0.3s ease;
animation: floatIn 0.6s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}
.main-container.shake {
animation: shake 0.5s ease-in-out;
}
@keyframes floatIn {
0% {
opacity: 0;
transform: translateY(40px) scale(0.95);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@keyframes shake {
0%,
100% {
transform: translateX(0);
}
15% {
transform: translateX(-8px) rotate(-1deg);
}
30% {
transform: translateX(8px) rotate(1deg);
}
45% {
transform: translateX(-6px) rotate(-0.5deg);
}
60% {
transform: translateX(6px) rotate(0.5deg);
}
75% {
transform: translateX(-3px);
}
90% {
transform: translateX(3px);
}
}
/* 顶部装饰 */
.top-emoji {
text-align: center;
font-size: 52px;
margin-bottom: 8px;
animation: bounceEmoji 2s ease-in-out infinite;
pointer-events: none;
}
@keyframes bounceEmoji {
0%,
100% {
transform: translateY(0);
}
30% {
transform: translateY(-18px);
}
50% {
transform: translateY(0);
}
70% {
transform: translateY(-8px);
}
85% {
transform: translateY(0);
}
}
/* 进度条 */
.progress-wrap {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 24px;
}
.progress-bar-outer {
flex: 1;
height: 10px;
background: var(--progress-bg);
border-radius: 99px;
overflow: hidden;
position: relative;
}
.progress-bar-inner {
height: 100%;
background: linear-gradient(90deg, #27ae60, #2ecc71, #58d68d);
border-radius: 99px;
transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
width: 0%;
}
.progress-label {
font-size: 14px;
font-weight: 700;
color: #555;
white-space: nowrap;
min-width: 48px;
text-align: right;
}
/* 问题文本 */
.question-text {
font-size: 26px;
font-weight: 800;
color: var(--text);
text-align: center;
margin-bottom: 32px;
line-height: 1.4;
transition: opacity 0.35s ease, transform 0.35s ease;
pointer-events: none;
letter-spacing: 0.02em;
}
.question-text.fade-out {
opacity: 0;
transform: translateY(-12px);
}
.question-text.fade-in {
opacity: 1;
transform: translateY(0);
}
/* 按钮区域 */
.buttons-area {
position: relative;
width: 100%;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
gap: 40px;
/* 足够容纳两个按钮 */;
}
/* 同意按钮 */
.btn-agree {
position: relative;
z-index: 10;
padding: 16px 44px;
font-size: 20px;
font-weight: 700;
border: none;
border-radius: 99px;
cursor: pointer;
background: linear-gradient(135deg, #27ae60, #2ecc71);
color: #fff;
letter-spacing: 0.06em;
box-shadow: 0 6px 20px rgba(39, 174, 96, 0.35);
transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
box-shadow 0.25s ease,
background 0.25s ease;
outline: none;
-webkit-tap-highlight-color: transparent;
white-space: nowrap;
flex-shrink: 0;
}
.btn-agree:hover {
transform: scale(1.08);
box-shadow: 0 10px 28px rgba(39, 174, 96, 0.5);
background: linear-gradient(135deg, #2ecc71, #58d68d);
}
.btn-agree:active {
transform: scale(0.94);
transition: transform 0.1s ease;
box-shadow: 0 3px 10px rgba(39, 174, 96, 0.3);
}
/* 同意按钮膨胀(霸凌模式) */
.btn-agree.bullying {
animation: bullyExpand 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
z-index: 25 !important;
}
@keyframes bullyExpand {
0% {
transform: scale(1);
}
40% {
transform: scale(1.55);
}
70% {
transform: scale(1.45);
}
100% {
transform: scale(1);
}
}
/* 不同意按钮 — 绝对定位,自由逃跑 */
.btn-disagree {
position: absolute;
z-index: 15;
padding: 16px 36px;
font-size: 20px;
font-weight: 700;
border: 2.5px solid #e74c3c;
border-radius: 99px;
cursor: pointer;
background: #fff;
color: #e74c3c;
letter-spacing: 0.06em;
box-shadow: 0 4px 16px rgba(231, 76, 60, 0.2);
transition: transform 0.12s ease-out,
left 0.08s linear,
top 0.08s linear,
box-shadow 0.2s ease;
outline: none;
-webkit-tap-highlight-color: transparent;
white-space: nowrap;
flex-shrink: 0;
will-change: transform, left, top;
}
.btn-disagree:hover {
box-shadow: 0 6px 22px rgba(231, 76, 60, 0.4);
}
.btn-disagree:active {
transform: scale(0.9);
transition: transform 0.06s ease;
}
/* 瞬移时的动画 */
.btn-disagree.teleporting {
transition: transform 0.15s cubic-bezier(0.6, 0, 1, 1),
left 0s,
top 0s;
transform: scale(0.05) !important;
pointer-events: none;
}
.btn-disagree.teleport-arrive {
transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
left 0s,
top 0s;
transform: scale(1) !important;
}
/* 嘲讽气泡 */
.taunt-bubble {
position: absolute;
z-index: 50;
pointer-events: none;
background: var(--bubble-bg);
color: var(--bubble-text);
font-weight: 700;
font-size: 15px;
padding: 10px 18px;
border-radius: 20px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
opacity: 0;
transform: translate(-50%, -120%) scale(0.3);
transition: opacity 0.25s ease, transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
white-space: nowrap;
text-align: center;
}
.taunt-bubble.visible {
opacity: 1;
transform: translate(-50%, -130%) scale(1);
}
.taunt-bubble::after {
content: '';
position: absolute;
bottom: -8px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid var(--bubble-bg);
}
/* 额外浮动嘲讽(从按钮弹出) */
.float-taunt {
position: fixed;
z-index: 100;
pointer-events: none;
font-weight: 900;
font-size: 18px;
color: #e74c3c;
animation: floatUp 1.2s ease-out forwards;
white-space: nowrap;
text-shadow: 0 2px 8px rgba(231, 76, 60, 0.3);
}
@keyframes floatUp {
0% {
opacity: 1;
transform: translate(-50%, 0) scale(0.6);
}
30% {
opacity: 1;
transform: translate(-50%, -40px) scale(1.2);
}
100% {
opacity: 0;
transform: translate(-50%, -100px) scale(0.8);
}
}
/* 结算页面 */
.result-screen {
display: none;
text-align: center;
animation: floatIn 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}
.result-screen.active {
display: block;
}
.result-emoji {
font-size: 80px;
animation: bounceEmoji 1.5s ease-in-out infinite;
pointer-events: none;
}
.result-title {
font-size: 30px;
font-weight: 900;
color: #2c3e50;
margin: 16px 0 8px;
letter-spacing: 0.03em;
}
.result-subtitle {
font-size: 17px;
color: #666;
margin-bottom: 20px;
line-height: 1.6;
}
.result-list {
text-align: left;
max-width: 400px;
margin: 0 auto 24px;
list-style: none;
padding: 0;
}
.result-list li {
padding: 10px 16px;
margin: 6px 0;
background: #f8f9fa;
border-radius: 12px;
font-size: 15px;
color: #444;
display: flex;
align-items: center;
gap: 10px;
animation: slideInItem 0.4s ease forwards;
opacity: 0;
}
.result-list li:nth-child(1) {
animation-delay: 0.1s;
}
.result-list li:nth-child(2) {
animation-delay: 0.2s;
}
.result-list li:nth-child(3) {
animation-delay: 0.3s;
}
.result-list li:nth-child(4) {
animation-delay: 0.4s;
}
.result-list li:nth-child(5) {
animation-delay: 0.5s;
}
.result-list li:nth-child(6) {
animation-delay: 0.6s;
}
.result-list li:nth-child(7) {
animation-delay: 0.7s;
}
.result-list li:nth-child(8) {
animation-delay: 0.8s;
}
.result-list li:nth-child(9) {
animation-delay: 0.9s;
}
.result-list li:nth-child(10) {
animation-delay: 1s;
}
@keyframes slideInItem {
0% {
opacity: 0;
transform: translateX(-20px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
.result-list .check-mark {
color: #27ae60;
font-weight: 900;
font-size: 18px;
}
.btn-restart {
padding: 14px 40px;
font-size: 18px;
font-weight: 700;
border: none;
border-radius: 99px;
cursor: pointer;
background: linear-gradient(135deg, #f39c12, #e67e22);
color: #fff;
letter-spacing: 0.05em;
box-shadow: 0 6px 20px rgba(243, 156, 18, 0.35);
transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1),
box-shadow 0.25s ease;
outline: none;
}
.btn-restart:hover {
transform: scale(1.08);
box-shadow: 0 10px 28px rgba(243, 156, 18, 0.5);
}
.btn-restart:active {
transform: scale(0.94);
}
/* 隐藏问题区 */
.question-screen.hidden {
display: none;
}
/* 粒子(瞬移时的小特效) */
.poof-particle {
position: fixed;
pointer-events: none;
z-index: 90;
font-size: 24px;
animation: poofOut 0.6s ease-out forwards;
}
@keyframes poofOut {
0% {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
100% {
opacity: 0;
transform: translate(-50%, -50%) scale(2.5);
}
}
/* 响应式 */
@media (max-width: 600px) {
.main-container {
padding: 28px 18px 24px;
border-radius: 20px;
}
.question-text {
font-size: 20px;
margin-bottom: 20px;
}
.btn-agree,
.btn-disagree {
padding: 12px 28px;
font-size: 16px;
}
.buttons-area {
height: 80px;
gap: 20px;
}
.top-emoji {
font-size: 38px;
}
.result-title {
font-size: 24px;
}
.result-emoji {
font-size: 56px;
}
}
</style>
</head>
<body>
<!-- 主容器 -->
<div class="main-container" id="mainContainer">
<!-- 顶部表情 -->
<div class="top-emoji" id="topEmoji">🤔</div>
<!-- 问题界面 -->
<div class="question-screen" id="questionScreen">
<!-- 进度条 -->
<div class="progress-wrap">
<div class="progress-bar-outer">
<div class="progress-bar-inner" id="progressBar" style="width: 0%;"></div>
</div>
<span class="progress-label" id="progressLabel">1/10</span>
</div>
<!-- 问题文本 -->
<p class="question-text fade-in" id="questionText"></p>
<!-- 按钮区域 -->
<div class="buttons-area" id="buttonsArea">
<button class="btn-agree" id="btnAgree">👍 同意</button>
<button class="btn-disagree" id="btnDisagree">👎 不同意</button>
</div>
<!-- 嘲讽气泡 -->
<div class="taunt-bubble" id="tauntBubble"></div>
</div>
<!-- 结算界面 -->
<div class="result-screen" id="resultScreen">
<div class="result-emoji">😏</div>
<div class="result-title" id="resultTitle"></div>
<div class="result-subtitle" id="resultSubtitle"></div>
<ul class="result-list" id="resultList"></ul>
<button class="btn-restart" id="btnRestart">🔄 再来一次</button>
</div>
</div>
<script>
(function() {
// ==================== DOM 引用 ====================
const mainContainer = document.getElementById('mainContainer');
const questionScreen = document.getElementById('questionScreen');
const resultScreen = document.getElementById('resultScreen');
const topEmoji = document.getElementById('topEmoji');
const progressBar = document.getElementById('progressBar');
const progressLabel = document.getElementById('progressLabel');
const questionText = document.getElementById('questionText');
const buttonsArea = document.getElementById('buttonsArea');
const btnAgree = document.getElementById('btnAgree');
const btnDisagree = document.getElementById('btnDisagree');
const tauntBubble = document.getElementById('tauntBubble');
const resultTitle = document.getElementById('resultTitle');
const resultSubtitle = document.getElementById('resultSubtitle');
const resultList = document.getElementById('resultList');
const btnRestart = document.getElementById('btnRestart');
// ==================== 问题列表 ====================
const questions = [
{ text: '你喜欢上学吗?', emoji: '🏫' },
{ text: '你喜欢写作业吗?', emoji: '📝' },
{ text: '你喜欢早上6点起床吗?', emoji: '⏰' },
{ text: '你喜欢背课文吗?', emoji: '📖' },
{ text: '你喜欢数学考试吗?', emoji: '🧮' },
{ text: '你喜欢体育课跑800米吗?', emoji: '🏃' },
{ text: '你喜欢被老师点名回答问题吗?', emoji: '🙋' },
{ text: '你喜欢做眼保健操吗?', emoji: '👀' },
{ text: '你喜欢开学第一天吗?', emoji: '🎒' },
{ text: '你喜欢补寒假作业吗?', emoji: '😱' },
];
// ==================== 嘲讽语句池 ====================
const taunts = [
'休想点到我!😜',
'做梦呢?💤',
'再快也追不上我~🏃💨',
'手速不够啊兄弟!🐢',
'放弃吧!🤪',
'嘿嘿,点不到~😝',
'你以为你能点到我?🤨',
'太慢了!🐌',
'我就知道你想选不同意!😏',
'想都别想!🙅',
'差一点!就差一点!😂',
'你的鼠标太慢啦~🖱️💨',
'哼!休想!😤',
'又被我躲开了!✌️',
'别挣扎了,点同意吧~🤗',
];
// ==================== 状态 ====================
let currentQuestionIndex = 0;
let disagreeClickCount = 0; // 玩家成功点到不同意的次数
let mouseX = -999;
let mouseY = -999;
let disagreeBtnLeft = 0;
let disagreeBtnTop = 0;
let disagreeBtnScale = 1;
let isTeleporting = false;
let isTransitioning = false; // 题目切换中
let tauntTimeout = null;
let animationFrameId = null;
let bullyCooldown = 0; // 霸凌冷却计时
let lastBullyTime = 0;
let containerRect = null;
let buttonsAreaRect = null;
let disagreeBtnWidth = 0;
let disagreeBtnHeight = 0;
// ==================== 初始化不同意按钮位置 ====================
function resetDisagreeBtnPosition() {
// 将不同意按钮放到同意按钮右侧
const agreeRect = btnAgree.getBoundingClientRect();
const areaRect = buttonsArea.getBoundingClientRect();
const relLeft = agreeRect.right - areaRect.left + 40; // 同意按钮右边40px
const relTop = (areaRect.height - disagreeBtnHeight) / 2;
// 确保在区域内
const maxLeft = areaRect.width - disagreeBtnWidth - 10;
const clampedLeft = Math.min(Math.max(10, relLeft), maxLeft);
const clampedTop = Math.min(Math.max(5, relTop), areaRect.height - disagreeBtnHeight - 5);
btnDisagree.style.left = clampedLeft + 'px';
btnDisagree.style.top = clampedTop + 'px';
btnDisagree.style.transform = 'scale(1)';
disagreeBtnLeft = clampedLeft;
disagreeBtnTop = clampedTop;
disagreeBtnScale = 1;
isTeleporting = false;
btnDisagree.classList.remove('teleporting', 'teleport-arrive');
updateDisagreeBtnSize();
}
function updateDisagreeBtnSize() {
const rect = btnDisagree.getBoundingClientRect();
disagreeBtnWidth = rect.width;
disagreeBtnHeight = rect.height;
}
// ==================== 鼠标追踪 ====================
function updateMousePosition(e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
function updateTouchPosition(e) {
if (e.touches && e.touches.length > 0) {
mouseX = e.touches[0].clientX;
mouseY = e.touches[0].clientY;
}
}
document.addEventListener('mousemove', updateMousePosition, { passive: true });
document.addEventListener('touchmove', updateTouchPosition, { passive: true });
document.addEventListener('touchstart', updateTouchPosition, { passive: true });
// ==================== 主循环 ====================
function gameLoop() {
if (isTransitioning || isTeleporting) {
animationFrameId = requestAnimationFrame(gameLoop);
return;
}
if (currentQuestionIndex >= questions.length) {
// 游戏结束,停止循环
animationFrameId = requestAnimationFrame(gameLoop);
return;
}
buttonsAreaRect = buttonsArea.getBoundingClientRect();
containerRect = mainContainer.getBoundingClientRect();
// 获取不同意按钮中心在页面上的坐标
const btnRect = btnDisagree.getBoundingClientRect();
const btnCenterX = btnRect.left + btnRect.width / 2;
const btnCenterY = btnRect.top + btnRect.height / 2;
// 计算鼠标到按钮中心的距离
const dx = mouseX - btnCenterX;
const dy = mouseY - btnCenterY;
const distance = Math.sqrt(dx * dx + dy * dy);
const evadeThreshold = 280; // 开始躲避的距离阈值
const minScale = 0.15; // 最小缩放
const criticalDistance = 60; // 触发瞬移的临界距离
if (distance < evadeThreshold && mouseX > 0 && mouseY > 0) {
// 计算远离方向
const angle = Math.atan2(dy, dx);
const fleeAngle = angle + Math.PI; // 反方向(远离鼠标)
// 移动速度:距离越近越快
const speedMultiplier = (evadeThreshold - distance) / evadeThreshold; // 0~1
const baseSpeed = 12;
const speed = baseSpeed * speedMultiplier + 2;
let newLeft = disagreeBtnLeft + Math.cos(fleeAngle) * speed;
let newTop = disagreeBtnTop + Math.sin(fleeAngle) * speed;
// 边界约束
const areaW = buttonsAreaRect.width;
const areaH = buttonsAreaRect.height;
const bw = disagreeBtnWidth * disagreeBtnScale;
const bh = disagreeBtnHeight * disagreeBtnScale;
newLeft = Math.max(0, Math.min(newLeft, areaW - bw));
newTop = Math.max(0, Math.min(newTop, areaH - bh));
// 更新按钮位置
disagreeBtnLeft = newLeft;
disagreeBtnTop = newTop;
btnDisagree.style.left = newLeft + 'px';
btnDisagree.style.top = newTop + 'px';
// 更新缩放:距离越近越小
const targetScale = Math.max(minScale, distance / evadeThreshold);
disagreeBtnScale = targetScale;
btnDisagree.style.transform = `scale(${targetScale})`;
// 霸凌检测:当不同意按钮缩得很小时,同意按钮膨胀
if (targetScale < 0.3 && Date.now() - lastBullyTime > 1500 && bullyCooldown <= 0) {
triggerBully();
}
// 瞬移检测:如果距离非常近且按钮已经很小
if (distance < criticalDistance && targetScale < 0.25 && !isTeleporting) {
triggerTeleport();
}
} else {
// 鼠标远离,缓慢恢复大小
if (disagreeBtnScale < 0.98) {
disagreeBtnScale = Math.min(1, disagreeBtnScale + 0.04);
btnDisagree.style.transform = `scale(${disagreeBtnScale})`;
}
// 缓慢向初始位置靠拢
const agreeRect = btnAgree.getBoundingClientRect();
const areaRect = buttonsAreaRect;
const homeLeft = agreeRect.right - areaRect.left + 40;
const homeTop = (areaRect.height - disagreeBtnHeight) / 2;
const homeLeftClamped = Math.min(Math.max(10, homeLeft), areaRect.width - disagreeBtnWidth - 10);
const homeTopClamped = Math.min(Math.max(5, homeTop), areaRect.height - disagreeBtnHeight - 5);
const lx = homeLeftClamped - disagreeBtnLeft;
const ly = homeTopClamped - disagreeBtnTop;
const homeDist = Math.sqrt(lx * lx + ly * ly);
if (homeDist > 2) {
const returnSpeed = 1.5;
disagreeBtnLeft += (lx / homeDist) * returnSpeed;
disagreeBtnTop += (ly / homeDist) * returnSpeed;
btnDisagree.style.left = disagreeBtnLeft + 'px';
btnDisagree.style.top = disagreeBtnTop + 'px';
}
}
// 冷却计时
if (bullyCooldown > 0) {
bullyCooldown--;
}
animationFrameId = requestAnimationFrame(gameLoop);
}
// ==================== 瞬移 ====================
function triggerTeleport() {
if (isTeleporting) return;
isTeleporting = true;
// 先缩小
btnDisagree.classList.add('teleporting');
btnDisagree.style.transform = 'scale(0.05)';
btnDisagree.style.pointerEvents = 'none';
// 在原位置放一个粒子效果
spawnPoof(btnDisagree);
// 短暂延迟后传送到新位置
setTimeout(() => {
const areaW = buttonsAreaRect.width;
const areaH = buttonsAreaRect.height;
const bw = disagreeBtnWidth;
const bh = disagreeBtnHeight;
// 找一个远离鼠标的安全位置
let bestLeft = disagreeBtnLeft;
let bestTop = disagreeBtnTop;
let bestDist = 0;
const mouseRelX = mouseX - buttonsAreaRect.left;
const mouseRelY = mouseY - buttonsAreaRect.top;
for (let attempt = 0; attempt < 30; attempt++) {
const candidateLeft = Math.random() * (areaW - bw);
const candidateTop = Math.random() * (areaH - bh);
const cx = candidateLeft + bw / 2;
const cy = candidateTop + bh / 2;
const dist = Math.sqrt((cx - mouseRelX) ** 2 + (cy - mouseRelY) ** 2);
if (dist > bestDist) {
bestDist = dist;
bestLeft = candidateLeft;
bestTop = candidateTop;
}
// 如果找到足够远的位置就停止
if (bestDist > 250) break;
}
disagreeBtnLeft = bestLeft;
disagreeBtnTop = bestTop;
disagreeBtnScale = 1;
btnDisagree.style.left = bestLeft + 'px';
btnDisagree.style.top = bestTop + 'px';
btnDisagree.classList.remove('teleporting');
btnDisagree.classList.add('teleport-arrive');
btnDisagree.style.transform = 'scale(1)';
btnDisagree.style.pointerEvents = 'auto';
// 在新位置放粒子
setTimeout(() => {
spawnPoof(btnDisagree);
}, 50);
setTimeout(() => {
btnDisagree.classList.remove('teleport-arrive');
isTeleporting = false;
}, 350);
}, 180);
}
function spawnPoof(element) {
const rect = element.getBoundingClientRect();
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
const particle = document.createElement('span');
particle.className = 'poof-particle';
particle.textContent = '💨';
particle.style.left = cx + 'px';
particle.style.top = cy + 'px';
document.body.appendChild(particle);
setTimeout(() => particle.remove(), 600);
}
// ==================== 霸凌(同意按钮膨胀) ====================
function triggerBully() {
lastBullyTime = Date.now();
bullyCooldown = 40; // 约40帧(~0.67秒)冷却
btnAgree.classList.remove('bullying');
void btnAgree.offsetWidth; // reflow
btnAgree.classList.add('bullying');
setTimeout(() => {
btnAgree.classList.remove('bullying');
}, 700);
}
// ==================== 嘲讽气泡 ====================
function showTauntBubble(targetBtn) {
if (tauntTimeout) clearTimeout(tauntTimeout);
const rect = targetBtn.getBoundingClientRect();
const areaRect = buttonsArea.getBoundingClientRect();
const bubbleX = rect.left - areaRect.left + rect.width / 2;
const bubbleY = rect.top - areaRect.top;
tauntBubble.style.left = bubbleX + 'px';
tauntBubble.style.top = bubbleY + 'px';
tauntBubble.textContent = taunts[Math.floor(Math.random() * taunts.length)];
tauntBubble.classList.add('visible');
tauntTimeout = setTimeout(() => {
tauntBubble.classList.remove('visible');
}, 1400);
}
function spawnFloatTaunt(targetBtn) {
const rect = targetBtn.getBoundingClientRect();
const cx = rect.left + rect.width / 2;
const cy = rect.top;
const el = document.createElement('span');
el.className = 'float-taunt';
el.textContent = taunts[Math.floor(Math.random() * taunts.length)];
el.style.left = cx + 'px';
el.style.top = cy + 'px';
document.body.appendChild(el);
setTimeout(() => el.remove(), 1300);
}
// ==================== 题目切换 ====================
function goToNextQuestion() {
if (isTransitioning) return;
isTransitioning = true;
currentQuestionIndex++;
if (currentQuestionIndex >= questions.length) {
// 全部完成,显示结算
showResults();
isTransitioning = false;
return;
}
// 淡出当前题目
questionText.classList.add('fade-out');
tauntBubble.classList.remove('visible');
if (tauntTimeout) clearTimeout(tauntTimeout);
setTimeout(() => {
// 更新内容
const q = questions[currentQuestionIndex];
questionText.textContent = q.text;
topEmoji.textContent = q.emoji;
progressBar.style.width = ((currentQuestionIndex) / questions.length * 100) + '%';
progressLabel.textContent = (currentQuestionIndex + 1) + '/' + questions.length;
// 重置不同意按钮
updateDisagreeBtnSize();
resetDisagreeBtnPosition();
updateDisagreeBtnSize();
// 淡入
questionText.classList.remove('fade-out');
questionText.classList.add('fade-in');
setTimeout(() => {
questionText.classList.remove('fade-in');
}, 350);
isTransitioning = false;
}, 350);
}
// ==================== 结算 ====================
function showResults() {
questionScreen.classList.add('hidden');
resultScreen.classList.add('active');
mainContainer.querySelector('.top-emoji').textContent = '🎉';
const total = questions.length;
const struggles = disagreeClickCount;
if (struggles === 0) {
resultTitle.textContent = '全部真心同意!';
resultSubtitle.textContent = '我就知道你是学霸!一次都没挣扎过~ 🎉';
topEmoji.textContent = '🤩';
} else if (struggles <= 2) {
resultTitle.textContent = '嘴上说不要,身体很诚实嘛~';
resultSubtitle.textContent = `虽然挣扎了 ${struggles} 次,但最后全都乖乖同意了!😏`;
topEmoji.textContent = '😏';
} else if (struggles <= 5) {
resultTitle.textContent = '挣扎得挺激烈啊!';
resultSubtitle.textContent = `足足点了 ${struggles} 次不同意...但有什么用呢?还是全同意了~ 🤪`;
topEmoji.textContent = '🤪';
} else {
resultTitle.textContent = '你真是倔强啊!';
resultSubtitle.textContent =
`${struggles} 次挣扎!手都点酸了吧?但结果嘛...嘿嘿,我就知道你喜欢上学!😤`;
topEmoji.textContent = '😤';
}
// 生成列表
resultList.innerHTML = '';
questions.forEach((q, i) => {
const li = document.createElement('li');
li.innerHTML = `<span class="check-mark">✅</span> 我就知道${q.text.replace('吗', '').replace('?', '')}!`;
resultList.appendChild(li);
});
// 更新进度条到100%
progressBar.style.width = '100%';
progressLabel.textContent = '完!';
}
function restartGame() {
currentQuestionIndex = 0;
disagreeClickCount = 0;
isTransitioning = false;
isTeleporting = false;
disagreeBtnScale = 1;
bullyCooldown = 0;
lastBullyTime = 0;
if (tauntTimeout) clearTimeout(tauntTimeout);
// 重置UI
questionScreen.classList.remove('hidden');
resultScreen.classList.remove('active');
tauntBubble.classList.remove('visible');
btnAgree.classList.remove('bullying');
btnDisagree.classList.remove('teleporting', 'teleport-arrive');
btnDisagree.style.pointerEvents = 'auto';
btnDisagree.style.transform = 'scale(1)';
const q = questions[0];
questionText.textContent = q.text;
questionText.classList.remove('fade-out', 'fade-in');
topEmoji.textContent = q.emoji;
progressBar.style.width = '0%';
progressLabel.textContent = '1/10';
mainContainer.querySelector('.top-emoji').textContent = '🤔';
topEmoji.textContent = q.emoji;
updateDisagreeBtnSize();
resetDisagreeBtnPosition();
updateDisagreeBtnSize();
buttonsAreaRect = buttonsArea.getBoundingClientRect();
containerRect = mainContainer.getBoundingClientRect();
}
// ==================== 事件绑定 ====================
// 同意按钮
btnAgree.addEventListener('click', (e) => {
if (isTransitioning || currentQuestionIndex >= questions.length) return;
e.stopPropagation();
goToNextQuestion();
});
// 不同意按钮
btnDisagree.addEventListener('click', (e) => {
if (isTransitioning || isTeleporting || currentQuestionIndex >= questions.length) return;
e.stopPropagation();
e.preventDefault();
// 点到不同意!
disagreeClickCount++;
showTauntBubble(btnDisagree);
spawnFloatTaunt(btnDisagree);
// 震动容器
mainContainer.classList.add('shake');
setTimeout(() => mainContainer.classList.remove('shake'), 500);
// 短暂延迟后进入下一题
setTimeout(() => {
if (currentQuestionIndex < questions.length) {
goToNextQuestion();
}
}, 900);
});
// 防止不同意按钮被Tab键聚焦(搞怪:聚焦即瞬移)
btnDisagree.addEventListener('focus', (e) => {
if (isTransitioning || currentQuestionIndex >= questions.length) return;
if (!isTeleporting) {
triggerTeleport();
// 把焦点转移到同意按钮
setTimeout(() => btnAgree.focus(), 200);
}
});
// 设置tabindex使得它能被聚焦但不显示轮廓太明显
btnDisagree.setAttribute('tabindex', '0');
// 重新开始按钮
btnRestart.addEventListener('click', () => {
restartGame();
});
// 窗口大小变化时更新
window.addEventListener('resize', () => {
updateDisagreeBtnSize();
buttonsAreaRect = buttonsArea.getBoundingClientRect();
containerRect = mainContainer.getBoundingClientRect();
// 确保按钮在边界内
const areaW = buttonsAreaRect.width;
const areaH = buttonsAreaRect.height;
const bw = disagreeBtnWidth * disagreeBtnScale;
const bh = disagreeBtnHeight * disagreeBtnScale;
disagreeBtnLeft = Math.max(0, Math.min(disagreeBtnLeft, areaW - bw));
disagreeBtnTop = Math.max(0, Math.min(disagreeBtnTop, areaH - bh));
btnDisagree.style.left = disagreeBtnLeft + 'px';
btnDisagree.style.top = disagreeBtnTop + 'px';
});
// ==================== 初始化 ====================
function init() {
const q = questions[0];
questionText.textContent = q.text;
topEmoji.textContent = q.emoji;
progressBar.style.width = '0%';
progressLabel.textContent = '1/10';
questionText.classList.add('fade-in');
setTimeout(() => questionText.classList.remove('fade-in'), 350);
updateDisagreeBtnSize();
resetDisagreeBtnPosition();
updateDisagreeBtnSize();
buttonsAreaRect = buttonsArea.getBoundingClientRect();
containerRect = mainContainer.getBoundingClientRect();
// 启动游戏循环
animationFrameId = requestAnimationFrame(gameLoop);
}
init();
// ==================== 清理(非必须,但良好实践) ====================
window.addEventListener('beforeunload', () => {
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
});
console.log('🤪 搞怪问答已就绪!');
console.log('💡 提示:试试用最快的速度去点"不同意"按钮,看你能点到几次~');
console.log('📱 桌面端体验最佳,移动端不同意按钮也会随机逃跑哦~');
})();
</script>
</body>
</html>