iT邦幫忙

0

AI 生成 原生 JS 實現真實翻轉 3D 骰子模擬器

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250609/20058095YWh195iJEf.jpg

<!DOCTYPE html>
<html lang="zh-Hant">

<head>
  <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>真實邏輯骰子翻轉</title>
  <style>
body {
  background: #fff0f6;
  font-family: sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;         /* 改成 min-height,避免內容超出時截斷 */
  padding: 2vh 4vw;          /* 加入 padding 避免太擠 */
  box-sizing: border-box;    /* 確保 padding 不會影響布局 */
}

    .dice-container {
      width: 100px;
      height: 100px;
      perspective: 800px;
      position: relative;
      display: none; /* <-- 加這行:一開始隱藏 */
    }

    .dice {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      transform-style: preserve-3d;
    }


    .face {
      position: absolute;
      width: 100px;
      height: 100px;
      background: #e05555;
      border: 2px solid #a55151;
      border-radius: 20px;
      font-size: 60px;
      color: #ebebeb;
      display: flex;
      align-items: center;
      justify-content: center;
      font-weight: bold;
    }

    .face1  { transform: rotateY(  0deg) translateZ(50px); }
    .face2  { transform: rotateY(180deg) translateZ(50px); }
    .face3  { transform: rotateY( 90deg) translateZ(50px); }
    .face4  { transform: rotateY(-90deg) translateZ(50px); }
    .face5  { transform: rotateX( 90deg) translateZ(50px); }
    .face6  { transform: rotateX(-90deg) translateZ(50px); }

    button {
      margin-top: 40px;
      padding: 12px 24px;
      font-size: 18px;
      border: none;
      border-radius: 10px;
      background: #ff82aa;
      color: white;
      cursor: pointer;
      box-shadow: 0 4px 10px rgba(0,0,0,0.15);
    }
  </style>
</head>
<body>

  <div class="dice-container">
    <div class="dice" id="dice">
      <div class="face face1">15</div>
      <div class="face face2">18</div>
      <div class="face face3">22</div>
      <div class="face face4">25</div>
      <div class="face face5">27</div>
      <div class="face face6">30</div>
    </div>
  </div>

  <button onclick="rollDice()">擲骰子</button>

  <script>
    const dice = document.getElementById('dice');

function isClose(a, b, tolerance = 20) {
  return Math.abs(a - b) < tolerance;
}

    function rollDice() {

const diceContainer = document.querySelector('.dice-container');
const display = getComputedStyle(diceContainer).display;

if (display === 'none') {
  diceContainer.style.display = 'block';
}

      const faces = {
        1: [0, 0],
        2: [0, 180],
        3: [0, -90],
        4: [0, 90],
        5: [-90, 0],
        6: [90, 0],
      };

      const result = Math.floor(Math.random() * 6) + 1;
      const [baseX, baseY] = faces[result];

      const offsetX = (Math.random() * 50 + 60 ).toFixed(0); // -100 ~ +100
	
      const dropRotationX = 90 * (Math.random() > 0.5 ? 1 : -1);
      const dropRotationY = 90 * (Math.random() > 0.5 ? 1 : -1);

      // STEP 1: 初始狀態(在高處)
      dice.style.transition = 'none';
      dice.style.transform = `translateY(-300px) translateX(0px) rotateX(0deg) rotateY(0deg)`;
      void dice.offsetWidth;

      // STEP 2: 掉落 + 少量翻轉
      dice.style.transition = 'transform 0.4s ease-in';
      dice.style.transform = `
        translateY(0px)
        translateX(0px)
        rotateX(${dropRotationX}deg)
        rotateY(${dropRotationY}deg)
      `;

      // STEP 3: 彈開 + 主旋轉 + 結果面朝上
      setTimeout(() => {
        console.log(Math.floor(Math.random() * 1))
        const extraX = 360 * (Math.floor(Math.random() * 1) + 0.5); // 轉1~2圈
        const extraY = 360 * (Math.floor(Math.random() * 1) + 0.5);

        const tiltX = -25; // 往上抬一點
        const tiltY = 10;  // 稍微往右

        const finalX = baseX + extraX + tiltX;
        const finalY = baseY + extraY + tiltY;

        dice.style.transition = 'transform 1.2s ease-out';
        dice.style.transform = `
          translateY(0px)
          translateX(${offsetX}px)
          rotateX(${baseX + extraX + tiltX}deg)
          rotateY(${baseY + extraY + tiltY}deg)
        `;


        // 判斷最終朝上哪面(加 tolerance)
        setTimeout(() => {
          const trueX = baseX + extraX;
          const trueY = baseY + extraY;

          const x = ((trueX % 360) + 360) % 360;
          const y = ((trueY % 360) + 360) % 360;

          let faceIndex = '?';

          if (isClose(x, 90) && isClose(y, 0)) faceIndex = 6;
          else if (isClose(x, 270) && isClose(y, 0)) faceIndex = 5;
          else if (isClose(x, 0) && isClose(y, 0)) faceIndex = 1;
          else if (isClose(x, 0) && isClose(y, 180)) faceIndex = 2;
          else if (isClose(x, 0) && isClose(y, 270)) faceIndex = 3;
          else if (isClose(x, 0) && isClose(y, 90)) faceIndex = 4;

          if (faceIndex !== '?') {
            const topValue = dice.querySelector(`.face${faceIndex}`).textContent;
            console.log(`🎯 朝上的數字是:${topValue}`);
          } else {
            console.log(`❓ 無法判斷最終朝上的面`);
          }
        }, 1200);



      }, 400);
    }
  </script>

</body>
</html>


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言