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>
posted @ 2024-09-12 10:06  风雪中de冲破  阅读(48)  评论(0)    收藏  举报