uniapp js 划消小游戏
1.效果图

代码:game.vue
<template>
<view class="wrap">
<!-- <img class="imgBG" src="@/static/image/hxBG.png" alt="" /> -->
<image class="imgBG" mode="aspectFill" src="@/static/image/hxBG.png" />
<view class="content">
<view class="header">
<view class="time">
<text class="name">时间</text>
<text class="name">{{ startTime }}</text>
</view>
<view class="fraction">
<text class="name">分数</text>
<up-count-to :startVal="0" :endVal="countValue"></up-count-to>
</view>
</view>
<view class="targetWrap">
<view class="title">目标数字</view>
<text class="num">{{ randomNum }}</text>
</view>
<view class="searchTitle">找到目标数字并划消:</view>
<view class="listWrap">
<view class="listBg"></view>
<view class="listBgTwo"></view>
<view
:class="[
'listWraps cf',
sdNum == 4
? 'listWrapsFour'
: sdNum == 5
? 'listWrapsFive'
: sdNum == 6
? 'listWrapsSix'
: ''
]"
v-if="sdNum == 4 || sdNum == 5 || sdNum == 6"
>
<view
:class="['items', item.active == 'on' ? 'on' : item.active == 'error' ? 'error' : '']"
@click="fillIn(item, index)"
v-for="(item, index) in rightList"
:key="index"
>
{{ item.num }}
</view>
</view>
<view class="listWraps empty listWrapsFour cf" v-else>
<view class="items" v-for="(item, index) in 16" :key="index"> {{ index + 1 }}</view>
</view>
</view>
</view>
<view class="zhezhao" v-if="zhezhaoShow">
<text class="bg" />
<view class="zhezhaoWrap" v-if="chooseShow">
<view class="title">选择难度</view>
<view class="btnWrap">
<view class="btn" @click="chooseLevel(4)">
<img class="img" src="@/static/image/hxBtn.png" alt="" />
<text class="name">简 单</text>
</view>
<view class="btn" @click="chooseLevel(5)">
<img class="img" src="@/static/image/hxBtn.png" alt="" />
<text class="name">普 通</text>
</view>
<view class="btn" @click="chooseLevel(6)">
<img class="img" src="@/static/image/hxBtn.png" alt="" />
<text class="name">困 难</text>
</view>
</view>
</view>
<view class="startGame" v-else>
<view class="btnWrap">
<view class="btn" @click="startGameFun">
<img class="img" src="@/static/image/hxBtn.png" alt="" />
<text class="name">开始游戏</text>
</view>
</view>
</view>
</view>
<view
:class="['zhezhao zhezhaoState', zhezhaoShowState == true ? 'on' : '']"
class="zhezhao zhezhaoState"
v-if="zhezhaoShowState"
>
<text class="bg" />
<view class="zhezhaoStateWrap">
<view>
<view class="title">完成训练!</view>
<view class="consuming">
<text class="name"></text>
<up-count-to :startVal="0" :endVal="countTotalValue"></up-count-to>
<text class="name mr24">分</text>
</view>
</view>
<view class="btnWrap">
<view class="btn" @click="trainAgain(1)">
<img class="img" src="@/static/image/hxBtn.png" alt="" />
<text class="name">再次训练</text>
</view>
<view class="btn" @click="trainAgain(2)">
<img class="img" src="@/static/image/hxBtn.png" alt="" />
<text class="name">退出训练</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { onShow, onUnload } from '@dcloudio/uni-app'
//选择难度
const zhezhaoShow = ref(true)
const chooseShow = ref(true)
const sdNum = ref(0)
const sdNumOld = ref(0)
const countValue = ref(0)
const countTotalValue = ref(0)
// 随机值
const randomNum = ref(1)
const rightList = ref([])
const zhezhaoShowState = ref(false)
const repeatAllNum = ref(0)
const repeatStartActive = ref(0)
const repeatActiveNum = ref(0)
// 高亮
const activeOn = ref(null)
const activeOnTwo = ref(null)
const timmerActive = ref(null)
// 重复的随机值 次数
const repeatNum = ref(0)
// 倒计时时间 判断是否暂停
const goToState = ref(false)
const timmer = ref(null)
const startTime = ref('03 : 00')
const stopTime = ref(0)
const newDateTime = ref(0)
onShow(() => {
const game3Hide = uni.getStorageSync('game3Hide')
if (game3Hide && game3Hide == 'true') {
console.log(game3Hide)
} else {
zhezhaoShow.value = true
startTime.value = '03 : 00'
countValue.value = 0
randomNum.value = 1
timmer.value = null
sdNum.value = 0
sdNumOld.value = 0
rightList.value = []
goToState.value = false
chooseShow.value = true
repeatNum.value = 0
stopTime.value = 0
newDateTime.value = 0
zhezhaoShowState.value = false
repeatAllNum.value = 0
repeatActiveNum.value = 0
activeOn.value = null
activeOnTwo.value = null
timmerActive.value = null
repeatStartActive.value = 0
}
})
onUnload(() => {
clearInterval(timmer.value)
timmer.value = null
uni.removeStorageSync('game3Hide')
})
const chooseLevel = (num) => {
chooseShow.value = false
sdNumOld.value = num
}
const startGameFun = () => {
zhezhaoShow.value = false
sdNum.value = sdNumOld.value
if (sdNum.value == 4) {
repeatAllNum.value = 6
repeatActiveNum.value = 6
} else if (sdNum.value == 5) {
repeatAllNum.value = 10
repeatActiveNum.value = 10
} else {
repeatAllNum.value = 14
repeatActiveNum.value = 14
}
generateShuDu()
startGame()
}
const playVideo = (str) => {
const maps = {
point: '/static/video/point.mp3',
empty: '/static/video/empty.mp3',
success: '/static/video/success.mp3'
}
let innerAudioContext = uni.createInnerAudioContext()
innerAudioContext.autoplay = true
innerAudioContext.src = maps[str]
innerAudioContext.onPlay(() => {
console.log('开始播放')
})
innerAudioContext.onEnded(() => {
innerAudioContext.destroy()
innerAudioContext = null
})
}
// 初始化数独
const generateArr = () => {
const arr = []
if (sdNum.value == 4 || sdNum.value == 5) {
for (let i = 0; i < sdNum.value; i++) {
arr[i] = []
for (let j = 0; j < sdNum.value; j++) {
arr[i][j] = Math.floor(Math.random() * 9) + 1
}
}
} else {
for (let i = 0; i < sdNum.value; i++) {
arr[i] = []
for (let j = 0; j < 5; j++) {
arr[i][j] = Math.floor(Math.random() * 9) + 1
}
}
}
return arr
}
const generateShuDu = () => {
const arr = generateArr()
const duplicateRemoval = []
let repeatNum = 0
const randomValue = Math.floor(Math.random() * 9) + 1
randomNum.value = randomValue
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
let obj = {
active: '',
isRead: false,
disabled: false
}
//当前是 4*4
if (sdNum.value == 4) {
if (arr[i][j] == randomValue) {
if (repeatNum >= repeatAllNum.value) {
let number = Math.floor(Math.random() * 9) + 1
if (number == randomValue) {
if (randomValue == sdNum.value) {
obj.num = Number(sdNum.value) - 1
} else {
obj.num = sdNum.value
}
duplicateRemoval.push(obj)
} else {
obj.num = number
duplicateRemoval.push(obj)
}
} else {
repeatNum = repeatNum + 1
obj.num = arr[i][j]
duplicateRemoval.push(obj)
}
} else {
obj.num = arr[i][j]
duplicateRemoval.push(obj)
}
} else if (sdNum.value == 5) {
if (arr[i][j] == randomValue) {
if (repeatNum >= repeatAllNum.value) {
let number = Math.floor(Math.random() * 9) + 1
if (number == randomValue) {
if (randomValue == sdNum.value) {
obj.num = Number(sdNum.value) - 1
} else {
obj.num = sdNum.value
}
duplicateRemoval.push(obj)
} else {
obj.num = number
duplicateRemoval.push(obj)
}
} else {
repeatNum = repeatNum + 1
obj.num = arr[i][j]
duplicateRemoval.push(obj)
}
} else {
obj.num = arr[i][j]
duplicateRemoval.push(obj)
}
} else {
if (arr[i][j] == randomValue) {
if (repeatNum >= repeatAllNum.value) {
let number = Math.floor(Math.random() * 9) + 1
if (number == randomValue) {
if (randomValue == sdNum.value) {
obj.num = Number(sdNum.value) - 1
} else {
obj.num = sdNum.value
}
duplicateRemoval.push(obj)
} else {
obj.num = number
duplicateRemoval.push(obj)
}
} else {
repeatNum = repeatNum + 1
obj.num = arr[i][j]
duplicateRemoval.push(obj)
}
} else {
obj.num = arr[i][j]
duplicateRemoval.push(obj)
}
}
}
}
sortFun(duplicateRemoval, repeatNum)
}
// 数据去重和排序
const sortFun = (duplicateRemoval, repeatNum) => {
let duplicateRemovalSort = JSON.parse(JSON.stringify(duplicateRemoval))
let repeatNumSort = repeatNum
if (sdNum.value == 4) {
if (repeatNumSort < repeatAllNum.value) {
for (let i = 0; i < duplicateRemovalSort.length; i++) {
if (repeatNumSort >= repeatAllNum.value) {
rightList.value = randomsort(duplicateRemovalSort)
return false
} else {
if (duplicateRemovalSort[i].num != randomNum.value) {
duplicateRemovalSort[i].num = randomNum.value
repeatNumSort = repeatNumSort + 1
}
}
}
}
} else if (sdNum.value == 5) {
if (repeatNumSort < repeatAllNum.value) {
for (let i = 0; i < duplicateRemovalSort.length; i++) {
if (repeatNumSort >= repeatAllNum.value) {
rightList.value = randomsort(duplicateRemovalSort)
return false
} else {
if (duplicateRemovalSort[i].num != randomNum.value) {
duplicateRemovalSort[i].num = randomNum.value
repeatNumSort = repeatNumSort + 1
}
}
}
}
} else {
if (repeatNumSort < repeatAllNum.value) {
for (let i = 0; i < duplicateRemovalSort.length; i++) {
if (repeatNumSort >= repeatAllNum.value) {
rightList.value = randomsort(duplicateRemovalSort)
return false
} else {
if (duplicateRemovalSort[i].num != randomNum.value) {
duplicateRemovalSort[i].num = randomNum.value
repeatNumSort = repeatNumSort + 1
}
}
}
}
}
return true
}
// 数组随机
const randomsort = (list) => {
let arr = JSON.parse(JSON.stringify(list))
for (var i = 0, len = arr.length; i < len; i++) {
var rand = parseInt(Math.random() * len)
var temp = arr[rand]
arr[rand] = arr[i]
arr[i] = temp
}
return arr
}
// 点击开始计时
const startGame = () => {
if (goToState.value == false) {
goToState.value = true
clearInterval(timmer.value)
timmer.value = null
startTime.value = '03 : 00'
stopTime.value = new Date().getTime() + 3 * 60 * 1000
// stopTime.value = new Date().getTime() + 10 * 1000
timmer.value = setInterval(() => {
newDateTime.value = stopTime.value - new Date().getTime()
if (newDateTime.value <= 1) {
startTime.value = '00 : 00'
goToState.value = false
clearInterval(timmer.value)
timmer.value = null
zhezhaoShowState.value = true
countTotalValue.value = countValue.value
console.log('游戏超时自动结束')
} else {
startTime.value = transformTime(newDateTime.value)
}
}, 1000)
}
}
// 点击结束 计算分数
// const endGame = () => {
// if (goToState.value == true) {
// goToState.value = false
// clearInterval(timmer.value)
// timmer.value = null
// const residueTime = transformTime(newDateTime.value, 'stop')
// console.log('剩余时间:', residueTime)
// }
// }
// 时间转换
const transformTime = (date, state) => {
var datetime = ''
//计算出小时数
var leave1 = date % (24 * 3600 * 1000) //计算天数后剩余的毫秒数
//计算相差分钟数
var leave2 = leave1 % (3600 * 1000) //计算小时数后剩余的毫秒数
var minutes =
Math.floor(leave2 / (60 * 1000)) < 10
? '0' + Math.floor(leave2 / (60 * 1000))
: Math.floor(leave2 / (60 * 1000))
//计算相差秒数
var leave3 = leave2 % (60 * 1000) //计算分钟数后剩余的毫秒数
var seconds =
Math.round(leave3 / 1000) < 10 ? '0' + Math.round(leave3 / 1000) : Math.round(leave3 / 1000)
if (state == 'stop') {
const secondsNum = Number(seconds) + Number(minutes) * 60
return secondsNum
} else {
datetime = minutes + ' : ' + seconds
return datetime
}
}
const fillIn = (item, index) => {
activeOn.value = index
if (activeOn.value !== activeOnTwo.value) {
clearTimeout(timmerActive.value)
timmerActive.value = null
if (activeOnTwo.value != null) {
rightList.value[activeOnTwo.value].active = ''
rightList.value[activeOnTwo.value].isRead = false
}
}
if (item.disabled == false && item.isRead == false) {
item.isRead = true
activeOnTwo.value = index
if (item.num == randomNum.value) {
activeOn.value = null
activeOnTwo.value = null
item.isRead = false
item.disabled = true
item.active = 'on'
repeatStartActive.value++
countValue.value = Number(countValue.value) + 10
if (Number(repeatStartActive.value) == Number(repeatActiveNum.value)) {
playVideo('success')
zhezhaoShowState.value = true
clearInterval(timmer.value)
timmer.value = null
const residueTime = transformTime(newDateTime.value, 'stop')
countTotalValue.value = countValue.value + Number((residueTime / 10).toFixed(0))
} else {
playVideo('point')
}
} else {
if (Number(countValue.value) - 5 <= 0) {
countValue.value = 0
} else {
countValue.value = Number(countValue.value) - 5
}
playVideo('empty')
item.active = 'error'
timmerActive.value = setTimeout(() => {
rightList.value[activeOnTwo.value].active = ''
rightList.value[activeOnTwo.value].isRead = false
activeOn.value = null
activeOnTwo.value = null
}, 1600)
}
}
}
const trainAgain = (num) => {
if (num == 1) {
zhezhaoShow.value = true
startTime.value = '03 : 00'
countValue.value = 0
randomNum.value = 1
timmer.value = null
sdNum.value = 0
sdNumOld.value = 0
rightList.value = []
goToState.value = false
chooseShow.value = true
repeatNum.value = 0
stopTime.value = 0
newDateTime.value = 0
zhezhaoShowState.value = false
repeatAllNum.value = 0
repeatActiveNum.value = 0
activeOn.value = null
activeOnTwo.value = null
timmerActive.value = null
repeatStartActive.value = 0
} else {
uni.reLaunch({
url: '/pages/index/index'
})
}
}
</script>
<style lang="scss" scoped>
.cf {
zoom: 1;
}
.cf::after {
content: '.';
display: block;
visibility: hidden;
height: 0;
clear: both;
font-size: 0;
}
@keyframes rotate {
from {
opacity: 0;
transform: scale(0);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes rotate-two {
0% {
transform: scale(0.9);
}
50% {
transform: scale(1);
}
100% {
transform: scale(0.9);
}
}
@keyframes error-active {
0% {
background: #fdf9f1;
}
25% {
background: #ffd2d2;
}
50% {
background: #fdf9f1;
}
75% {
background: #ffd2d2;
}
100% {
background: #fdf9f1;
}
}
.wrap {
width: 100%;
height: 100vh;
position: relative;
background: #d7f5f5;
text-align: center;
.imgBG {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.content {
position: relative;
z-index: 1;
width: calc(100% - 96rpx);
height: 100%;
display: inline-block;
text-align: left;
.header {
margin-top: 48rpx;
color: #065f43;
font-weight: 700;
font-size: 48rpx;
position: relative;
.time {
.name {
display: inline-block;
vertical-align: middle;
&:nth-child(1) {
margin-right: 16rpx;
}
}
}
.fraction {
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
.name {
display: inline-block;
vertical-align: middle;
margin-right: 16rpx;
}
::v-deep .u-count-num {
display: inline-block;
vertical-align: middle;
color: #065f43 !important;
font-weight: 700 !important;
font-size: 48rpx !important;
}
}
}
.targetWrap {
margin-top: 48rpx;
text-align: center;
height: 294rpx;
border: 8rpx solid #035f42;
border-radius: 24rpx;
font-weight: 700;
position: relative;
.title {
margin-top: 16rpx;
color: #013726;
font-size: 40rpx;
}
.num {
font-size: 208rpx;
color: #013726;
position: absolute;
top: 30rpx;
left: 50%;
transform: translateX(-50%);
}
}
.searchTitle {
font-size: 40rpx;
color: #013726;
font-weight: 700;
margin: 22rpx 0;
}
.listWrap {
position: relative;
.listBg {
position: absolute;
left: 50%;
transform: translateX(-50%);
top: -8rpx;
width: 688rpx;
height: 798rpx;
background: #035f42;
padding: 8rpx;
border-radius: 24rpx;
z-index: -1;
}
.listBgTwo {
position: absolute;
left: calc(50% + 16rpx);
top: 8rpx;
width: 668rpx;
height: 798rpx;
background: #408754;
transform: translateX(-50%);
padding: 8rpx;
z-index: -2;
border-radius: 32rpx;
}
.listWraps {
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 0;
width: 672rpx;
font-size: 0;
text-align: left;
background: #447968;
border-radius: 24rpx;
.items {
font-size: 76rpx;
font-weight: 700;
text-align: center;
background: #fdf9f1;
border: 1rpx solid #035f42;
border-radius: 16rpx;
float: left;
position: relative;
&.error {
border-color: red;
animation: error-active 1.5s forwards;
}
&.on {
background: #9abfb3;
&::after {
content: '';
position: absolute;
top: 50%;
left: 8%;
transform: translateY(-50%);
width: 84%;
height: 6rpx;
background: #035f42;
border-radius: 6rpx;
}
}
}
&.empty {
color: #fdf9f1;
}
&.listWrapsFour {
.items {
width: calc(25% - 2rpx);
margin: 1rpx 2rpx 0 0;
line-height: 191rpx;
}
}
&.listWrapsFive,
&.listWrapsSix {
.items {
width: calc(20% - 2rpx);
margin: 1rpx 2rpx 0 0;
line-height: 152rpx;
}
}
&.listWrapsSix {
.items {
line-height: 126rpx;
}
}
}
}
}
.zhezhao {
position: relative;
width: 100%;
height: 100vh;
z-index: 1;
.bg {
position: fixed;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100vh;
background: rgb(0 0 0 / 50%);
}
.zhezhaoWrap {
position: fixed;
top: 280rpx;
left: 116rpx;
z-index: 1;
width: calc(100% - 232rpx);
font-size: 48rpx;
color: #fff;
text-align: center;
.btnWrap {
margin-top: 128rpx;
.btn {
position: relative;
height: 142rpx;
margin-top: 50rpx;
line-height: 122rpx;
text-align: center;
animation: rotate-two 1s infinite;
&:nth-child(1) {
margin-top: 0;
}
.img {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 100%;
height: 100%;
}
.name {
position: relative;
z-index: 1;
}
}
}
}
.startGame {
position: fixed;
bottom: 300rpx;
left: 116rpx;
z-index: 1;
width: calc(100% - 232rpx);
font-size: 48rpx;
color: #fff;
text-align: center;
.btnWrap {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
.btn {
position: relative;
height: 142rpx;
margin-top: 50rpx;
line-height: 122rpx;
text-align: center;
animation: rotate-two 1s infinite;
&:nth-child(1) {
margin-top: 0;
}
.img {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 100%;
height: 100%;
}
.name {
position: relative;
z-index: 1;
}
}
}
}
&.zhezhaoState {
position: fixed;
top: 0;
left: 0;
.bg {
background: rgb(0 0 0 / 70%);
}
.zhezhaoStateWrap {
position: fixed;
top: 184rpx;
left: 0;
z-index: 1;
width: 100%;
font-size: 64rpx;
color: #fff;
text-align: center;
.consuming {
margin-top: 112rpx;
font-size: 48rpx;
.name {
&.mr24 {
margin-right: 24rpx;
}
&.ml24 {
margin-left: 24rpx;
}
}
::v-deep .u-count-num {
font-size: 240rpx !important;
font-weight: 700 !important;
color: #fff !important;
}
}
.btnWrap {
width: calc(100% - 232rpx);
margin: 128rpx auto 0;
.btn {
position: relative;
height: 142rpx;
margin-top: 50rpx;
line-height: 110rpx;
text-align: center;
animation: rotate-two 1s infinite;
&:nth-child(1) {
margin-top: 0;
}
.img {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 100%;
height: 100%;
}
.name {
position: relative;
z-index: 1;
font-size: 48rpx;
}
}
}
}
&.on {
animation: rotate 0.3s linear;
}
}
}
}
</style>

浙公网安备 33010602011771号