選擇配料,拖放到披薩上,製作你的完美披薩!
<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: linear-gradient(135deg, #ffe8cc 0%, #ffb380 100%);
min-height: 100vh;
overflow-x: hidden;
}
.topping {
cursor: pointer;
transition: all 0.2s;
}
.topping:hover {
transform: scale(1.1);
}
.pizza-topping {
position: absolute;
transition: all 0.2s;
z-index: 10;
}
.pizza-base {
position: relative;
width: 400px;
height: 400px;
margin: 0 auto;
}
.sauce-layer {
position: absolute;
top: 10px;
left: 10px;
width: 380px;
height: 380px;
border-radius: 50%;
}
.cheese-layer {
position: absolute;
top: 15px;
left: 15px;
width: 370px;
height: 370px;
border-radius: 50%;
}
.code-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.code-modal.active {
opacity: 1;
pointer-events: auto;
}
.code-container {
width: 80%;
height: 80%;
background-color: #fff;
border-radius: 10px;
padding: 20px;
overflow-y: auto;
position: relative;
}
pre {
white-space: pre-wrap;
font-family: monospace;
font-size: 14px;
line-height: 1.5;
padding: 15px;
background-color: #f5f5f5;
border-radius: 5px;
overflow-x: auto;
}
.close-btn {
position: absolute;
top: 10px;
right: 10px;
font-size: 24px;
cursor: pointer;
color: #333;
}
.copy-btn {
position: absolute;
top: 10px;
right: 50px;
padding: 5px 15px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
.copy-btn:hover {
background-color: #45a049;
}
.dev-btn {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 100;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.bounce {
animation: bounce 0.5s;
}
</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}.relative{position:relative}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:0.25rem}.mb-2{margin-bottom:0.5rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mt-4{margin-top:1rem}.flex{display:flex}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-16{height:4rem}.h-3{height:0.75rem}.h-8{height:2rem}.h-full{height:100%}.w-10{width:2.5rem}.w-12{width:3rem}.w-16{width:4rem}.w-8{width:2rem}.w-full{width:100%}.max-w-6xl{max-width:72rem}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:0.5rem}.gap-6{gap:1.5rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:0.5rem}.rounded-sm{border-radius:0.125rem}.rounded-xl{border-radius:0.75rem}.bg-gray-300{--tw-bg-opacity:1;background-color:rgb(209 213 219 / 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-orange-100{--tw-bg-opacity:1;background-color:rgb(255 237 213 / var(--tw-bg-opacity, 1))}.bg-orange-50{--tw-bg-opacity:1;background-color:rgb(255 247 237 / var(--tw-bg-opacity, 1))}.bg-pink-300{--tw-bg-opacity:1;background-color:rgb(249 168 212 / var(--tw-bg-opacity, 1))}.bg-pink-700{--tw-bg-opacity:1;background-color:rgb(190 24 93 / 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-300{--tw-bg-opacity:1;background-color:rgb(253 224 71 / var(--tw-bg-opacity, 1))}.bg-yellow-400{--tw-bg-opacity:1;background-color:rgb(250 204 21 / var(--tw-bg-opacity, 1))}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-2{padding-top:0.5rem;padding-bottom:0.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-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:0.75rem;line-height:1rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-orange-600{--tw-text-opacity:1;color:rgb(234 88 12 / var(--tw-text-opacity, 1))}.text-orange-700{--tw-text-opacity:1;color:rgb(194 65 12 / var(--tw-text-opacity, 1))}.text-orange-800{--tw-text-opacity:1;color:rgb(154 52 18 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255 / 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)}.transition-colors{transition-property:color, background-color, border-color, fill, stroke, -webkit-text-decoration-color;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke, -webkit-text-decoration-color;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms}.hover\:bg-gray-900:hover{--tw-bg-opacity:1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.hover\:bg-red-600:hover{--tw-bg-opacity:1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}@media (min-width: 768px){.md\:w-1\/2{width:50%}.md\:flex-row{flex-direction:row}}</style></head>
<body class="p-4">
<div class="max-w-6xl mx-auto">
<div class="bg-white rounded-xl shadow-lg p-6 mb-6">
<h1 class="text-3xl font-bold text-center text-orange-600 mb-2">互動式披薩製作遊戲</h1>
<p class="text-center text-gray-600 mb-6">選擇配料,拖放到披薩上,製作你的完美披薩!</p>
<div class="flex flex-col md:flex-row gap-6">
<!-- 左側:披薩製作區 -->
<div class="w-full md:w-1/2 bg-orange-50 rounded-lg p-4 flex flex-col items-center">
<button id="reset-btn" class="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded-lg transition-colors mb-4">
重新開始
</button>
<div id="pizza-container" class="pizza-base relative">
<!-- 披薩底座 -->
<svg viewBox="0 0 400 400" class="w-full h-full">
<circle cx="200" cy="200" r="190" fill="#e2b280" stroke="#c28d4b" stroke-width="10"></circle>
<circle cx="200" cy="200" r="175" fill="#f2d3a9" stroke-width="0"></circle>
</svg>
<!-- 醬料層 -->
<div id="sauce-layer" class="sauce-layer" style="background-color: #b91c1c;"></div>
<!-- 起司層 -->
<div id="cheese-layer" class="cheese-layer hidden" style="background-color: #fbbf24;"></div>
<div class="pizza-topping" data-type="pepperoni" style="width: 30px; height: 30px; border-radius: 50%; background-color: rgb(197, 48, 48); left: 184.844px; top: 287.875px; z-index: 10;"></div><div class="pizza-topping" data-type="ham" style="width: 40px; height: 30px; background-color: rgb(237, 135, 150); left: 98.6415px; top: 99.9718px;"></div><div class="pizza-topping" data-type="bacon" style="width: 50px; height: 10px; background-color: rgb(192, 80, 80); left: 258.568px; top: 211.151px;"></div><div class="pizza-topping" data-type="mushroom" style="left: 237.666px; top: 58.2504px;">
<div style="width: 25px; height: 15px; background-color: #d1d5db; border-radius: 50% 50% 0 0;"></div>
<div style="width: 10px; height: 12.5px; background-color: #a1a1aa; margin: 0 auto;"></div>
</div><div class="pizza-topping" data-type="olive" style="width: 15px; height: 15px; border-radius: 50%; background-color: rgb(31, 41, 55); left: 241.943px; top: 117.357px;"></div><div class="pizza-topping" data-type="pepper" style="left: 257.5px; top: 280.531px; z-index: 10;">
<div style="width: 30px; height: 30px; background-color: #10b981; border-radius: 0 50% 50% 50%; transform: rotate(45deg);"></div>
</div><div class="pizza-topping" data-type="pineapple" style="left: 275.116px; top: 143.587px;">
<div style="width: 25px; height: 25px; background-color: #fcd34d; clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);"></div>
</div><div class="pizza-topping" data-type="pepperoni" style="width: 30px; height: 30px; border-radius: 50%; background-color: rgb(197, 48, 48); left: 150.761px; top: 175.027px;"></div><div class="pizza-topping" data-type="ham" style="width: 40px; height: 30px; background-color: rgb(237, 135, 150); left: 128.547px; top: 246.188px; z-index: 10;"></div></div>
<div id="message" class="mt-4 text-xl font-bold text-center text-green-600 hidden">已添加火腿!</div>
</div>
<!-- 右側:配料選擇區 -->
<div class="w-full md:w-1/2 bg-orange-100 rounded-lg p-4">
<h2 class="text-xl font-bold text-orange-800 mb-4">選擇配料</h2>
<div class="mb-4">
<h3 class="font-semibold text-orange-700 mb-2">基本層</h3>
<div class="flex flex-wrap gap-2">
<div class="topping bg-red-600 w-16 h-16 rounded-full flex items-center justify-center text-white font-bold" data-type="sauce">
醬料
</div>
<div class="topping bg-yellow-400 w-16 h-16 rounded-full flex items-center justify-center text-white font-bold" data-type="cheese">
起司
</div>
</div>
</div>
<div class="mb-4">
<h3 class="font-semibold text-orange-700 mb-2">肉類</h3>
<div class="flex flex-wrap gap-2">
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="pepperoni">
<div class="w-12 h-12 bg-red-500 rounded-full flex items-center justify-center">
<span class="text-xs text-white">臘腸</span>
</div>
</div>
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="ham">
<div class="w-12 h-12 bg-pink-300 rounded-sm flex items-center justify-center">
<span class="text-xs text-white">火腿</span>
</div>
</div>
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="bacon">
<div class="w-12 h-3 bg-pink-700 rounded-sm mb-1"></div>
<div class="w-12 h-3 bg-pink-700 rounded-sm">培根</div>
</div>
</div>
</div>
<div class="mb-4">
<h3 class="font-semibold text-orange-700 mb-2">蔬菜</h3>
<div class="flex flex-wrap gap-2">
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="mushroom">
<div class="w-10 h-10 bg-gray-300 rounded-full flex items-center justify-center">
<span class="text-xs">蘑菇</span>
</div>
</div>
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="olive">
<div class="w-8 h-8 bg-gray-800 rounded-full flex items-center justify-center">
<span class="text-xs text-white">橄欖</span>
</div>
</div>
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="pepper">
<div class="w-10 h-10 bg-green-500 rounded-lg flex items-center justify-center">
<span class="text-xs text-white">青椒</span>
</div>
</div>
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="pineapple">
<div class="w-10 h-10 bg-yellow-300 rounded-lg flex items-center justify-center">
<span class="text-xs">鳳梨</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 開發人員按鈕 -->
<button id="dev-button" class="dev-btn bg-gray-800 hover:bg-gray-900 text-white font-bold py-2 px-4 rounded-lg shadow-lg transition-colors">
開發人員
</button>
<!-- 程式碼顯示模態框 -->
<div id="code-modal" class="code-modal active">
<div class="code-container">
<button id="copy-btn" class="copy-btn">複製代碼</button>
<span id="close-modal" class="close-btn">×</span>
<h2 class="text-2xl font-bold mb-4">互動式披薩製作遊戲 - 完整程式碼</h2>
<pre id="code-display"><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: linear-gradient(135deg, #ffe8cc 0%, #ffb380 100%);
min-height: 100vh;
overflow-x: hidden;
}
.topping {
cursor: pointer;
transition: all 0.2s;
}
.topping:hover {
transform: scale(1.1);
}
.pizza-topping {
position: absolute;
transition: all 0.2s;
z-index: 10;
}
.pizza-base {
position: relative;
width: 400px;
height: 400px;
margin: 0 auto;
}
.sauce-layer {
position: absolute;
top: 10px;
left: 10px;
width: 380px;
height: 380px;
border-radius: 50%;
}
.cheese-layer {
position: absolute;
top: 15px;
left: 15px;
width: 370px;
height: 370px;
border-radius: 50%;
}
.code-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.code-modal.active {
opacity: 1;
pointer-events: auto;
}
.code-container {
width: 80%;
height: 80%;
background-color: #fff;
border-radius: 10px;
padding: 20px;
overflow-y: auto;
position: relative;
}
pre {
white-space: pre-wrap;
font-family: monospace;
font-size: 14px;
line-height: 1.5;
padding: 15px;
background-color: #f5f5f5;
border-radius: 5px;
overflow-x: auto;
}
.close-btn {
position: absolute;
top: 10px;
right: 10px;
font-size: 24px;
cursor: pointer;
color: #333;
}
.copy-btn {
position: absolute;
top: 10px;
right: 50px;
padding: 5px 15px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
.copy-btn:hover {
background-color: #45a049;
}
.dev-btn {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 100;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.bounce {
animation: bounce 0.5s;
}
</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}.relative{position:relative}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:0.25rem}.mb-2{margin-bottom:0.5rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mt-4{margin-top:1rem}.flex{display:flex}.hidden{display:none}.h-10{height:2.5rem}.h-12{height:3rem}.h-16{height:4rem}.h-3{height:0.75rem}.h-8{height:2rem}.h-full{height:100%}.w-10{width:2.5rem}.w-12{width:3rem}.w-16{width:4rem}.w-8{width:2rem}.w-full{width:100%}.max-w-6xl{max-width:72rem}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:0.5rem}.gap-6{gap:1.5rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:0.5rem}.rounded-sm{border-radius:0.125rem}.rounded-xl{border-radius:0.75rem}.bg-gray-300{--tw-bg-opacity:1;background-color:rgb(209 213 219 / 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-orange-100{--tw-bg-opacity:1;background-color:rgb(255 237 213 / var(--tw-bg-opacity, 1))}.bg-orange-50{--tw-bg-opacity:1;background-color:rgb(255 247 237 / var(--tw-bg-opacity, 1))}.bg-pink-300{--tw-bg-opacity:1;background-color:rgb(249 168 212 / var(--tw-bg-opacity, 1))}.bg-pink-700{--tw-bg-opacity:1;background-color:rgb(190 24 93 / 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-300{--tw-bg-opacity:1;background-color:rgb(253 224 71 / var(--tw-bg-opacity, 1))}.bg-yellow-400{--tw-bg-opacity:1;background-color:rgb(250 204 21 / var(--tw-bg-opacity, 1))}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-2{padding-top:0.5rem;padding-bottom:0.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-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:0.75rem;line-height:1rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-orange-600{--tw-text-opacity:1;color:rgb(234 88 12 / var(--tw-text-opacity, 1))}.text-orange-700{--tw-text-opacity:1;color:rgb(194 65 12 / var(--tw-text-opacity, 1))}.text-orange-800{--tw-text-opacity:1;color:rgb(154 52 18 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255 / 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)}.transition-colors{transition-property:color, background-color, border-color, fill, stroke, -webkit-text-decoration-color;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke, -webkit-text-decoration-color;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms}.hover\:bg-gray-900:hover{--tw-bg-opacity:1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.hover\:bg-red-600:hover{--tw-bg-opacity:1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}@media (min-width: 768px){.md\:w-1\/2{width:50%}.md\:flex-row{flex-direction:row}}</style></head>
<body class="p-4">
<div class="max-w-6xl mx-auto">
<div class="bg-white rounded-xl shadow-lg p-6 mb-6">
<h1 class="text-3xl font-bold text-center text-orange-600 mb-2">互動式披薩製作遊戲</h1>
<p class="text-center text-gray-600 mb-6">選擇配料,拖放到披薩上,製作你的完美披薩!</p>
<div class="flex flex-col md:flex-row gap-6">
<!-- 左側:披薩製作區 -->
<div class="w-full md:w-1/2 bg-orange-50 rounded-lg p-4 flex flex-col items-center">
<button id="reset-btn" class="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded-lg transition-colors mb-4">
重新開始
</button>
<div id="pizza-container" class="pizza-base relative">
<!-- 披薩底座 -->
<svg viewBox="0 0 400 400" class="w-full h-full">
<circle cx="200" cy="200" r="190" fill="#e2b280" stroke="#c28d4b" stroke-width="10"></circle>
<circle cx="200" cy="200" r="175" fill="#f2d3a9" stroke-width="0"></circle>
</svg>
<!-- 醬料層 -->
<div id="sauce-layer" class="sauce-layer hidden" style="background-color: #b91c1c;"></div>
<!-- 起司層 -->
<div id="cheese-layer" class="cheese-layer hidden" style="background-color: #fbbf24;"></div>
</div>
<div id="message" class="mt-4 text-xl font-bold text-center text-green-600 hidden"></div>
</div>
<!-- 右側:配料選擇區 -->
<div class="w-full md:w-1/2 bg-orange-100 rounded-lg p-4">
<h2 class="text-xl font-bold text-orange-800 mb-4">選擇配料</h2>
<div class="mb-4">
<h3 class="font-semibold text-orange-700 mb-2">基本層</h3>
<div class="flex flex-wrap gap-2">
<div class="topping bg-red-600 w-16 h-16 rounded-full flex items-center justify-center text-white font-bold" data-type="sauce">
醬料
</div>
<div class="topping bg-yellow-400 w-16 h-16 rounded-full flex items-center justify-center text-white font-bold" data-type="cheese">
起司
</div>
</div>
</div>
<div class="mb-4">
<h3 class="font-semibold text-orange-700 mb-2">肉類</h3>
<div class="flex flex-wrap gap-2">
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="pepperoni">
<div class="w-12 h-12 bg-red-500 rounded-full flex items-center justify-center">
<span class="text-xs text-white">臘腸</span>
</div>
</div>
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="ham">
<div class="w-12 h-12 bg-pink-300 rounded-sm flex items-center justify-center">
<span class="text-xs text-white">火腿</span>
</div>
</div>
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="bacon">
<div class="w-12 h-3 bg-pink-700 rounded-sm mb-1"></div>
<div class="w-12 h-3 bg-pink-700 rounded-sm">培根</div>
</div>
</div>
</div>
<div class="mb-4">
<h3 class="font-semibold text-orange-700 mb-2">蔬菜</h3>
<div class="flex flex-wrap gap-2">
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="mushroom">
<div class="w-10 h-10 bg-gray-300 rounded-full flex items-center justify-center">
<span class="text-xs">蘑菇</span>
</div>
</div>
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="olive">
<div class="w-8 h-8 bg-gray-800 rounded-full flex items-center justify-center">
<span class="text-xs text-white">橄欖</span>
</div>
</div>
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="pepper">
<div class="w-10 h-10 bg-green-500 rounded-lg flex items-center justify-center">
<span class="text-xs text-white">青椒</span>
</div>
</div>
<div class="topping bg-white w-16 h-16 rounded-lg flex items-center justify-center shadow-md" data-type="pineapple">
<div class="w-10 h-10 bg-yellow-300 rounded-lg flex items-center justify-center">
<span class="text-xs">鳳梨</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 開發人員按鈕 -->
<button id="dev-button" class="dev-btn bg-gray-800 hover:bg-gray-900 text-white font-bold py-2 px-4 rounded-lg shadow-lg transition-colors">
開發人員
</button>
<!-- 程式碼顯示模態框 -->
<div id="code-modal" class="code-modal">
<div class="code-container">
<button id="copy-btn" class="copy-btn">複製代碼</button>
<span id="close-modal" class="close-btn">×</span>
<h2 class="text-2xl font-bold mb-4">互動式披薩製作遊戲 - 完整程式碼</h2>
<pre id="code-display"></pre>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 獲取DOM元素
const pizzaContainer = document.getElementById('pizza-container');
const sauceLayer = document.getElementById('sauce-layer');
const cheeseLayer = document.getElementById('cheese-layer');
const resetBtn = document.getElementById('reset-btn');
const message = document.getElementById('message');
const devButton = document.getElementById('dev-button');
const codeModal = document.getElementById('code-modal');
const closeModal = document.getElementById('close-modal');
const copyBtn = document.getElementById('copy-btn');
const codeDisplay = document.getElementById('code-display');
// 狀態變數
let toppings = [];
let hasSauce = false;
let hasCheese = false;
let isDragging = false;
let currentTopping = null;
let offsetX, offsetY;
// 配料數據
const toppingData = {
pepperoni: {
color: '#c53030',
shape: 'circle',
size: 30,
name: '臘腸'
},
ham: {
color: '#ed8796',
shape: 'rect',
width: 40,
height: 30,
name: '火腿'
},
bacon: {
color: '#c05050',
shape: 'rect',
width: 50,
height: 10,
name: '培根'
},
mushroom: {
color: '#d1d5db',
shape: 'mushroom',
size: 25,
name: '蘑菇'
},
olive: {
color: '#1f2937',
shape: 'circle',
size: 15,
name: '橄欖'
},
pepper: {
color: '#10b981',
shape: 'pepper',
size: 30,
name: '青椒'
},
pineapple: {
color: '#fcd34d',
shape: 'pineapple',
size: 25,
name: '鳳梨'
}
};
// 初始化
function init() {
// 添加配料點擊事件
document.querySelectorAll('.topping').forEach(topping => {
topping.addEventListener('click', handleToppingClick);
});
// 重置按鈕
resetBtn.addEventListener('click', resetPizza);
// 開發人員按鈕
devButton.addEventListener('click', showCode);
// 關閉模態框
closeModal.addEventListener('click', hideCode);
// 複製代碼
copyBtn.addEventListener('click', copyCode);
// 點擊模態框外部關閉
window.addEventListener('click', (e) => {
if (e.target === codeModal) {
hideCode();
}
});
// 設置代碼顯示
codeDisplay.textContent = document.documentElement.outerHTML;
// 添加披薩容器事件
pizzaContainer.addEventListener('mousedown', startDragging);
pizzaContainer.addEventListener('mousemove', dragTopping);
pizzaContainer.addEventListener('mouseup', stopDragging);
pizzaContainer.addEventListener('mouseleave', stopDragging);
// 觸摸事件支持
pizzaContainer.addEventListener('touchstart', handleTouchStart, { passive: false });
pizzaContainer.addEventListener('touchmove', handleTouchMove, { passive: false });
pizzaContainer.addEventListener('touchend', handleTouchEnd);
}
// 處理配料點擊
function handleToppingClick(e) {
const type = e.currentTarget.dataset.type;
if (type === 'sauce') {
toggleSauce();
} else if (type === 'cheese') {
toggleCheese();
} else {
addTopping(type);
}
}
// 切換醬料
function toggleSauce() {
hasSauce = !hasSauce;
sauceLayer.classList.toggle('hidden', !hasSauce);
if (hasSauce) {
showMessage('已添加醬料!');
} else {
showMessage('已移除醬料!');
}
}
// 切換起司
function toggleCheese() {
hasCheese = !hasCheese;
cheeseLayer.classList.toggle('hidden', !hasCheese);
if (hasCheese) {
showMessage('已添加起司!');
} else {
showMessage('已移除起司!');
}
}
// 添加配料
function addTopping(type) {
const data = toppingData[type];
const topping = document.createElement('div');
topping.className = 'pizza-topping';
topping.dataset.type = type;
// 根據配料類型設置樣式
if (data.shape === 'circle') {
topping.style.width = `${data.size}px`;
topping.style.height = `${data.size}px`;
topping.style.borderRadius = '50%';
topping.style.backgroundColor = data.color;
} else if (data.shape === 'rect') {
topping.style.width = `${data.width}px`;
topping.style.height = `${data.height}px`;
topping.style.backgroundColor = data.color;
} else if (data.shape === 'mushroom') {
topping.innerHTML = `
<div style="width: ${data.size}px; height: ${data.size * 0.6}px; background-color: ${data.color}; border-radius: 50% 50% 0 0;"></div>
<div style="width: ${data.size * 0.4}px; height: ${data.size * 0.5}px; background-color: #a1a1aa; margin: 0 auto;"></div>
`;
} else if (data.shape === 'pepper') {
topping.innerHTML = `
<div style="width: ${data.size}px; height: ${data.size}px; background-color: ${data.color}; border-radius: 0 50% 50% 50%; transform: rotate(45deg);"></div>
`;
} else if (data.shape === 'pineapple') {
topping.innerHTML = `
<div style="width: ${data.size}px; height: ${data.size}px; background-color: ${data.color}; clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);"></div>
`;
}
// 隨機位置
const pizzaRect = pizzaContainer.getBoundingClientRect();
const centerX = pizzaRect.width / 2;
const centerY = pizzaRect.height / 2;
const radius = Math.min(centerX, centerY) * 0.7;
const angle = Math.random() * Math.PI * 2;
const distance = Math.random() * radius;
const x = centerX + Math.cos(angle) * distance - (data.size || data.width) / 2;
const y = centerY + Math.sin(angle) * distance - (data.size || data.height) / 2;
topping.style.left = `${x}px`;
topping.style.top = `${y}px`;
// 添加拖動事件
topping.addEventListener('mousedown', (e) => {
e.stopPropagation();
currentTopping = topping;
isDragging = true;
const rect = topping.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
topping.style.zIndex = 20;
});
// 添加觸摸事件
topping.addEventListener('touchstart', (e) => {
e.stopPropagation();
e.preventDefault();
currentTopping = topping;
isDragging = true;
const rect = topping.getBoundingClientRect();
const touch = e.touches[0];
offsetX = touch.clientX - rect.left;
offsetY = touch.clientY - rect.top;
topping.style.zIndex = 20;
}, { passive: false });
pizzaContainer.appendChild(topping);
toppings.push({ element: topping, type });
topping.classList.add('bounce');
setTimeout(() => {
topping.classList.remove('bounce');
}, 500);
showMessage(`已添加${data.name}!`);
}
// 開始拖動
function startDragging(e) {
if (e.target === pizzaContainer || e.target.tagName === 'svg' || e.target.tagName === 'circle') {
return;
}
let target = e.target;
while (target && !target.classList.contains('pizza-topping')) {
target = target.parentElement;
}
if (!target) return;
e.preventDefault();
currentTopping = target;
isDragging = true;
const rect = target.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
target.style.zIndex = 20;
}
// 拖動配料
function dragTopping(e) {
if (!isDragging || !currentTopping) return;
e.preventDefault();
const pizzaRect = pizzaContainer.getBoundingClientRect();
const x = e.clientX - pizzaRect.left - offsetX;
const y = e.clientY - pizzaRect.top - offsetY;
// 限制在披薩範圍內
const toppingRect = currentTopping.getBoundingClientRect();
const toppingWidth = toppingRect.width;
const toppingHeight = toppingRect.height;
const maxX = pizzaRect.width - toppingWidth;
const maxY = pizzaRect.height - toppingHeight;
const boundedX = Math.max(0, Math.min(x, maxX));
const boundedY = Math.max(0, Math.min(y, maxY));
currentTopping.style.left = `${boundedX}px`;
currentTopping.style.top = `${boundedY}px`;
}
// 停止拖動
function stopDragging() {
if (currentTopping) {
currentTopping.style.zIndex = 10;
}
isDragging = false;
currentTopping = null;
}
// 處理觸摸開始
function handleTouchStart(e) {
if (e.target === pizzaContainer || e.target.tagName === 'svg' || e.target.tagName === 'circle') {
return;
}
let target = e.target;
while (target && !target.classList.contains('pizza-topping')) {
target = target.parentElement;
}
if (!target) return;
e.preventDefault();
currentTopping = target;
isDragging = true;
const touch = e.touches[0];
const rect = target.getBoundingClientRect();
offsetX = touch.clientX - rect.left;
offsetY = touch.clientY - rect.top;
target.style.zIndex = 20;
}
// 處理觸摸移動
function handleTouchMove(e) {
if (!isDragging || !currentTopping) return;
e.preventDefault();
const touch = e.touches[0];
const pizzaRect = pizzaContainer.getBoundingClientRect();
const x = touch.clientX - pizzaRect.left - offsetX;
const y = touch.clientY - pizzaRect.top - offsetY;
// 限制在披薩範圍內
const toppingRect = currentTopping.getBoundingClientRect();
const toppingWidth = toppingRect.width;
const toppingHeight = toppingRect.height;
const maxX = pizzaRect.width - toppingWidth;
const maxY = pizzaRect.height - toppingHeight;
const boundedX = Math.max(0, Math.min(x, maxX));
const boundedY = Math.max(0, Math.min(y, maxY));
currentTopping.style.left = `${boundedX}px`;
currentTopping.style.top = `${boundedY}px`;
}
// 處理觸摸結束
function handleTouchEnd() {
if (currentTopping) {
currentTopping.style.zIndex = 10;
}
isDragging = false;
currentTopping = null;
}
// 重置披薩
function resetPizza() {
hasSauce = false;
hasCheese = false;
sauceLayer.classList.add('hidden');
cheeseLayer.classList.add('hidden');
toppings.forEach(topping => {
topping.element.remove();
});
toppings = [];
showMessage('披薩已重置!');
}
// 顯示訊息
function showMessage(text) {
message.textContent = text;
message.classList.remove('hidden');
setTimeout(() => {
message.classList.add('hidden');
}, 2000);
}
// 顯示代碼
function showCode() {
codeModal.classList.add('active');
codeDisplay.textContent = document.documentElement.outerHTML;
}
// 隱藏代碼
function hideCode() {
codeModal.classList.remove('active');
}
// 複製代碼
function copyCode() {
const code = codeDisplay.textContent;
navigator.clipboard.writeText(code).then(() => {
copyBtn.textContent = '已複製!';
setTimeout(() => {
copyBtn.textContent = '複製代碼';
}, 2000);
}).catch(err => {
console.error('無法複製代碼: ', err);
});
}
// 初始化
init();
});
</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:'947496add5f0f209',t:'MTc0ODUwNjk5NS4wMDAwMDA='};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></pre>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 獲取DOM元素
const pizzaContainer = document.getElementById('pizza-container');
const sauceLayer = document.getElementById('sauce-layer');
const cheeseLayer = document.getElementById('cheese-layer');
const resetBtn = document.getElementById('reset-btn');
const message = document.getElementById('message');
const devButton = document.getElementById('dev-button');
const codeModal = document.getElementById('code-modal');
const closeModal = document.getElementById('close-modal');
const copyBtn = document.getElementById('copy-btn');
const codeDisplay = document.getElementById('code-display');
// 狀態變數
let toppings = [];
let hasSauce = false;
let hasCheese = false;
let isDragging = false;
let currentTopping = null;
let offsetX, offsetY;
// 配料數據
const toppingData = {
pepperoni: {
color: '#c53030',
shape: 'circle',
size: 30,
name: '臘腸'
},
ham: {
color: '#ed8796',
shape: 'rect',
width: 40,
height: 30,
name: '火腿'
},
bacon: {
color: '#c05050',
shape: 'rect',
width: 50,
height: 10,
name: '培根'
},
mushroom: {
color: '#d1d5db',
shape: 'mushroom',
size: 25,
name: '蘑菇'
},
olive: {
color: '#1f2937',
shape: 'circle',
size: 15,
name: '橄欖'
},
pepper: {
color: '#10b981',
shape: 'pepper',
size: 30,
name: '青椒'
},
pineapple: {
color: '#fcd34d',
shape: 'pineapple',
size: 25,
name: '鳳梨'
}
};
// 初始化
function init() {
// 添加配料點擊事件
document.querySelectorAll('.topping').forEach(topping => {
topping.addEventListener('click', handleToppingClick);
});
// 重置按鈕
resetBtn.addEventListener('click', resetPizza);
// 開發人員按鈕
devButton.addEventListener('click', showCode);
// 關閉模態框
closeModal.addEventListener('click', hideCode);
// 複製代碼
copyBtn.addEventListener('click', copyCode);
// 點擊模態框外部關閉
window.addEventListener('click', (e) => {
if (e.target === codeModal) {
hideCode();
}
});
// 設置代碼顯示
codeDisplay.textContent = document.documentElement.outerHTML;
// 添加披薩容器事件
pizzaContainer.addEventListener('mousedown', startDragging);
pizzaContainer.addEventListener('mousemove', dragTopping);
pizzaContainer.addEventListener('mouseup', stopDragging);
pizzaContainer.addEventListener('mouseleave', stopDragging);
// 觸摸事件支持
pizzaContainer.addEventListener('touchstart', handleTouchStart, { passive: false });
pizzaContainer.addEventListener('touchmove', handleTouchMove, { passive: false });
pizzaContainer.addEventListener('touchend', handleTouchEnd);
}
// 處理配料點擊
function handleToppingClick(e) {
const type = e.currentTarget.dataset.type;
if (type === 'sauce') {
toggleSauce();
} else if (type === 'cheese') {
toggleCheese();
} else {
addTopping(type);
}
}
// 切換醬料
function toggleSauce() {
hasSauce = !hasSauce;
sauceLayer.classList.toggle('hidden', !hasSauce);
if (hasSauce) {
showMessage('已添加醬料!');
} else {
showMessage('已移除醬料!');
}
}
// 切換起司
function toggleCheese() {
hasCheese = !hasCheese;
cheeseLayer.classList.toggle('hidden', !hasCheese);
if (hasCheese) {
showMessage('已添加起司!');
} else {
showMessage('已移除起司!');
}
}
// 添加配料
function addTopping(type) {
const data = toppingData[type];
const topping = document.createElement('div');
topping.className = 'pizza-topping';
topping.dataset.type = type;
// 根據配料類型設置樣式
if (data.shape === 'circle') {
topping.style.width = `${data.size}px`;
topping.style.height = `${data.size}px`;
topping.style.borderRadius = '50%';
topping.style.backgroundColor = data.color;
} else if (data.shape === 'rect') {
topping.style.width = `${data.width}px`;
topping.style.height = `${data.height}px`;
topping.style.backgroundColor = data.color;
} else if (data.shape === 'mushroom') {
topping.innerHTML = `
<div style="width: ${data.size}px; height: ${data.size * 0.6}px; background-color: ${data.color}; border-radius: 50% 50% 0 0;"></div>
<div style="width: ${data.size * 0.4}px; height: ${data.size * 0.5}px; background-color: #a1a1aa; margin: 0 auto;"></div>
`;
} else if (data.shape === 'pepper') {
topping.innerHTML = `
<div style="width: ${data.size}px; height: ${data.size}px; background-color: ${data.color}; border-radius: 0 50% 50% 50%; transform: rotate(45deg);"></div>
`;
} else if (data.shape === 'pineapple') {
topping.innerHTML = `
<div style="width: ${data.size}px; height: ${data.size}px; background-color: ${data.color}; clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);"></div>
`;
}
// 隨機位置
const pizzaRect = pizzaContainer.getBoundingClientRect();
const centerX = pizzaRect.width / 2;
const centerY = pizzaRect.height / 2;
const radius = Math.min(centerX, centerY) * 0.7;
const angle = Math.random() * Math.PI * 2;
const distance = Math.random() * radius;
const x = centerX + Math.cos(angle) * distance - (data.size || data.width) / 2;
const y = centerY + Math.sin(angle) * distance - (data.size || data.height) / 2;
topping.style.left = `${x}px`;
topping.style.top = `${y}px`;
// 添加拖動事件
topping.addEventListener('mousedown', (e) => {
e.stopPropagation();
currentTopping = topping;
isDragging = true;
const rect = topping.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
topping.style.zIndex = 20;
});
// 添加觸摸事件
topping.addEventListener('touchstart', (e) => {
e.stopPropagation();
e.preventDefault();
currentTopping = topping;
isDragging = true;
const rect = topping.getBoundingClientRect();
const touch = e.touches[0];
offsetX = touch.clientX - rect.left;
offsetY = touch.clientY - rect.top;
topping.style.zIndex = 20;
}, { passive: false });
pizzaContainer.appendChild(topping);
toppings.push({ element: topping, type });
topping.classList.add('bounce');
setTimeout(() => {
topping.classList.remove('bounce');
}, 500);
showMessage(`已添加${data.name}!`);
}
// 開始拖動
function startDragging(e) {
if (e.target === pizzaContainer || e.target.tagName === 'svg' || e.target.tagName === 'circle') {
return;
}
let target = e.target;
while (target && !target.classList.contains('pizza-topping')) {
target = target.parentElement;
}
if (!target) return;
e.preventDefault();
currentTopping = target;
isDragging = true;
const rect = target.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
target.style.zIndex = 20;
}
// 拖動配料
function dragTopping(e) {
if (!isDragging || !currentTopping) return;
e.preventDefault();
const pizzaRect = pizzaContainer.getBoundingClientRect();
const x = e.clientX - pizzaRect.left - offsetX;
const y = e.clientY - pizzaRect.top - offsetY;
// 限制在披薩範圍內
const toppingRect = currentTopping.getBoundingClientRect();
const toppingWidth = toppingRect.width;
const toppingHeight = toppingRect.height;
const maxX = pizzaRect.width - toppingWidth;
const maxY = pizzaRect.height - toppingHeight;
const boundedX = Math.max(0, Math.min(x, maxX));
const boundedY = Math.max(0, Math.min(y, maxY));
currentTopping.style.left = `${boundedX}px`;
currentTopping.style.top = `${boundedY}px`;
}
// 停止拖動
function stopDragging() {
if (currentTopping) {
currentTopping.style.zIndex = 10;
}
isDragging = false;
currentTopping = null;
}
// 處理觸摸開始
function handleTouchStart(e) {
if (e.target === pizzaContainer || e.target.tagName === 'svg' || e.target.tagName === 'circle') {
return;
}
let target = e.target;
while (target && !target.classList.contains('pizza-topping')) {
target = target.parentElement;
}
if (!target) return;
e.preventDefault();
currentTopping = target;
isDragging = true;
const touch = e.touches[0];
const rect = target.getBoundingClientRect();
offsetX = touch.clientX - rect.left;
offsetY = touch.clientY - rect.top;
target.style.zIndex = 20;
}
// 處理觸摸移動
function handleTouchMove(e) {
if (!isDragging || !currentTopping) return;
e.preventDefault();
const touch = e.touches[0];
const pizzaRect = pizzaContainer.getBoundingClientRect();
const x = touch.clientX - pizzaRect.left - offsetX;
const y = touch.clientY - pizzaRect.top - offsetY;
// 限制在披薩範圍內
const toppingRect = currentTopping.getBoundingClientRect();
const toppingWidth = toppingRect.width;
const toppingHeight = toppingRect.height;
const maxX = pizzaRect.width - toppingWidth;
const maxY = pizzaRect.height - toppingHeight;
const boundedX = Math.max(0, Math.min(x, maxX));
const boundedY = Math.max(0, Math.min(y, maxY));
currentTopping.style.left = `${boundedX}px`;
currentTopping.style.top = `${boundedY}px`;
}
// 處理觸摸結束
function handleTouchEnd() {
if (currentTopping) {
currentTopping.style.zIndex = 10;
}
isDragging = false;
currentTopping = null;
}
// 重置披薩
function resetPizza() {
hasSauce = false;
hasCheese = false;
sauceLayer.classList.add('hidden');
cheeseLayer.classList.add('hidden');
toppings.forEach(topping => {
topping.element.remove();
});
toppings = [];
showMessage('披薩已重置!');
}
// 顯示訊息
function showMessage(text) {
message.textContent = text;
message.classList.remove('hidden');
setTimeout(() => {
message.classList.add('hidden');
}, 2000);
}
// 顯示代碼
function showCode() {
codeModal.classList.add('active');
codeDisplay.textContent = document.documentElement.outerHTML;
}
// 隱藏代碼
function hideCode() {
codeModal.classList.remove('active');
}
// 複製代碼
function copyCode() {
const code = codeDisplay.textContent;
navigator.clipboard.writeText(code).then(() => {
copyBtn.textContent = '已複製!';
setTimeout(() => {
copyBtn.textContent = '複製代碼';
}, 2000);
}).catch(err => {
console.error('無法複製代碼: ', err);
});
}
// 初始化
init();
});
</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:'947496add5f0f209',t:'MTc0ODUwNjk5NS4wMDAwMDA='};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>