垃圾分類遊戲 將垃圾拖放到正確的回收箱中 分數: 0 正確: 0 錯誤: 0 等級: 1 紙類 塑膠 金屬 玻璃 一般垃圾 遊戲說明 紙類:報紙、紙箱、紙張 塑膠:寶特瓶、塑膠袋、塑膠容器 金屬:鋁罐、鐵罐、金屬瓶蓋 玻璃:玻璃瓶、玻璃杯 一般垃圾:食物殘渣、髒紙巾、口香糖 開發人員 城市碼 × 複製代碼
將垃圾拖放到正確的回收箱中
分數: 0
正確: 0
錯誤: 0
等級: 1
<html lang="zh-TW"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>垃圾分類遊戲</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Microsoft JhengHei', sans-serif;
background-color: #e0f2e9;
overflow-x: hidden;
}
.draggable {
cursor: grab;
transition: transform 0.1s;
}
.draggable:active {
cursor: grabbing;
transform: scale(1.05);
}
.bin {
transition: all 0.3s;
}
.bin.highlight {
transform: scale(1.05);
box-shadow: 0 0 15px rgba(0,0,0,0.3);
}
.waste-item {
position: absolute;
user-select: none;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.7);
z-index: 50;
}
.confetti {
position: absolute;
width: 10px;
height: 10px;
opacity: 0;
animation: fall 3s ease-out forwards;
}
@keyframes fall {
0% {
transform: translateY(-100px) rotate(0deg);
opacity: 1;
}
100% {
transform: translateY(100vh) rotate(360deg);
opacity: 0;
}
}
</style>
<style>*, ::before, ::after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / 0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/* ! tailwindcss v3.4.16 | MIT License | https://tailwindcss.com */*,::after,::before{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}::after,::before{--tw-content:''}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.fixed{position:fixed}.relative{position:relative}.bottom-4{bottom:1rem}.right-4{right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-8{margin-top:2rem;margin-bottom:2rem}.mb-1{margin-bottom:0.25rem}.mb-2{margin-bottom:0.5rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mt-12{margin-top:3rem}.mt-2{margin-top:0.5rem}.mt-20{margin-top:5rem}.flex{display:flex}.h-1\/4{height:25%}.h-2\.5{height:0.625rem}.h-32{height:8rem}.max-h-\[80vh\]{max-height:80vh}.min-h-\[400px\]{min-height:400px}.min-h-screen{min-height:100vh}.w-11\/12{width:91.666667%}.w-24{width:6rem}.w-full{width:100%}.max-w-4xl{max-width:56rem}.max-w-md{max-width:28rem}.cursor-pointer{cursor:pointer}.list-disc{list-style-type:disc}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-4{gap:1rem}.gap-8{gap:2rem}.space-y-2 > :not([hidden]) ~ :not([hidden]){--tw-space-y-reverse:0;margin-top:calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0.5rem * var(--tw-space-y-reverse))}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:0.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:0.5rem}.rounded-xl{border-radius:0.75rem}.rounded-t-lg{border-top-left-radius:0.5rem;border-top-right-radius:0.5rem}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128 / var(--tw-bg-opacity, 1))}.bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99 / var(--tw-bg-opacity, 1))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-600{--tw-bg-opacity:1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-yellow-500{--tw-bg-opacity:1;background-color:rgb(234 179 8 / var(--tw-bg-opacity, 1))}.bg-yellow-600{--tw-bg-opacity:1;background-color:rgb(202 138 4 / var(--tw-bg-opacity, 1))}.p-2{padding:0.5rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-3{padding:0.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-2{padding-top:0.5rem;padding-bottom:0.5rem}.py-3{padding-top:0.75rem;padding-bottom:0.75rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pl-6{padding-left:1.5rem}.text-center{text-align:center}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:0.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:0.75rem;line-height:1rem}.font-bold{font-weight:700}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity:1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity:1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.shadow-lg{--tw-shadow:0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)}.transition{transition-property:color, background-color, border-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-text-decoration-color, -webkit-backdrop-filter;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-text-decoration-color, -webkit-backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-700:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(21 128 61 / var(--tw-bg-opacity, 1))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}@media (min-width: 768px){.md\:h-40{height:10rem}.md\:w-32{width:8rem}.md\:flex-row{flex-direction:row}.md\:gap-8{gap:2rem}}</style></head>
<body class="min-h-screen">
<div class="container mx-auto px-4 py-8">
<header class="text-center mb-8">
<h1 class="text-4xl font-bold text-green-700 mb-2">垃圾分類遊戲</h1>
<p class="text-lg text-gray-700">將垃圾拖放到正確的回收箱中</p>
</header>
<div class="flex flex-col md:flex-row justify-center gap-8 mb-8">
<div class="stats bg-white p-4 rounded-lg shadow-md">
<p class="text-xl font-bold">分數: <span id="score">0</span></p>
<p>正確: <span id="correct">0</span></p>
<p>錯誤: <span id="wrong">0</span></p>
</div>
<div class="level bg-white p-4 rounded-lg shadow-md">
<p class="text-xl font-bold">等級: <span id="level">1</span></p>
<div class="w-full bg-gray-200 rounded-full h-2.5 mt-2">
<div id="progress-bar" class="bg-green-600 h-2.5 rounded-full" style="width: 0%"></div>
</div>
</div>
</div>
<div class="game-area relative bg-white rounded-xl shadow-lg p-6 min-h-[400px] mb-8">
<div id="waste-container" class="flex flex-wrap justify-center gap-4 mb-8"><div id="item-glass-jar-0" class="waste-item draggable bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center" data-type="glass" style="width: 80px; height: 80px; left: 50.9871px; top: 110.659px;">
<div class="text-4xl mb-1">🏺</div>
<div class="text-xs text-center">玻璃罐</div>
</div><div id="item-newspaper-1" class="waste-item draggable bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center" data-type="paper" style="width: 80px; height: 80px; left: 711.032px; top: 143.79px;">
<div class="text-4xl mb-1">📰</div>
<div class="text-xs text-center">報紙</div>
</div><div id="item-cardboard-2" class="waste-item draggable bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center" data-type="paper" style="width: 80px; height: 80px; left: 385.724px; top: 218.425px;">
<div class="text-4xl mb-1">📦</div>
<div class="text-xs text-center">紙箱</div>
</div><div id="item-glass-bottle-3" class="waste-item draggable bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center" data-type="glass" style="width: 80px; height: 80px; left: 890.884px; top: 129.65px;">
<div class="text-4xl mb-1">🍾</div>
<div class="text-xs text-center">玻璃瓶</div>
</div></div>
<div class="bins-container flex flex-wrap justify-center gap-4 md:gap-8 mt-12">
<div id="bin-paper" class="bin w-24 h-32 md:w-32 md:h-40 bg-blue-500 rounded-lg flex flex-col items-center justify-end p-2 cursor-pointer">
<div class="bin-top w-full h-1/4 bg-blue-600 rounded-t-lg mb-1"></div>
<div class="bin-label text-white text-center font-bold">紙類</div>
</div>
<div id="bin-plastic" class="bin w-24 h-32 md:w-32 md:h-40 bg-yellow-500 rounded-lg flex flex-col items-center justify-end p-2 cursor-pointer">
<div class="bin-top w-full h-1/4 bg-yellow-600 rounded-t-lg mb-1"></div>
<div class="bin-label text-white text-center font-bold">塑膠</div>
</div>
<div id="bin-metal" class="bin w-24 h-32 md:w-32 md:h-40 bg-red-500 rounded-lg flex flex-col items-center justify-end p-2 cursor-pointer">
<div class="bin-top w-full h-1/4 bg-red-600 rounded-t-lg mb-1"></div>
<div class="bin-label text-white text-center font-bold">金屬</div>
</div>
<div id="bin-glass" class="bin w-24 h-32 md:w-32 md:h-40 bg-green-500 rounded-lg flex flex-col items-center justify-end p-2 cursor-pointer">
<div class="bin-top w-full h-1/4 bg-green-600 rounded-t-lg mb-1"></div>
<div class="bin-label text-white text-center font-bold">玻璃</div>
</div>
<div id="bin-general" class="bin w-24 h-32 md:w-32 md:h-40 bg-gray-500 rounded-lg flex flex-col items-center justify-end p-2 cursor-pointer">
<div class="bin-top w-full h-1/4 bg-gray-600 rounded-t-lg mb-1"></div>
<div class="bin-label text-white text-center font-bold">一般垃圾</div>
</div>
</div>
</div>
<div class="instructions bg-white p-6 rounded-lg shadow-md mb-8">
<h2 class="text-2xl font-bold text-green-700 mb-4">遊戲說明</h2>
<ul class="list-disc pl-6 space-y-2">
<li><span class="font-bold text-blue-500">紙類</span>:報紙、紙箱、紙張</li>
<li><span class="font-bold text-yellow-500">塑膠</span>:寶特瓶、塑膠袋、塑膠容器</li>
<li><span class="font-bold text-red-500">金屬</span>:鋁罐、鐵罐、金屬瓶蓋</li>
<li><span class="font-bold text-green-500">玻璃</span>:玻璃瓶、玻璃杯</li>
<li><span class="font-bold text-gray-500">一般垃圾</span>:食物殘渣、髒紙巾、口香糖</li>
</ul>
</div>
</div>
<!-- 開發人員按鈕 -->
<button id="dev-button" class="fixed bottom-4 right-4 bg-gray-800 text-white px-4 py-2 rounded-lg shadow-lg hover:bg-gray-700 transition">
開發人員
</button>
<!-- 開發人員模式 -->
<div id="dev-modal" class="modal">
<div class="modal-content bg-white w-11/12 max-w-4xl mx-auto my-8 p-6 rounded-lg shadow-xl overflow-y-auto max-h-[80vh]">
<div class="flex justify-between items-center mb-4">
<h2 class="text-2xl font-bold">城市碼</h2>
<button id="close-modal" class="text-gray-500 hover:text-gray-800 text-2xl">×</button>
</div>
<div class="mb-4">
<button id="copy-code" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition">複製代碼</button>
</div>
<pre id="city-code" class="bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm"></pre>
</div>
</div>
<!-- 遊戲結束模態框 -->
<div id="game-over-modal" class="modal">
<div class="modal-content bg-white w-11/12 max-w-md mx-auto mt-20 p-6 rounded-lg shadow-xl text-center">
<h2 class="text-3xl font-bold mb-4">遊戲結束!</h2>
<p class="text-xl mb-2">最終分數: <span id="final-score" class="font-bold text-green-600">0</span></p>
<p class="text-lg mb-6">你已經達到最高等級!</p>
<button id="restart-game" class="bg-green-600 text-white px-6 py-3 rounded-lg text-lg font-bold hover:bg-green-700 transition">再玩一次</button>
</div>
</div>
<!-- 等級提升模態框 -->
<div id="level-up-modal" class="modal">
<div class="modal-content bg-white w-11/12 max-w-md mx-auto mt-20 p-6 rounded-lg shadow-xl text-center">
<h2 class="text-3xl font-bold mb-4">等級提升!</h2>
<p class="text-xl mb-6">恭喜!你已經升到 <span id="new-level" class="font-bold text-green-600">2</span> 級</p>
<button id="continue-game" class="bg-green-600 text-white px-6 py-3 rounded-lg text-lg font-bold hover:bg-green-700 transition">繼續遊戲</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 遊戲狀態
const gameState = {
score: 0,
correct: 0,
wrong: 0,
level: 1,
maxLevel: 5,
itemsPerLevel: 5,
itemsProcessed: 0,
currentItems: []
};
// 垃圾物品數據
const wasteItems = [
{ id: 'newspaper', name: '報紙', type: 'paper', emoji: '📰' },
{ id: 'cardboard', name: '紙箱', type: 'paper', emoji: '📦' },
{ id: 'document', name: '文件', type: 'paper', emoji: '📄' },
{ id: 'plastic-bottle', name: '寶特瓶', type: 'plastic', emoji: '🍶' },
{ id: 'plastic-bag', name: '塑膠袋', type: 'plastic', emoji: '🛍️' },
{ id: 'yogurt-cup', name: '優格杯', type: 'plastic', emoji: '🥛' },
{ id: 'soda-can', name: '鋁罐', type: 'metal', emoji: '🥫' },
{ id: 'tin-can', name: '鐵罐', type: 'metal', emoji: '🥫' },
{ id: 'bottle-cap', name: '瓶蓋', type: 'metal', emoji: '⚪' },
{ id: 'glass-bottle', name: '玻璃瓶', type: 'glass', emoji: '🍾' },
{ id: 'glass-jar', name: '玻璃罐', type: 'glass', emoji: '🏺' },
{ id: 'food-waste', name: '食物殘渣', type: 'general', emoji: '🍎' },
{ id: 'tissue', name: '衛生紙', type: 'general', emoji: '🧻' },
{ id: 'gum', name: '口香糖', type: 'general', emoji: '🍬' }
];
// DOM 元素
const scoreElement = document.getElementById('score');
const correctElement = document.getElementById('correct');
const wrongElement = document.getElementById('wrong');
const levelElement = document.getElementById('level');
const progressBar = document.getElementById('progress-bar');
const wasteContainer = document.getElementById('waste-container');
const gameOverModal = document.getElementById('game-over-modal');
const finalScoreElement = document.getElementById('final-score');
const restartButton = document.getElementById('restart-game');
const levelUpModal = document.getElementById('level-up-modal');
const newLevelElement = document.getElementById('new-level');
const continueButton = document.getElementById('continue-game');
const devButton = document.getElementById('dev-button');
const devModal = document.getElementById('dev-modal');
const closeModalButton = document.getElementById('close-modal');
const cityCodeElement = document.getElementById('city-code');
const copyCodeButton = document.getElementById('copy-code');
// 初始化遊戲
initGame();
// 初始化遊戲
function initGame() {
resetGameState();
updateUI();
generateWasteItems();
setupEventListeners();
}
// 重置遊戲狀態
function resetGameState() {
gameState.score = 0;
gameState.correct = 0;
gameState.wrong = 0;
gameState.level = 1;
gameState.itemsProcessed = 0;
gameState.currentItems = [];
}
// 更新 UI
function updateUI() {
scoreElement.textContent = gameState.score;
correctElement.textContent = gameState.correct;
wrongElement.textContent = gameState.wrong;
levelElement.textContent = gameState.level;
const progress = (gameState.itemsProcessed % gameState.itemsPerLevel) / gameState.itemsPerLevel * 100;
progressBar.style.width = `${progress}%`;
}
// 生成垃圾物品
function generateWasteItems() {
wasteContainer.innerHTML = '';
gameState.currentItems = [];
// 根據等級增加難度
const itemCount = Math.min(3 + gameState.level, 8);
// 隨機選擇垃圾物品
const selectedItems = [];
const availableItems = [...wasteItems];
for (let i = 0; i < itemCount; i++) {
if (availableItems.length === 0) break;
const randomIndex = Math.floor(Math.random() * availableItems.length);
const item = availableItems.splice(randomIndex, 1)[0];
selectedItems.push(item);
}
// 創建垃圾物品元素
selectedItems.forEach((item, index) => {
const itemElement = document.createElement('div');
itemElement.id = `item-${item.id}-${index}`;
itemElement.className = 'waste-item draggable bg-white p-3 rounded-lg shadow-md flex flex-col items-center justify-center';
itemElement.style.width = '80px';
itemElement.style.height = '80px';
itemElement.style.left = `${50 + Math.random() * (window.innerWidth - 200)}px`;
itemElement.style.top = `${100 + Math.random() * 150}px`;
itemElement.dataset.type = item.type;
itemElement.innerHTML = `
<div class="text-4xl mb-1">${item.emoji}</div>
<div class="text-xs text-center">${item.name}</div>
`;
wasteContainer.appendChild(itemElement);
gameState.currentItems.push(itemElement);
// 設置拖拽事件
setupDraggable(itemElement);
});
}
// 設置拖拽功能
function setupDraggable(element) {
let isDragging = false;
let offsetX, offsetY;
element.addEventListener('mousedown', startDrag);
element.addEventListener('touchstart', startDrag, { passive: false });
function startDrag(e) {
e.preventDefault();
isDragging = true;
if (e.type === 'mousedown') {
offsetX = e.clientX - element.getBoundingClientRect().left;
offsetY = e.clientY - element.getBoundingClientRect().top;
} else {
offsetX = e.touches[0].clientX - element.getBoundingClientRect().left;
offsetY = e.touches[0].clientY - element.getBoundingClientRect().top;
}
element.style.zIndex = '10';
document.addEventListener('mousemove', drag);
document.addEventListener('touchmove', drag, { passive: false });
document.addEventListener('mouseup', endDrag);
document.addEventListener('touchend', endDrag);
}
function drag(e) {
if (!isDragging) return;
e.preventDefault();
let clientX, clientY;
if (e.type === 'mousemove') {
clientX = e.clientX;
clientY = e.clientY;
} else {
clientX = e.touches[0].clientX;
clientY = e.touches[0].clientY;
}
element.style.left = `${clientX - offsetX}px`;
element.style.top = `${clientY - offsetY}px`;
// 檢查是否在回收箱上方
checkBinHighlight(clientX, clientY);
}
function endDrag(e) {
if (!isDragging) return;
isDragging = false;
element.style.zIndex = '1';
// 移除事件監聽器
document.removeEventListener('mousemove', drag);
document.removeEventListener('touchmove', drag);
document.removeEventListener('mouseup', endDrag);
document.removeEventListener('touchend', endDrag);
// 檢查是否放入正確的回收箱
let clientX, clientY;
if (e.type === 'mouseup') {
clientX = e.clientX;
clientY = e.clientY;
} else {
// 對於 touchend,我們需要使用最後一個已知的位置
const rect = element.getBoundingClientRect();
clientX = rect.left + rect.width / 2;
clientY = rect.top + rect.height / 2;
}
checkBinDrop(clientX, clientY, element);
// 移除所有回收箱的高亮
document.querySelectorAll('.bin').forEach(bin => {
bin.classList.remove('highlight');
});
}
}
// 檢查是否在回收箱上方
function checkBinHighlight(x, y) {
document.querySelectorAll('.bin').forEach(bin => {
const rect = bin.getBoundingClientRect();
if (
x >= rect.left &&
x <= rect.right &&
y >= rect.top &&
y <= rect.bottom
) {
bin.classList.add('highlight');
} else {
bin.classList.remove('highlight');
}
});
}
// 檢查是否放入正確的回收箱
function checkBinDrop(x, y, element) {
const itemType = element.dataset.type;
let isCorrect = false;
let binFound = false;
document.querySelectorAll('.bin').forEach(bin => {
const rect = bin.getBoundingClientRect();
if (
x >= rect.left &&
x <= rect.right &&
y >= rect.top &&
y <= rect.bottom
) {
binFound = true;
const binType = bin.id.replace('bin-', '');
if (binType === itemType) {
isCorrect = true;
gameState.score += 10 * gameState.level;
gameState.correct++;
createConfetti(x, y);
} else {
gameState.score = Math.max(0, gameState.score - 5);
gameState.wrong++;
}
// 移除垃圾物品
element.style.transition = 'all 0.3s';
element.style.opacity = '0';
element.style.transform = 'scale(0.5)';
setTimeout(() => {
if (element.parentNode) {
element.parentNode.removeChild(element);
}
// 更新遊戲狀態
gameState.itemsProcessed++;
updateUI();
// 檢查是否需要生成新的垃圾物品
checkGameProgress();
}, 300);
}
});
// 如果沒有放入任何回收箱,將物品彈回原位
if (!binFound) {
element.style.transition = 'all 0.3s';
element.style.left = `${50 + Math.random() * (window.innerWidth - 200)}px`;
element.style.top = `${100 + Math.random() * 150}px`;
setTimeout(() => {
element.style.transition = '';
}, 300);
}
}
// 檢查遊戲進度
function checkGameProgress() {
// 檢查是否所有物品都已處理
if (gameState.currentItems.every(item => !item.parentNode)) {
// 生成新的垃圾物品
generateWasteItems();
}
// 檢查是否升級
if (gameState.itemsProcessed >= gameState.itemsPerLevel * gameState.level) {
if (gameState.level < gameState.maxLevel) {
levelUp();
} else {
gameOver();
}
}
}
// 升級
function levelUp() {
gameState.level++;
newLevelElement.textContent = gameState.level;
levelUpModal.style.display = 'block';
createConfetti(window.innerWidth / 2, window.innerHeight / 2, 50);
}
// 遊戲結束
function gameOver() {
finalScoreElement.textContent = gameState.score;
gameOverModal.style.display = 'block';
createConfetti(window.innerWidth / 2, window.innerHeight / 2, 100);
}
// 創建五彩紙屑效果
function createConfetti(x, y, count = 20) {
const colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff', '#00ffff'];
for (let i = 0; i < count; i++) {
const confetti = document.createElement('div');
confetti.className = 'confetti';
confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
confetti.style.left = `${x + (Math.random() * 100 - 50)}px`;
confetti.style.top = `${y}px`;
confetti.style.animationDuration = `${Math.random() * 2 + 1}s`;
document.body.appendChild(confetti);
// 動畫結束後移除元素
setTimeout(() => {
if (confetti.parentNode) {
confetti.parentNode.removeChild(confetti);
}
}, 3000);
}
}
// 設置事件監聽器
function setupEventListeners() {
// 繼續遊戲按鈕
continueButton.addEventListener('click', function() {
levelUpModal.style.display = 'none';
generateWasteItems();
});
// 重新開始遊戲按鈕
restartButton.addEventListener('click', function() {
gameOverModal.style.display = 'none';
initGame();
});
// 開發人員按鈕
devButton.addEventListener('click', function() {
// 獲取完整的 HTML 代碼
const fullCode = document.documentElement.outerHTML;
cityCodeElement.textContent = fullCode;
devModal.style.display = 'block';
});
// 關閉模態框按鈕
closeModalButton.addEventListener('click', function() {
devModal.style.display = 'none';
});
// 複製代碼按鈕
copyCodeButton.addEventListener('click', function() {
const codeText = cityCodeElement.textContent;
// 創建一個臨時的 textarea 元素來複製文本
const textarea = document.createElement('textarea');
textarea.value = codeText;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
// 顯示複製成功提示
copyCodeButton.textContent = '複製成功!';
setTimeout(() => {
copyCodeButton.textContent = '複製代碼';
}, 2000);
});
// 點擊模態框背景關閉模態框
window.addEventListener('click', function(e) {
if (e.target === devModal) {
devModal.style.display = 'none';
}
if (e.target === levelUpModal) {
levelUpModal.style.display = 'none';
generateWasteItems();
}
if (e.target === gameOverModal) {
gameOverModal.style.display = 'none';
initGame();
}
});
}
});
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'943b01f675b1f255',t:'MTc0NzkwMzIxNS4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script><iframe height="1" width="1" style="position: absolute; top: 0px; left: 0px; border: none; visibility: hidden;"></iframe>
</body></html>
最終分數: 0
你已經達到最高等級!
恭喜!你已經升到 2 級