幸运大转盘:使用HTML5和JavaScript制作的抽奖转盘

该文章已生成可运行项目,

简介

在这篇文章中,我们将学习如何使用 HTML5 和 JavaScript 来实现一个幸运大转盘的抽奖效果。这个转盘能够模拟现实中的幸运转盘抽奖机制,通过点击按钮,用户能够看到不同奖品的抽取结果。接下来,我们将逐步分析代码,看看如何实现这一功能。

效果展示

在这个幸运大转盘中,玩家可以通过点击“GO”按钮触发转盘的旋转,并最终抽取一个奖品。转盘上的每个奖品都有不同的概率,最终的奖品会通过一个漂亮的闪烁效果呈现给用户。
在这里插入图片描述

功能介绍

1.转盘绘制:

  • 使用 HTML5 Canvas 来绘制转盘的轮廓和奖品扇形。
  • 每个奖品区域会用不同的颜色显示,并且会显示奖品的图标和名称。

2.奖品设置:

  • 每个奖品都有一个名字和图片,且不同奖品的出现概率不同。

3.转盘旋转

  • 点击“GO”按钮时,转盘开始旋转,并且最终选中一个奖品。
  • 转盘旋转时,采用闪烁效果,使最终的奖品更加突出。

4.结果显示:

  • 旋转结束后,会弹出一个模态框显示中奖的奖品,包括奖品名称和图片。

代码分析

<body>
    <!-- 轮盘 -->
    <h1>幸运大转盘</h1>
    <div class="wheel-container">
        <canvas id="wheelCanvas" width="500" height="500"></canvas>
        <button class="go-button" id="goButton">GO</button>
    </div>
    <!-- 结果弹窗 -->
    <div class="modal" id="resultModal">
        <div class="modal-content">
            <span class="close-button" id="closeModal">&times;</span>
            <h2>恭喜!</h2>
            <img id="prizeImage" class="prize-image" src="" alt="奖品图片">
            <p id="prizeText"></p>
        </div>
    </div>

    <script>
        const canvas = document.getElementById('wheelCanvas');
        const ctx = canvas.getContext('2d');
        const goButton = document.getElementById('goButton');
        const modal = document.getElementById('resultModal');
        const closeModal = document.getElementById('closeModal');
        const prizeText = document.getElementById('prizeText');

        // 奖品配置(name奖品名称,probability:概率,pic:图片信息)
        const prizes = [
           
            { name: "宝马", probability: 12.00, pic:'../Image/drawWheel/1.png' },
            { name: "兰博基尼", probability: 10.00, pic:'../Image/drawWheel/2.png' },
            { name: "烈焰头饰", probability: 20.00, pic:'../Image/drawWheel/3.png'},
            { name: "冰雪头饰", probability: 8.00, pic:'../Image/drawWheel/4.png' },
            { name: "代金券", probability: 3.00, pic:'../Image/drawWheel/6.png' },
            { name: "宝石", probability: 25.50, pic:'../Image/drawWheel/7.png' },
            { name: "金币", probability: 5.00, pic:'../Image/drawWheel/8.png' },
            { name: "礼包", probability: 0.50, pic:'../Image/drawWheel/9.png' },
            { name: "Miss", probability: 6, pic:'../Image/drawWheel/10.png' },
            { name: "再来一次", probability: 6.00, pic:'../Image/drawWheel/11.png' },
        ];

        const normalColors = ['#FFD700', '#FF4500'];  // 金色和橙红色
        const highlightColors = ['#FFE44D', '#FF6347'];  // 亮金色和亮橙红色
        const radius = 240;//轮盘半径
        const centerX = canvas.width / 2;//轮盘中心x坐标    
        const centerY = canvas.height / 2;//轮盘中心y坐标
        let isSpinning = false;//是否正在旋转
        let highlightedIndex = -1;//当前高亮显示的奖品索引

        // 预加载图片
        const images = prizes.map(prize => {
            const img = new Image();
            img.src = prize.pic;
            return img;
        });

        // 绘制转盘
        function drawWheel() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);//清除画布
            
            const anglePerPrize = (Math.PI * 2) / prizes.length;//每个扇形的角度
            
            prizes.forEach((prize, index) => {
                const startAngle = index * anglePerPrize;//每个扇形的起始角度
                const endAngle = (index + 1) * anglePerPrize;//每个扇形的结束角度
                
                // 绘制扇形
                ctx.beginPath();//开始绘制路径
                ctx.moveTo(centerX, centerY);//移动到中心点
                ctx.arc(centerX, centerY, radius, startAngle, endAngle);//绘制弧线
                ctx.closePath();//关闭路径
                
                // 判断是否需要高亮显示
                if (index === highlightedIndex) {
                    ctx.fillStyle = highlightColors[index % 2];//设置高亮颜色
                } else {
                    ctx.fillStyle = normalColors[index % 2];//设置正常颜色
                }
                ctx.fill();//填充
                
                // 绘制图片
                ctx.save();//保存当前状态
                ctx.translate(centerX, centerY);//移动到中心点
                ctx.rotate(startAngle + anglePerPrize / 2);//旋转
                
                // 计算图片位置和大小
                const imgSize = 60; // 图片大小
                const imgDistance = radius * 0.7; // 图片距离中心的距离
                
                // 绘制图片,确保图片已加载
                if (images[index].complete) {
                    // 保存当前旋转状态
                    ctx.save();
                    // 反向旋转,抵消扇形的旋转,使图片保持垂直
                    ctx.rotate(-(startAngle + anglePerPrize / 2));
                    // 计算图片在扇形中的位置
                    const x = Math.cos(startAngle + anglePerPrize / 2) * imgDistance;//计算图片在扇形中的x坐标
                    const y = Math.sin(startAngle + anglePerPrize / 2) * imgDistance;//计算图片在扇形中的y坐标
                    ctx.drawImage(
                        images[index],//图片        
                        x - imgSize / 2,//图片x坐标
                        y - imgSize / 2,//图片y坐标
                        imgSize,//图片宽度
                        imgSize//图片高度
                    );

                    // 绘制奖品名称
                    ctx.font = '14px Arial';//设置字体
                    ctx.fillStyle = '#FFFFFF';//设置文字颜色    
                    ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';//设置阴影颜色
                    ctx.shadowBlur = 4;//设置阴影模糊度
                    ctx.shadowOffsetX = 2;//设置阴影偏移量
                    ctx.shadowOffsetY = 2;//设置阴影偏移量
                    ctx.textAlign = 'center';//设置文字对齐方式
                    ctx.textBaseline = 'middle';//设置文字基线
                    // 文字位置在图片下方
                    ctx.fillText(
                        prize.name, //奖品名称
                        x,
                        y + imgSize/2 + 12
                    );
                    // 清除阴影效果
                    ctx.shadowColor = 'transparent';//阴影颜色
                    ctx.shadowBlur = 0;//阴影模糊度
                    ctx.shadowOffsetX = 0;//阴影偏移量
                    ctx.shadowOffsetY = 0;//阴影偏移量

                    // 恢复旋转状态
                    ctx.restore();//恢复旋转状态
                }
                
                ctx.restore();//恢复旋转状态
            });

            // 绘制中心圆形遮罩
            ctx.beginPath();//开始绘制路径
            ctx.arc(centerX, centerY, 50, 0, Math.PI * 2);//绘制圆形
            ctx.fillStyle = '#2d2d2d';//设置填充颜色
            ctx.fill();//填充
        }

        // 根据概率获取奖品
        function getRandomPrize() {
            const random = Math.random() * 100;//随机数
            let probabilitySum = 0;//概率总和
            
            for (let i = 0; i < prizes.length; i++) {//遍历奖品 
                probabilitySum += prizes[i].probability;//累加概率  
                if (random <= probabilitySum) {//如果随机数小于等于概率总和
                    return i;//返回奖品索引
                }
            }
            return prizes.length - 1;//返回最后一个奖品索引
        }

        // 亮起一圈
        function lightUpOneRound(prizeIndex, callback) {
            let currentIndex = 0;
            const speed = 100; // 每个扇形亮起的时间间隔
            
            function lightUp() {
                if (currentIndex >= prizes.length) {//如果当前索引大于等于奖品数量
                    callback();//回调函数
                    return;
                }
                
                highlightedIndex = currentIndex;//当前高亮显示的奖品索引
                drawWheel();
                currentIndex++;
                setTimeout(lightUp, speed);
            }
            
            lightUp();//亮起一圈
        }

        // 最终奖品闪烁效果
        function flashFinalPrize(index) {
            let flashCount = 0;
            const maxFlashes = 5; // 闪烁次数
            const flashSpeed = 200; // 闪烁间隔时间
            
            function flash() {
                if (flashCount >= maxFlashes * 2) {
                    highlightedIndex = index; // 最后保持高亮
                    drawWheel();
                    isSpinning = false;
                    goButton.disabled = false;
                    
                    // 显示中奖信息和图片
                    const prizeImage = document.getElementById('prizeImage');
                    prizeImage.src = prizes[index].pic;
                    prizeText.textContent = `您获得了:${prizes[index].name}`;
                    modal.style.display = 'block';
                    return;
                }
                
                highlightedIndex = flashCount % 2 === 0 ? index : -1;
                drawWheel();
                flashCount++;
                setTimeout(flash, flashSpeed);
            }
            
            flash();
        }

        // 开始抽奖
        function spin() {
            if (isSpinning) return;//如果正在旋转,则返回
            
            isSpinning = true;//设置正在旋转
            goButton.disabled = true;//禁用按钮
            
            // 随机选择奖品
            const prizeIndex = getRandomPrize();//随机选择奖品
            
            // 先亮一圈,然后显示最终结果
            lightUpOneRound(prizeIndex, () => {
                // 短暂暗下来
                highlightedIndex = -1;
                drawWheel();
                
                // 延迟一下再显示最终结果
                setTimeout(() => {
                    flashFinalPrize(prizeIndex);
                }, 500);
            });
        }

        // 等待所有图片加载完成后初始化
        let loadedImages = 0;
        images.forEach(img => {
            img.onload = () => {
                loadedImages++;
                if (loadedImages === images.length) {
                    drawWheel();
                }
            };
        });
        
        // 事件监听
        goButton.addEventListener('click', spin);
        
        closeModal.addEventListener('click', () => {
            modal.style.display = 'none';
        });
        
        window.addEventListener('click', (event) => {
            if (event.target === modal) {
                modal.style.display = 'none';
            }
        });
    </script>
</body>

核心功能详解:

绘制转盘:使用Canvas API绘制转盘,并根据奖品的数量与分布绘制相应的扇形区域。

转盘旋转:通过设置旋转角度和利用setTimeout控制旋转的速度,实现转盘的旋转动画。

随机奖品抽取:通过 Math.random 生成随机数,按照奖品的概率分配机制,决定最终的中奖结果。

总结

通过HTML5和JavaScript的结合,我们实现了一个简单而有趣的幸运大转盘游戏。用户可以通过点击按钮触发转盘旋转,并显示最终的奖品。这个项目展示了如何使用Canvas API绘制图形,以及如何实现旋转动画和随机奖品抽取功能。

项目地址https://gitee.com/Mosen10086/h5-demo.git

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值