iT邦幫忙

0

【AI幫寫】幸運轉輪、午餐吃什麼!!

  • 分享至 

  • xImage
  •  

就自己有排序、抽獎需求,請AI寫了一個自己想用的網頁,放在github上無毒沒廣告,
有興趣的人可以看看:

https://mackuo.github.io/Wheel-of-fortune/


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

1 則留言

1
淺水員
iT邦大師 6 級 ‧ 2026-07-02 23:09:17

當作交流吧,我變動的點:

  1. Web Animations API 處理
  2. 模擬物理性質
    • 假設這是等角加速度運動,所以用二次曲線
    • 全程時間由旋轉的角度推導,而不是直接取亂數
  3. 簡化計算角度的步驟
/* ---------------- Spin logic ---------------- */

  /**
   * 調整小數部分往中間集中些(變成 0.1 ~ 0.9)
  */
  function adjSector(val) {
    return (val | 0) + 0.1 + (val - ((val | 0))) * 0.8;
  }

  function spin(){
    if (isSpinning || wheelItems.length === 0) return;
    isSpinning = true;
    updateSpinAvailability();

    const n = wheelItems.length;
    const reduceMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;

    /**
     * 這邊用旋轉幾個扇形區域為單位來計算
     * 這樣整數部分就是第幾個選項的索引
     * 小數部分對應到扇形內多轉了多少
    */
    const rndSector = (reduceMotion ? 2 + Math.random() : 6 +  Math.random() * 5) * n;
    const nextSector = adjSector(currentSector + rndSector);
    
    /**
     * 旋轉經過的角度與時間平方成正比
     * 所以時間應該由旋轉經過的角度開根號獲得
     * 這樣體感上才會是同一個轉盤
     * 後面係數可以自行改變,數字越大代表摩擦力越小
    */
    const duration = Math.sqrt((nextSector - currentSector) / n) * 1800 | 0;
    const fromDeg = Math.round(currentSector * 360 / n);
    const toDeg = Math.round(nextSector * 360 / n);

    let startTime = null;
    let lastSliceIdx = currentSector | 0;
    
    const ani = wheelWrap.animate([
        { transform: `rotate(${fromDeg}deg)` },
        { transform: `rotate(${toDeg}deg)` }
    ], {
        duration: duration,
        // 這是一條拋物線,以符合等角加速度運動
        easing: 'cubic-bezier(0.333, 0.667, 0.667, 1)',
        fill: 'forwards'
    });

    function frame() {
        // 取得目前的進度值 (0.0 ~ 1.0 之間),這直接就是 Sector 的進度了
        let t = ani.effect.getComputedTiming().progress;
        
        if (t !== null) {
            // 透過進度,等比例算出當前所處的 sector 索引
            const idx = currentSector + (nextSector - currentSector) * t | 0;
            if (idx !== lastSliceIdx){
              lastSliceIdx = idx;
              playTick();
            }
        }

        // 如果動畫還沒結束,就在下一影格繼續監控
        if (ani.playState !== 'finished') {
            requestAnimationFrame(frame);
        } else {
            currentSector = (nextSector | 0) % n + (nextSector - (nextSector | 0));
            isSpinning = false;
            updateSpinAvailability();
            onSpinComplete(n - 1 - (currentSector | 0));
        }
    }
    requestAnimationFrame(frame);
  }

我要留言

立即登入留言