搖骰子設(shè)計(jì)與實(shí)現(xiàn)
手機(jī)搖一搖可以搖骰子,上劃可查看結(jié)果,震動加聲音等功能。
本章底部會貼出所有代碼,圖片資源以及音頻資源很簡單,自己找一下就行了。
已經(jīng)上線小程序,可以掃碼直接預(yù)覽效果。
準(zhǔn)備工作
新建一個項(xiàng)目,將已經(jīng)準(zhǔn)備好的資源,放入到項(xiàng)目中。下面是需要資源圖片的示例。
實(shí)現(xiàn)步驟以及思路
作為一個前端,看到東西總是想著去實(shí)現(xiàn)一下。感覺搖骰子簡單就實(shí)現(xiàn)一下,如果難的話,可能就不會出來了。哈哈,開始上正文。
首先開始思考搖骰子的流程,準(zhǔn)備狀態(tài)>>>晃動中狀態(tài)>>>等待開起狀態(tài)>>>開啟后狀態(tài)。
簡單的四步循環(huán),開整。
第一步:實(shí)現(xiàn)準(zhǔn)備狀態(tài)
實(shí)現(xiàn)準(zhǔn)備狀態(tài),我們要實(shí)現(xiàn)什么?
1、手機(jī)搖一搖后開始搖骰子
開整,頁面如何鋪設(shè)就不描述了代碼在最下面。
利用uni.onGyroscopeChange監(jiān)聽陀螺儀,根據(jù)陀螺儀變化的速率來判斷是否搖動了手機(jī),當(dāng)檢測到搖動手機(jī)號開始游戲,并停止監(jiān)聽陀螺儀。
實(shí)際情況中發(fā)現(xiàn),搖動幅度大持續(xù)時間長,會執(zhí)行多次。這里我想的是加個shakeState變量,監(jiān)聽到一次的時候就改變 shakeState,然后停止監(jiān)聽后開始游戲。
//監(jiān)聽陀螺儀
start() {
uni.onGyroscopeChange((res) => {
var nowRange = Math.abs(res.x) + Math.abs(res.x) + Math.abs(res.x);
if (nowRange > 10) {
this.shakeState = true
}
if(this.shakeState){
this.stop()
this.shakeState = false
this.playGame()
}
});
uni.startGyroscope({
interval: "normal"
})
},
//停止監(jiān)聽陀螺儀
stop() {
uni.stopGyroscope({})
},
第二步:實(shí)現(xiàn)晃動中狀態(tài)
實(shí)現(xiàn)晃動中狀態(tài),我們要實(shí)現(xiàn)什么?
1、整個骰盅晃動,發(fā)出搖骰子的聲音
骰盅晃動是通過vue中的**:class類樣式綁定,在代碼中寫了一個rollDiceAnimation**的樣式類實(shí)現(xiàn)一個動畫,然后判斷“gameType”的變量實(shí)現(xiàn)動畫。
<view class="diceCountent" :class="{'rollDiceAnimation':gameType == 1}">
</view>
聲音的是利用了“uni.createInnerAudioContext()”設(shè)置好自動播放,音頻文件地址,調(diào)用**onPlay()**方法實(shí)現(xiàn)聲音的播放。
const innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;
innerAudioContext.src = '/static/rollDice/dice.mp3';
innerAudioContext.onPlay(() => {});
第三步:等待開起狀態(tài)
實(shí)現(xiàn)晃動中狀態(tài),我們要實(shí)現(xiàn)什么?
1、上劃骰盅晃動,展示結(jié)果。
實(shí)現(xiàn)滑動,這里就不得不說下手指觸摸屏幕**“@touchstart”、觸摸移動“@touchmove”、手指離開屏幕“@touchend”這個三個事件。手指觸摸的時候記錄當(dāng)前pageY**的值,移動時算出移動的位置,改變骰盅的位置。手指離開后恢復(fù)原先的狀態(tài)。
原本想著,滑動骰盅直接展示結(jié)果,但是感覺太突然了。就使用“opacity”透明度顯得不那么突然。
<image class="maskbox" v-show="gameType != 3" :style="{'transform':'translate3d(0px,-'+yMove+'px,0)'}"
@touchstart="maskTouchStart" @touchmove.prevent="maskTouchMove" @touchend="maskTouchEnd"
src="../../static/rollDice/dice.png" mode=""></image>
// 開始觸摸屏幕
maskTouchStart(ev) {
this.YStart = ev.changedTouches[0].pageY
},
// 觸摸移動
maskTouchMove(ev) {
var result =0
if(this.gameType == 2){
result = parseInt(this.YStart - ev.changedTouches[0].pageY)
}
if(result > 0){
this.yMove = result
this.opacityShow = result/100
}
},
// 觸摸結(jié)束
maskTouchEnd(ev) {
this.yMove = 0
this.opacityShow = 0
},
第四步:開啟后狀態(tài)
開啟后狀態(tài),我們要實(shí)現(xiàn)什么?
1、結(jié)果骰子的展示。
畢竟6個骰子和20個骰子展示是不一樣的。這里先定好要展示位置的大小,然后通過骰子的個數(shù),來改變骰子圖片的大小
// 設(shè)置骰子位置前
setDice() {
var arr = []
// 生成坐標(biāo)數(shù)組
if (this.diceCount > 9) {
let pointSum = Math.floor(Math.sqrt(this.diceCount)) + 1
this.diceWidth = parseInt(240 / pointSum)
for (let i = 0; i < pointSum; i++) {
for (let k = 0; k < pointSum; k++) {
arr[arr.length] = {
top: i * this.diceWidth,
left: k * this.diceWidth
}
}
}
} else {
for (let i = 0; i < 3; i++) {
for (let k = 0; k < 3; k++) {
arr[arr.length] = {
top: i * 80,
left: k * 80
}
}
}
}
// 骰子位置以及角度
var dice, angle, temp, tempList
for (var i = 0; i < this.diceCount; i++) {
dice = (Math.random() * 6) >> 0
angle = (Math.random() * 6) >> 0
temp = (Math.random() * arr.length) >> 0;
// 讓數(shù)組不重復(fù)
tempList = arr[temp];
arr.splice(temp, 1)
this.addDiceList(dice, angle, tempList)
}
},
// 設(shè)置骰子
addDiceList(dice, angle, tempList) {
this.diceList.push({
"rotate": 30 * angle,
"dice": dice,
"top": tempList.top,
"left": tempList.left
})
},
部分優(yōu)化
總體的功能就實(shí)現(xiàn)了,為了更加完善。設(shè)置彈框、歷史開骰記錄、準(zhǔn)備狀態(tài)下顯示骰子數(shù)量、等待開起狀態(tài)開始陀螺儀監(jiān)聽可繼續(xù)搖。這就不多說了,具體的邏輯代碼都在下面。文章來源:http://www.zghlxwxcb.cn/news/detail-663663.html
代碼和我,只要一個能跑就行!文章來源地址http://www.zghlxwxcb.cn/news/detail-663663.html
總代碼
<template>
<view>
<!-- 背景 -->
<image class="gameBg" src="../../static/rollDice/gameBg.jpg" mode=""></image>
<view style="height: 60rpx;"></view>
<!-- 骰子 -->
<view class="diceCountent" :class="{'rollDiceAnimation':gameType == 1}">
<image src="../../static/rollDice/dicebg.png" class="bgimg" mode=""></image>
<view class="dicebox">
<view class="diceitem" v-for="(item,index) in diceList" :key="index" :style="{width:diceWidth+'rpx',height:diceWidth+'rpx',top:item.top+'rpx',left:item.left+'rpx',
transform:`rotate(${item.rotate}deg)`}">
<image :src="diceAll[item.dice].img" class="diceimg" mode=""></image>
</view>
</view>
<image class="maskbox" v-show="gameType != 3" :style="{'transform':'translate3d(0px,-'+yMove+'px,0)'}"
@touchstart="maskTouchStart" @touchmove.prevent="maskTouchMove" @touchend="maskTouchEnd"
src="../../static/rollDice/dice.png" mode=""></image>
<view v-show="gameType == 0" class="diceSumBox">
{{diceCount}}
</view>
<view v-show="gameType == 2" class="diceSumBox">
</view>
</view>
<!-- 總合計(jì) -->
<view style="height: 800rpx;"></view>
<!-- 按鈕-->
<view class="btnBox">
<view v-show="gameType == 0" @click="playGame()" class="startBtn">
搖一搖
</view>
<view v-show="gameType == 2" @click="openDice()" class="openBtn">
開
</view>
</view>
<!-- v-show="gameType == 3" -->
<view :style="{'opacity':opacityShow}" class="totalbox">
<text class="totalboxTitle">總點(diǎn)數(shù):{{point}}</text>
<view class="totaldicebox">
<view class="totaldiceItem">
<image src="../../static/rollDice/01.png" class="smallDiceimg" mode=""></image>
<text>X {{one}}</text>
</view>
<view class="totaldiceItem">
<image src="../../static/rollDice/03.png" class="smallDiceimg" mode=""></image>
<text>X {{thr}}</text>
</view>
<view class="totaldiceItem">
<image src="../../static/rollDice/05.png" class="smallDiceimg" mode=""></image>
<text>X {{fiv}}</text>
</view>
</view>
<view class="totaldicebox">
<view class="totaldiceItem">
<image src="../../static/rollDice/02.png" class="smallDiceimg" mode=""></image>
<text>X {{two}}</text>
</view>
<view class="totaldiceItem">
<image src="../../static/rollDice/04.png" class="smallDiceimg" mode=""></image>
<text>X {{fou}}</text>
</view>
<view class="totaldiceItem">
<image src="../../static/rollDice/06.png" class="smallDiceimg" mode=""></image>
<text>X {{six}}</text>
</view>
</view>
</view>
<view class="smallTipBox">
<text v-show="gameType == 2">上劃骰盅可提前查看結(jié)果</text>
<text v-show="gameType == 3">點(diǎn)擊右下角可重新開始</text>
</view>
<!-- 記錄 -->
<view class="footBox">
<image @click="setRecord()" src="../../static/rollDice/record.png" class="recordImg" mode=""></image>
<view v-show="gameType == 2" @click="playGame()" class="againBtn">
重
</view>
<view v-show="gameType == 3" @click="reface()" class="againBtn">
復(fù)
</view>
</view>
<view v-show="recordShow" class="recordBox">
<view @click="recordShow = false" class="closeBox">
X
</view>
<view class="title">
歷史開骰記錄
</view>
<view class="headTitle">
<view class="whead">總和</view>
<image src="../../static/rollDice/01.png" class="diceRecordimg" mode=""></image>
<image src="../../static/rollDice/02.png" class="diceRecordimg" mode=""></image>
<image src="../../static/rollDice/03.png" class="diceRecordimg" mode=""></image>
<image src="../../static/rollDice/04.png" class="diceRecordimg" mode=""></image>
<image src="../../static/rollDice/05.png" class="diceRecordimg" mode=""></image>
<image src="../../static/rollDice/06.png" class="diceRecordimg" mode=""></image>
</view>
<scroll-view scroll-y="true" class="diceContentBox">
<view v-for="(item,index) in recordList" :key="index" class="diceContent">
<text class="whead">{{item.point}}點(diǎn)</text>
<text>{{item.one}}個</text>
<text>{{item.two}}個</text>
<text>{{item.thr}}個</text>
<text>{{item.fou}}個</text>
<text>{{item.fiv}}個</text>
<text>{{item.six}}個</text>
</view>
</scroll-view>
</view>
<!-- 設(shè)置 -->
<!-- 左上角設(shè)置,可設(shè)置音樂,震動,篩子個數(shù),自動開 -->
<view @click="setBoxShow = true" class="setBtn">
<image src="../../static/set.png" mode=""></image>
</view>
<view v-show="setBoxShow" class="setBox">
<view @click="setBoxShow = false" class="closeBox">
X
</view>
<view class="title">
設(shè)置
</view>
<view @click="automated = !automated" class="handleBtn">
自動開骰:{{automated?'開啟':'關(guān)閉'}}
</view>
<view @click="musicshow = !musicshow" class="handleBtn">
聲音:{{musicshow?'開啟':'關(guān)閉'}}
</view>
<view @click="shakeShow = !shakeShow" class="handleBtn">
震動:{{shakeShow?'開啟':'關(guān)閉'}}
</view>
<view class="handleBtn setCountBox">
<text>骰子:</text>
<image @click="setcount()" src="../../static/rollDice/reduce.png" mode=""></image>
<text style="width: 100rpx;">{{diceCount}}</text>
<image @click="setcount('add')" src="../../static/rollDice/add.png" mode=""></image>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
shakeState:false, // 搖一搖
opacityShow:0, // 統(tǒng)計(jì)透明度
YStart:'', // 開始位置
yMove: 0,
setBoxShow: false, // 設(shè)置
musicshow: true, // 音樂
shakeShow:true, // 震動
automated: false, // 自動開
recordShow: false, // 記錄
gameType: 0, // 0:游戲準(zhǔn)備,1搖骰子中,2等待開篩子,3已經(jīng)開過篩子
point: 0,
one: 0,
two: 0,
thr: 0,
fou: 0,
fiv: 0,
six: 0,
diceCount: 6,
diceWidth: 70,
diceList: [],
diceAll: [{
img: '../../static/rollDice/01.png',
dicesum: 1
}, {
img: '../../static/rollDice/02.png',
dicesum: 2
}, {
img: '../../static/rollDice/03.png',
dicesum: 3
}, {
img: '../../static/rollDice/04.png',
dicesum: 4
}, {
img: '../../static/rollDice/05.png',
dicesum: 5
}, {
img: '../../static/rollDice/06.png',
dicesum: 6
}],
recordList: [],
}
},
onShow() {
// this.playGame()
this.start()
},
methods: {
// 開始觸摸屏幕
maskTouchStart(ev) {
this.YStart = ev.changedTouches[0].pageY
},
// 觸摸移動
maskTouchMove(ev) {
var result =0
if(this.gameType == 2){
result = parseInt(this.YStart - ev.changedTouches[0].pageY)
}
if(result > 0){
this.yMove = result
this.opacityShow = result/100
}
},
// 觸摸結(jié)束
maskTouchEnd(ev) {
this.yMove = 0
this.opacityShow = 0
},
//監(jiān)聽陀螺儀
start() {
uni.onGyroscopeChange((res) => {
var nowRange = Math.abs(res.x) + Math.abs(res.x) + Math.abs(res.x);
if (nowRange > 10) {
this.shakeState = true
}
if(this.shakeState){
this.stop()
this.shakeState = false
this.playGame()
}
});
uni.startGyroscope({
interval: "normal"
})
},
//停止監(jiān)聽陀螺儀
stop() {
uni.stopGyroscope({})
},
setcount(txt) {
if (txt == 'add') {
if (this.diceCount < 100) {
this.diceCount++
}
} else {
if (this.diceCount > 1) {
this.diceCount--
}
}
},
// 查看記錄
setRecord() {
this.recordShow = true
},
// 開起骰子
openDice() {
this.opacityShow = 1
this.gameType = 3
this.stop()
},
// 重置游戲
reface() {
this.opacityShow = 0
this.gameType = 0
this.diceList = []
this.recordList[this.recordList.length] = {
'point': this.point,
'one': this.one,
'two': this.two,
'thr': this.thr,
'fou': this.fou,
'fiv': this.fiv,
'six': this.six,
}
this.start()
},
// 開始游戲
playGame() {
this.diceList = []
// 震動
if(this.shakeShow){
uni.vibrateLong();
}
if(this.musicshow){
const innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;
innerAudioContext.src = '/static/rollDice/dice.mp3';
innerAudioContext.onPlay(() => {});
}
this.setDice()
this.diceCountDice()
this.gameType = 1
// 自動開骰
if (this.automated) {
setTimeout(() => {
this.gameType = 3
this.opacityShow = 1
}, 2000)
} else {
setTimeout(() => {
this.gameType = 2
this.start()
}, 2000)
}
},
// 設(shè)置骰子位置前
setDice() {
var arr = [] // 深拷貝
// 生成坐標(biāo)數(shù)組
if (this.diceCount > 9) {
let pointSum = Math.floor(Math.sqrt(this.diceCount)) + 1
this.diceWidth = parseInt(240 / pointSum)
for (let i = 0; i < pointSum; i++) {
for (let k = 0; k < pointSum; k++) {
arr[arr.length] = {
top: i * this.diceWidth,
left: k * this.diceWidth
}
}
}
} else {
for (let i = 0; i < 3; i++) {
for (let k = 0; k < 3; k++) {
arr[arr.length] = {
top: i * 80,
left: k * 80
}
}
}
}
var dice, angle, temp, tempList
for (var i = 0; i < this.diceCount; i++) {
dice = (Math.random() * 6) >> 0
angle = (Math.random() * 6) >> 0
temp = (Math.random() * arr.length) >> 0;
// 讓數(shù)組不重復(fù)
tempList = arr[temp];
arr.splice(temp, 1)
this.addDiceList(dice, angle, tempList)
}
},
// 設(shè)置骰子
addDiceList(dice, angle, tempList) {
this.diceList.push({
"rotate": 30 * angle,
"dice": dice,
"top": tempList.top,
"left": tempList.left
})
},
// 統(tǒng)計(jì)數(shù)量
diceCountDice() {
this.one = 0
this.two = 0
this.thr = 0
this.fou = 0
this.fiv = 0
this.six = 0
let sum = 0
this.diceList.forEach((item) => {
sum = sum + item.dice + 1
switch (item.dice) {
case 0:
this.one++;
break;
case 1:
this.two++;
break;
case 2:
this.thr++;
break;
case 3:
this.fou++;
break;
case 4:
this.fiv++;
break;
case 5:
this.six++;
break;
}
})
this.point = sum
}
}
}
</script>
<style lang="scss">
.gameBg {
position: fixed;
width: 750rpx;
height: 100vh;
}
/* 骰子 */
.diceCountent {
position: absolute;
left: 130rpx;
padding-top: 60rpx;
.bgimg {
position: absolute;
top: 270rpx;
width: 500rpx;
height: 520rpx;
}
.dicebox {
position: relative;
top: 330rpx;
margin-left: 110rpx;
z-index: 10;
}
.diceitem {
position: absolute;
}
.diceimg {
width: 100%;
height: 100%;
}
.maskbox {
position: absolute;
margin-left: 40rpx;
width: 430rpx;
height: 600rpx;
z-index: 10;
}
.diceSumBox {
position: absolute;
top: 340rpx;
margin-left: 40rpx;
font-size: 160rpx;
font-weight: bold;
color: #d2d1d9;
z-index: 10;
width: 430rpx;
text-align: center;
}
}
.rollDiceAnimation {
animation: moveRoll 1.2s;
}
@keyframes moveRoll {
0% {
left: 130rpx;
}
5% {
left: 0rpx;
}
15% {
left: 260rpx;
}
25% {
left: 0rpx;
}
35% {
left: 260rpx;
}
45% {
left: 0rpx;
}
55% {
left: 260rpx;
}
65% {
left: 0rpx;
}
75% {
left: 260rpx;
}
85% {
left: 0rpx;
}
95% {
left: 260rpx;
}
100% {
left: 130rpx;
}
}
// 結(jié)果統(tǒng)計(jì)
.totalbox {
color: #FFFFFF;
display: flex;
flex-direction: column;
align-items: center;
width: 640rpx;
border-radius: 30rpx;
margin: 10rpx auto 0;
padding: 0 20rpx 10rpx;
border: 6rpx #7b422e solid;
// background: linear-gradient(#FFFFFF, #0ba952);
position: relative;
.totalboxTitle {
font-size: 50rpx;
line-height: 100rpx;
}
.smallDiceimg {
width: 80rpx;
height: 80rpx;
}
.totaldicebox {
display: flex;
width: 100%;
padding: 10rpx 0;
}
.totaldiceItem {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.totaldiceItem text {
margin-left: 10rpx;
font-size: 42rpx;
}
}
.btnBox {
display: flex;
justify-content: center;
position: relative;
text-align: center;
z-index: 10;
font-size: 46rpx;
.startBtn {
width: 200rpx;
border: 2rpx #f6f6f7 solid;
color: #FFFFFF;
padding: 0 60rpx;
line-height: 80rpx;
border-radius: 40rpx;
background: #303038;
}
.openBtn {
font-size: 54rpx;
line-height: 160rpx;
text-align: center;
width: 160rpx;
height: 160rpx;
border-radius: 100rpx;
border: 2rpx #f6f6f7 solid;
color: #FFFFFF;
background: #303038;
}
}
// 歷史記錄
.recordBox {
position: fixed;
bottom: 0;
width: 670rpx;
height: 60vh;
z-index: 10;
background: #faf5ec;
border: 10rpx #755345 solid;
padding: 20rpx 30rpx;
border-radius: 50rpx 50rpx 0 0;
.title {
width: 100%;
font-weight: bold;
line-height: 120rpx;
font-size: 40rpx;
text-align: center;
}
.closeBox {
position: absolute;
right: 0;
top: 0;
font-size: 40rpx;
font-weight: bold;
padding: 20rpx 30rpx;
}
.headTitle {
display: flex;
align-items: center;
justify-content: space-around;
.whead {
font-weight: bold;
text-align: center;
width: 110rpx;
}
.diceRecordimg {
width: 54rpx;
height: 54rpx;
}
}
.diceContentBox {
height: 40vh;
margin-top: 20rpx;
overflow: hidden;
border: 2rpx #c1c1c1 solid;
}
.diceContent {
display: flex;
align-items: center;
color: #333333;
justify-content: space-around;
line-height: 70rpx;
border-bottom: 2rpx #999 solid;
.whead {
text-align: center;
width: 110rpx;
}
text {
width: 54rpx;
text-align: center;
}
}
}
.footBox {
position: fixed;
width: 650rpx;
display: flex;
justify-content: space-between;
bottom: 50rpx;
left: 50rpx;
.recordImg {
width: 90rpx;
height: 90rpx;
}
.againBtn {
color: #FFFFFF;
font-size: 40rpx;
text-align: center;
font-weight: bold;
width: 90rpx;
line-height: 90rpx;
height: 90rpx;
border-radius: 100rpx;
border: 6rpx #FFFFFF solid;
}
}
// 設(shè)置
.setBtn {
position: fixed;
top: 80rpx;
left: 40rpx;
image {
width: 80rpx;
height: 80rpx;
}
}
.setBox {
z-index: 10;
position: fixed;
top: 26vh;
left: 110rpx;
color: #442e27;
border: 10rpx #755345 solid;
border-radius: 30rpx;
padding: 0 50rpx 50rpx 50rpx;
background: #faf5ec;
.title {
width: 100%;
font-weight: bold;
line-height: 140rpx;
font-size: 40rpx;
text-align: center;
}
.handleBtn {
border-radius: 30rpx;
font-size: 34rpx;
font-weight: bold;
line-height: 70rpx;
text-align: center;
width: 400rpx;
background: #f7d16a;
border: 6rpx #6c5447 solid;
margin-bottom: 20rpx;
}
.closeBox {
position: absolute;
right: 0;
font-size: 40rpx;
font-weight: bold;
padding: 10rpx 20rpx;
}
.setCountBox {
display: flex;
align-items: center;
justify-content: center;
image {
width: 40rpx;
height: 40rpx;
padding: 0 10rpx;
}
}
}
.smallTipBox{
position: relative;
color: #FFFFFF;
font-size: 36rpx;
line-height: 120rpx;
width: 100%;
text-align: center;
}
</style>
到了這里,關(guān)于搖骰子設(shè)計(jì)與實(shí)現(xiàn)(uni-app微信小程序)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!