turkeywu/facecombin
0
1<!DOCTYPE html>2<html lang="zh-TW">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>人臉組合遊戲</title>7 <style>8 * {9 margin: 0;10 padding: 0;11 box-sizing: border-box;12 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;13 }14 15 body {16 background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);17 color: white;18 min-height: 100vh;19 display: flex;20 flex-direction: column;21 align-items: center;22 padding: 2rem;23 }24 25 .container {26 max-width: 1200px;27 width: 100%;28 text-align: center;29 }30 31 h1 {32 font-size: 2.5rem;33 margin-bottom: 1rem;34 text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);35 }36 37 .description {38 font-size: 1.2rem;39 margin-bottom: 2rem;40 max-width: 700px;41 margin-left: auto;42 margin-right: auto;43 line-height: 1.6;44 }45 46 .game-area {47 display: flex;48 justify-content: center;49 gap: 2rem;50 margin-bottom: 2rem;51 }52 53 .face-container {54 width: 400px;55 height: 500px;56 background-color: rgba(255, 255, 255, 0.1);57 border-radius: 15px;58 position: relative;59 overflow: visible;60 box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);61 border: 2px solid rgba(255, 255, 255, 0.2);62 }63 64 .face-part {65 position: absolute;66 width: 100%;67 display: flex;68 justify-content: center;69 align-items: center;70 overflow: hidden;71 cursor: move;72 transition: transform 0.2s ease;73 }74 75 .face-part.dragging {76 cursor: grabbing;77 z-index: 100;78 }79 80 .face-part.selected {81 outline: 2px dashed #ffeb3b;82 outline-offset: 2px;83 }84 85 /* 確保額頭在最上層 */86 .forehead {87 top: 0;88 height: 35%;89 z-index: 30;90 }91 92 .eyes-nose {93 top: 30%;94 height: 45%;95 z-index: 20;96 }97 98 .mouth-chin {99 bottom: 0;100 height: 35%;101 z-index: 10;102 }103 104 .face-part img {105 max-width: 100%;106 max-height: 100%;107 object-fit: contain;108 pointer-events: none;109 transition: transform 0.3s ease;110 }111 112 .right-panel {113 display: flex;114 flex-direction: column;115 gap: 1.5rem;116 width: 300px;117 }118 119 .controls {120 display: flex;121 flex-direction: column;122 gap: 1rem;123 }124 125 button {126 padding: 12px 30px;127 font-size: 1.2rem;128 border: none;129 border-radius: 50px;130 background: linear-gradient(to right, #ff7e5f, #feb47b);131 color: white;132 cursor: pointer;133 transition: all 0.3s ease;134 box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);135 font-weight: bold;136 }137 138 button:hover {139 transform: translateY(-3px);140 box-shadow: 0 7px 20px rgba(0, 0, 0, 0.3);141 }142 143 button:active {144 transform: translateY(1px);145 }146 147 button:disabled {148 background: #cccccc;149 cursor: not-allowed;150 transform: none;151 box-shadow: none;152 }153 154 .result-message {155 margin-top: 1.5rem;156 font-size: 1.3rem;157 font-weight: bold;158 min-height: 2rem;159 text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);160 }161 162 .reset-position {163 margin-top: 10px;164 padding: 8px 16px;165 font-size: 0.9rem;166 }167 168 .scale-controls {169 display: flex;170 flex-direction: column;171 gap: 1rem;172 margin-top: 1rem;173 width: 100%;174 }175 176 .scale-control-group {177 display: flex;178 justify-content: space-between;179 align-items: center;180 background: rgba(255, 255, 255, 0.1);181 padding: 10px 15px;182 border-radius: 10px;183 }184 185 .scale-label {186 font-size: 1rem;187 font-weight: bold;188 }189 190 .scale-buttons {191 display: flex;192 gap: 0.5rem;193 }194 195 .scale-btn {196 padding: 6px 12px;197 font-size: 0.9rem;198 }199 200 .instructions {201 margin-top: 1rem;202 font-size: 0.9rem;203 color: rgba(255, 255, 255, 0.8);204 max-width: 400px;205 }206 207 .current-selection {208 margin-top: 1rem;209 font-size: 1rem;210 color: #ffeb3b;211 min-height: 1.5rem;212 }213 214 @media (max-width: 768px) {215 .game-area {216 flex-direction: column;217 align-items: center;218 }219 220 .right-panel {221 width: 100%;222 max-width: 400px;223 }224 225 .face-container {226 width: 300px;227 height: 400px;228 }229 230 .scale-control-group {231 flex-direction: column;232 gap: 0.5rem;233 }234 }235 </style>236</head>237<body>238 <div class="container">239 <h1>人臉組合遊戲</h1>240 <p class="description">按下開始按鈕,隨機組合額頭、眼睛鼻子、嘴巴下巴,創造獨一無二的新面孔!</p>241 242 <div class="game-area">243 <div class="face-container" id="face-container">244 <div class="face-part forehead" id="forehead-part">245 <img id="forehead-img" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjEyMCIgdmlld0JveD0iMCAwIDMwMCAxMjAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIzMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjNGE5MGUyIi8+Cjx0ZXh0IHg9IjE1MCIgeT0iNjAiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiPuiPnOWHuzwvdGV4dD4KPC9zdmc+" alt="額頭">246 </div>247 <div class="face-part eyes-nose" id="eyes-nose-part">248 <img id="eyes-nose-img" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjE2MCIgdmlld0JveD0iMCAwIDMwMCAxNjAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIzMDAiIGhlaWdodD0iMTYwIiBmaWxsPSIjN2VkMzIxIi8+Cjx0ZXh0IHg9IjE1MCIgeT0iODAiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiPuihqOi/nOaUueiPnDwvdGV4dD4KPC9zdmc+" alt="眼睛鼻子">249 </div>250 <div class="face-part mouth-chin" id="mouth-chin-part">251 <img id="mouth-chin-img" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjEyMCIgdmlld0JveD0iMCAwIDMwMCAxMjAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIzMDAiIGhlaWdodD0iMTIwIiBmaWxsPSIjZDAwMjFiIi8+Cjx0ZXh0IHg9IjE1MCIgeT0iNjAiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0id2hpdGUiI116leHQtYW5jaG9yPSJtaWRkbGUiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiPuWNl+WbnuWnkzwvdGV4dD4KPC9zdmc+" alt="嘴巴下巴">252 </div>253 </div>254 255 <div class="right-panel">256 <div class="current-selection" id="current-selection">257 點擊選擇要調整的部位258 </div>259 260 <div class="scale-controls">261 <div class="scale-control-group">262 <div class="scale-label">額頭</div>263 <div class="scale-buttons">264 <button class="scale-btn" data-part="forehead" data-action="zoom-out">縮小</button>265 <button class="scale-btn" data-part="forehead" data-action="reset">重置</button>266 <button class="scale-btn" data-part="forehead" data-action="zoom-in">放大</button>267 </div>268 </div>269 270 <div class="scale-control-group">271 <div class="scale-label">眼睛鼻子</div>272 <div class="scale-buttons">273 <button class="scale-btn" data-part="eyesNose" data-action="zoom-out">縮小</button>274 <button class="scale-btn" data-part="eyesNose" data-action="reset">重置</button>275 <button class="scale-btn" data-part="eyesNose" data-action="zoom-in">放大</button>276 </div>277 </div>278 279 <div class="scale-control-group">280 <div class="scale-label">嘴巴下巴</div>281 <div class="scale-buttons">282 <button class="scale-btn" data-part="mouthChin" data-action="zoom-out">縮小</button>283 <button class="scale-btn" data-part="mouthChin" data-action="reset">重置</button>284 <button class="scale-btn" data-part="mouthChin" data-action="zoom-in">放大</button>285 </div>286 </div>287 </div>288 289 <button class="reset-position" id="reset-position-btn">重置所有位置與大小</button>290 291 <div class="controls">292 <button id="start-btn">開始組合</button>293 <button id="stop-btn" disabled>停止組合</button>294 </div>295 296 <div class="result-message" id="result-message">297 按下開始按鈕創造新面孔!298 </div>299 300 <div class="instructions">301 提示:點擊選擇要調整的部位,然後使用縮放按鈕調整大小,或直接拖動調整位置302 </div>303 </div>304 </div>305 </div>306 307 <script>308 // 圖片資料庫 - 根據您的資料夾結構309 const faceParts = {310 forehead: [],311 eyesNose: [],312 mouthChin: []313 };314 315 // 初始化圖片路徑316 function initImagePaths() {317 // 額頭圖片路徑 (head資料夾)318 for (let i = 1; i <= 28; i++) {319 faceParts.forehead.push({320 id: i,321 src: `combind/head/${i}.jpg`322 });323 }324 325 // 眼睛鼻子圖片路徑 (eye資料夾)326 for (let i = 1; i <= 28; i++) {327 faceParts.eyesNose.push({328 id: i,329 src: `combind/eye/${i}.jpg`330 });331 }332 333 // 嘴巴下巴圖片路徑 (mouse資料夾)334 for (let i = 1; i <= 28; i++) {335 faceParts.mouthChin.push({336 id: i,337 src: `combind/mouse/${i}.jpg`338 });339 }340 }341 342 // DOM元素343 const startBtn = document.getElementById('start-btn');344 const stopBtn = document.getElementById('stop-btn');345 const resultMessage = document.getElementById('result-message');346 const resetPositionBtn = document.getElementById('reset-position-btn');347 const currentSelectionText = document.getElementById('current-selection');348 const faceContainer = document.getElementById('face-container');349 350 // 臉部部位元素351 const foreheadImg = document.getElementById('forehead-img');352 const eyesNoseImg = document.getElementById('eyes-nose-img');353 const mouthChinImg = document.getElementById('mouth-chin-img');354 355 // 臉部部位容器元素356 const foreheadPart = document.getElementById('forehead-part');357 const eyesNosePart = document.getElementById('eyes-nose-part');358 const mouthChinPart = document.getElementById('mouth-chin-part');359 360 // 遊戲狀態361 let isSpinning = false;362 let spinInterval;363 let currentSelection = {364 forehead: 0,365 eyesNose: 0,366 mouthChin: 0367 };368 369 // 拖動狀態370 let isDragging = false;371 let currentDraggingPart = null;372 let dragOffset = { x: 0, y: 0 };373 374 // 縮放狀態375 let scaleFactors = {376 forehead: 1,377 eyesNose: 1,378 mouthChin: 1379 };380 381 // 當前選中的部位382 let selectedPart = null;383 384 // 初始化遊戲385 function initGame() {386 // 初始化圖片路徑387 initImagePaths();388 389 // 設置初始圖片390 updateFace();391 392 // 設置拖動事件393 setupDragging();394 395 // 設置縮放按鈕事件396 setupScaleButtons();397 398 // 事件監聽399 startBtn.addEventListener('click', startSpinning);400 stopBtn.addEventListener('click', stopSpinning);401 resetPositionBtn.addEventListener('click', resetAll);402 403 // 初始選擇第一個部位404 selectPart('forehead');405 }406 407 // 設置拖動功能408 function setupDragging() {409 const parts = [foreheadPart, eyesNosePart, mouthChinPart];410 411 parts.forEach(part => {412 // 鼠標按下事件413 part.addEventListener('mousedown', (e) => {414 startDrag(e);415 // 點擊時選擇該部位416 const partId = part.id.replace('-part', '');417 selectPart(partId);418 });419 420 // 觸摸設備支持421 part.addEventListener('touchstart', (e) => {422 startDrag(e);423 // 點擊時選擇該部位424 const partId = part.id.replace('-part', '');425 selectPart(partId);426 }, { passive: false });427 });428 429 // 鼠標移動事件430 document.addEventListener('mousemove', drag);431 document.addEventListener('touchmove', drag, { passive: false });432 433 // 鼠標釋放事件434 document.addEventListener('mouseup', endDrag);435 document.addEventListener('touchend', endDrag);436 }437 438 // 設置縮放按鈕事件439 function setupScaleButtons() {440 const scaleButtons = document.querySelectorAll('.scale-btn');441 442 scaleButtons.forEach(button => {443 button.addEventListener('click', () => {444 const part = button.dataset.part;445 const action = button.dataset.action;446 447 // 選擇對應的部位448 selectPart(part);449 450 // 執行對應的操作451 if (action === 'zoom-in') {452 zoomPart(part, 0.1);453 } else if (action === 'zoom-out') {454 zoomPart(part, -0.1);455 } else if (action === 'reset') {456 resetPartScale(part);457 }458 });459 });460 }461 462 // 選擇部位463 function selectPart(partId) {464 // 移除所有部位的選中狀態465 foreheadPart.classList.remove('selected');466 eyesNosePart.classList.remove('selected');467 mouthChinPart.classList.remove('selected');468 469 // 設置當前選中的部位470 selectedPart = partId;471 472 // 添加選中狀態473 if (partId === 'forehead') {474 foreheadPart.classList.add('selected');475 currentSelectionText.textContent = '當前選擇: 額頭';476 } else if (partId === 'eyesNose') {477 eyesNosePart.classList.add('selected');478 currentSelectionText.textContent = '當前選擇: 眼睛鼻子';479 } else if (partId === 'mouthChin') {480 mouthChinPart.classList.add('selected');481 currentSelectionText.textContent = '當前選擇: 嘴巴下巴';482 }483 }484 485 // 開始拖動486 function startDrag(e) {487 e.preventDefault();488 isDragging = true;489 currentDraggingPart = e.currentTarget;490 currentDraggingPart.classList.add('dragging');491 492 // 計算偏移量493 const rect = currentDraggingPart.getBoundingClientRect();494 if (e.type === 'mousedown') {495 dragOffset.x = e.clientX - rect.left;496 dragOffset.y = e.clientY - rect.top;497 } else if (e.type === 'touchstart') {498 dragOffset.x = e.touches[0].clientX - rect.left;499 dragOffset.y = e.touches[0].clientY - rect.top;500 }501 }502 503 // 拖動中504 function drag(e) {505 if (!isDragging || !currentDraggingPart) return;506 507 e.preventDefault();508 509 let clientX, clientY;510 if (e.type === 'mousemove') {511 clientX = e.clientX;512 clientY = e.clientY;513 } else if (e.type === 'touchmove') {514 clientX = e.touches[0].clientX;515 clientY = e.touches[0].clientY;516 }517 518 // 計算新位置519 const containerRect = faceContainer.getBoundingClientRect();520 const newLeft = clientX - containerRect.left - dragOffset.x;521 const newTop = clientY - containerRect.top - dragOffset.y;522 523 // 擴大移動範圍 - 允許元素移出容器524 const maxLeft = containerRect.width + 100;525 const maxTop = containerRect.height + 100;526 527 const boundedLeft = Math.max(-100, Math.min(maxLeft, newLeft));528 const boundedTop = Math.max(-100, Math.min(maxTop, newTop));529 530 // 應用新位置531 currentDraggingPart.style.left = `${boundedLeft}px`;532 currentDraggingPart.style.top = `${boundedTop}px`;533 }534 535 // 結束拖動536 function endDrag() {537 if (isDragging && currentDraggingPart) {538 currentDraggingPart.classList.remove('dragging');539 }540 isDragging = false;541 currentDraggingPart = null;542 }543 544 // 重置所有位置和大小545 function resetAll() {546 // 重置位置547 foreheadPart.style.left = '0px';548 foreheadPart.style.top = '0px';549 eyesNosePart.style.left = '0px';550 eyesNosePart.style.top = '175px';551 mouthChinPart.style.left = '0px';552 mouthChinPart.style.top = '325px';553 554 // 重置縮放555 scaleFactors = {556 forehead: 1,557 eyesNose: 1,558 mouthChin: 1559 };560 561 // 應用縮放重置562 applyScale();563 564 // 重置選擇565 selectPart('forehead');566 }567 568 // 重置特定部位的縮放569 function resetPartScale(part) {570 scaleFactors[part] = 1;571 applyScale();572 }573 574 // 縮放特定部位575 function zoomPart(part, delta) {576 scaleFactors[part] = Math.max(0.5, Math.min(2, scaleFactors[part] + delta));577 applyScale();578 }579 580 // 應用縮放581 function applyScale() {582 foreheadImg.style.transform = `scale(${scaleFactors.forehead})`;583 eyesNoseImg.style.transform = `scale(${scaleFactors.eyesNose})`;584 mouthChinImg.style.transform = `scale(${scaleFactors.mouthChin})`;585 }586 587 // 創建佔位圖片588 function createPlaceholderImage(text, color) {589 const svg = `<svg width="300" height="120" viewBox="0 0 300 120" fill="none" xmlns="http://www.w3.org/2000/svg">590 <rect width="300" height="120" fill="${color}"/>591 <text x="150" y="60" font-family="Arial" font-size="14" fill="white" text-anchor="middle" dominant-baseline="middle">${text}</text>592 </svg>`;593 return 'data:image/svg+xml;base64,' + btoa(svg);594 }595 596 // 開始旋轉597 function startSpinning() {598 if (isSpinning) return;599 600 isSpinning = true;601 startBtn.disabled = true;602 stopBtn.disabled = false;603 resultMessage.textContent = "組合中...";604 605 // 隨機選擇臉部部位606 spinInterval = setInterval(() => {607 currentSelection.forehead = Math.floor(Math.random() * faceParts.forehead.length);608 currentSelection.eyesNose = Math.floor(Math.random() * faceParts.eyesNose.length);609 currentSelection.mouthChin = Math.floor(Math.random() * faceParts.mouthChin.length);610 611 // 更新臉部圖片612 updateFace();613 }, 100); // 每100ms更新一次614 }615 616 // 停止旋轉617 function stopSpinning() {618 if (!isSpinning) return;619 620 clearInterval(spinInterval);621 isSpinning = false;622 startBtn.disabled = false;623 stopBtn.disabled = true;624 625 // 顯示結果訊息626 resultMessage.textContent = "新面孔創造成功!";627 }628 629 // 更新臉部圖片630 function updateFace() {631 // 設置圖片並添加錯誤處理632 foreheadImg.src = faceParts.forehead[currentSelection.forehead].src;633 foreheadImg.onerror = function() {634 this.src = createPlaceholderImage('額頭', '#4a90e2');635 };636 637 eyesNoseImg.src = faceParts.eyesNose[currentSelection.eyesNose].src;638 eyesNoseImg.onerror = function() {639 this.src = createPlaceholderImage('眼睛鼻子', '#7ed321');640 };641 642 mouthChinImg.src = faceParts.mouthChin[currentSelection.mouthChin].src;643 mouthChinImg.onerror = function() {644 this.src = createPlaceholderImage('嘴巴下巴', '#d0021b');645 };646 }647 648 // 初始化遊戲649 window.onload = initGame;650 </script>651</body>652</html>