在大转盘游戏中,使用百分比计算概率是一种直观且常用的方法。这种方法通过为每个奖项分配一定的百分比概率,确保所有奖项的概率总和为 100%,从而实现公平且可控制的抽奖逻辑。
1.HTML代码和样式
<template>
<!-- 大转盘抽奖 -->
<div class="bigPages">
<div class="bigBox">
<div class="out-box" ref="outBox">
<div v-for="(item, index) in awardList" :style="{'--i': index,'--color': setColor(index)}">
<text>{{item.name}}</text>
</div>
</div>
<div class="inset" @click="awardStart">抽奖</div>
</div>
</div>
</template>
<style lang="scss" scoped>
@mixin felx-center {
display: flex;
justify-content: center;
align-items: center;
}
@font-face {
font-family: 'diyFont';
src: url('../assets/禹卫书法行书简体.ttf');
}
.bigPages {
@include felx-center();
height: 100vh;
width: 100vw;
margin: auto;
.bigBox {
@include felx-center();
position: relative;
}
.out-box {
position: relative;
height: 300px;
width: 300px;
border-radius: 50%;
background-color: red;
overflow: hidden;
// transform: rotate(45deg);
div {
@include felx-center();
position: absolute;
height: 50%;
width: 150px;
overflow: hidden;
background-color: var(--color);
// transform: rotate(calc(var(--i) * 45deg));
transform-origin: right bottom;
-webkit-clip-path: polygon(0 0, 37% 0, 100% 100%, 0 60%);
clip-path: polygon(0 0, 59% 0, 100% 100%, 0 59%);
text {
transform: rotate(-45deg) translateY(-20px);
}
}
}
.inset {
@include felx-center();
position: absolute;
height: 60px;
width: 60px;
border-radius: 50%;
background-color: #fff;
box-shadow: 0 0 3px 2px #fee;
font-size: 25px;
font-family: 'diyFont';
font-weight: bold;
cursor: pointer;
}
.inset::before {
content: '';
position: absolute;
// top: -78px;
// right: 20px;
// border: 40px solid #fff;
// border-left-width: 10px;
// border-right-width: 10px;
// border-left-color: transparent;
// border-right-color: transparent;
// border-top-color: transparent;
top: -38px;
right: 20px;
height: 40px;
width: 20px;
-webkit-clip-path: polygon(50% 0, 0 100%, 100% 100%);
clip-path: polygon(50% 0, 0 100%, 100% 100%);
background-color: #fff;
}
}
</style>
2.JS实现逻辑
<script setup>
import {
ref,
onMounted
} from "vue"
const awardList = ref([{
name: '1号奖品',
precent: 5
}, //5%
{
name: '2号奖品',
precent: 5
},
{
name: '3号奖品',
precent: 10
},
{
name: '4号奖品',
precent: 10
},
{
name: '5号奖品',
precent: 15
},
{
name: '6号奖品',
precent: 15
},
{
name: '7号奖品',
precent: 15
},
{
name: '未中奖',
precent: 25
},
])
const outBox = ref(null)
const textAll = ref([]);
const divAll = ref([]);
const isFlag = ref(true); //防止重复点击抽奖按钮
const timer = ref(null);
const rotateDeg = ref(0); //计算旋转度数 360 / 总数量(awardList的数量)
// 权重 获奖概率 2
const weight = ref([5, 10, 20, 30, 45, 60, 75, 100])
onMounted(() => {
rotateDeg.value = (360 / awardList.value.length).toFixed(2)
textAll.value = document.querySelectorAll('text')
divAll.value = document.querySelectorAll('.out-box > div')
outBox.value.style.transform = "rotate(" + rotateDeg.value + "deg)"
for (let i = 0; i < awardList.value.length; i++) {
divAll.value[i].style.transform = "rotate(" + i * rotateDeg.value + "deg)"
}
})
const awardStart = () => {
if (isFlag.value) {
// 不考虑概率问题 ---1
// let random = parseInt(Math.random() * 8)
// getAward( rotateDeg.value - (rotateDeg.value * random), awardList.value[random].name)
// 数组权重计算概率 ---2
// let random = parseInt(Math.random() * 100);
// let randomWeight = weight.value.concat(random);
// let randomSort = randomWeight.sort((a,b) => {
// return a - b;
// })
// let randomIndex = randomSort.indexOf(random);
// // 向逆时针旋转
// getAward( rotateDeg.value - (rotateDeg.value * randomIndex), awardList.value[randomIndex].name)
// 用百分比计算中奖概率问题(随机数在概率值之间的个数)---3
let percentTotal = awardList.value.reduce((sum, per) => sum + per.precent, 0);
let random = parseInt(Math.random() * percentTotal);
let sumPercent = 0; //概率累计值
let percentIndex = 0;
for (let i = 0; i < awardList.value.length; i++) {
// 累加值为-- 5, 10, 20, 30, 45, 60, 75, 100
sumPercent += awardList.value[i].precent;
if (random < sumPercent) {
percentIndex = i // 找到中奖奖项
break
}
}
// 向逆时针旋转
getAward(rotateDeg.value - (rotateDeg.value * percentIndex), awardList.value[percentIndex].name)
}
}
// 转到那个奖项
const getAward = (dun, text) => {
isFlag.value = false;
console.log('dd', dun + '---' + text);
let begin = 0;
let basic = 360 * 5; //多少圈1800 / 360
timer.value = setInterval(() => {
if (begin >= (basic + dun)) {
isFlag.value = true;
clearInterval(timer.value)
}
outBox.value.style.transform = "rotate(" + begin + "deg)";
// 缓慢停止的公式
begin += Math.ceil((basic + dun - begin) * 0.1);
// begin += 20
}, 20)
}
const setColor = (index) => {
let str = ''
switch (index) {
case 0:
str = '#ff8d79';
break;
case 1:
str = '#86ffa2';
break;
case 2:
str = '#d0b4ff';
break;
case 3:
str = '#66ebff';
break;
case 4:
str = '#ffa6ce';
break;
case 5:
str = '#e4feff';
break;
case 6:
str = '#a097ff';
break;
case 7:
str = '#eab5ff';
break;
case 8:
str = '#ffa6ce';
break;
case 9:
str = '#e4feff';
break;
case 10:
str = '#a097ff';
break;
}
return str
}
</script>
3.实现效果图
注:该笔记主要用于自我研究学习,如有好的想法和改进之处请在评论区提出。