zoukankan      html  css  js  c++  java
  • 2048小游戏源码(vue自定义指令使用)

    不多说,直接上代码

    <template>
      <div class="gameMain">
        <div class="gameName">2048小游戏</div>
        <div class="maxScore">
          最高分:<span id="maxScore">{{ maxScore }}</span>
        </div>
        <div class="col-sm-3 col-md-4"></div>
        <div class="gameBody col-sm-6 col-md-4" id="gameBody" v-touch:left="move" v-touch:right="move" v-touch:up="move" v-touch:down="move">
          <div class="row" v-for="(row, index) in gameList" :key="index">
            <div
              class="item"
              :style="{ background: refreshColorData[item.num] }"
              v-for="(item, idx) in row"
              :key="idx"
            >
              {{ item ? item.num : null }}
            </div>
          </div>
        </div>
        <div class="col-sm-4 col-md-4 gameDirection">
          <span @click="move('up')">上</span>
          <span @click="move('down')">下</span>
          <span @click="move('left')">左</span>
          <span @click="move('right')">右</span>
        </div>
        <div class="scoreAndRefresh col-sm-6 col-md-6">
          <div class="gameScore ">
            得分:<span id="gameScore">{{ gameScore }}</span> 分
          </div>
          <div class="btn btn-danger refreshBtn" @click="refreshGame">刷新</div>
        </div>
    
       <div class="gameOver" v-if="gameOver">游戏结束</div>
      </div>
    </template>
    
    <script>
    import touch from './directives.js'
    export default {
      name: 'Games',
      directives: { touch },
      data () {
        return {
          refreshColorData: {
            2: 'rgb(250, 225, 188)',
            4: 'rgb(202, 240, 240)',
            8: 'rgb(117, 231, 193)',
            16: 'rgb(240, 132, 132)',
            32: 'rgb(181, 240, 181)',
            64: 'rgb(182, 210, 246)',
            128: 'rgb(255, 207, 126)',
            256: 'rgb(250, 216, 216)',
            521: 'rgb(124, 183, 231)',
            1024: 'rgb(225, 219, 215)',
            2048: 'rgb(221, 160, 221)',
            4096: 'rgb(250, 139, 176)'
          },
          gameOver: false,
          gameScore: 0,
          maxScore: 0, // 最高分
          gameList: null,
          isNewRndItem: false //   // 是否产生新元素
        }
      },
      created () {
        this.gameList = this.matrix(4, 4, null)
        // 游戏初始化
        this.gameInit()
      },
      methods: {
        gameInit () {
          // 初始化分数
          this.gameScore = 0
          this.gameScore = 0
          // 最大分值
          if (localStorage.getItem('maxScore')) {
            this.maxScore = localStorage.getItem('maxScore') - 0
          } else {
            this.maxScore = 0
          }
          // 随机生成两个新元素
          this.newRndItem()
          this.newRndItem()
        },
        move (direction) {
          if (this.gameOver) return false
          // 获取所有非空元素
          let nonEmptyItems = [].concat
            .apply([], this.gameList)
            .filter(item => item.num !== null)
          // 如果按下的方向是左或上,则正向遍历非空元素
          if (direction === 'left' || direction === 'up') {
            for (let i = 0; i < nonEmptyItems.length; i++) {
              let currentItem = nonEmptyItems[i]
              this.itemMove(currentItem, direction)
            }
          } else if (direction === 'right' || direction === 'down') {
            // 如果按下的方向是右或下,则反向遍历非空元素
            for (let i = nonEmptyItems.length - 1; i >= 0; i--) {
              let currentItem = nonEmptyItems[i]
              this.itemMove(currentItem, direction)
            }
          }
          // 是否产生新元素
          if (this.isNewRndItem && !this.gameOver) {
            this.newRndItem()
          }
          this.isGameOver()
        },
        getSideItem (current, direction) {
          let sideItemX = current.id.substr(0, 1)
          let sideItemY = current.id.slice(1, 2)
          let falg
          switch (direction) {
            case 'left':
              falg = sideItemX > 0
              sideItemX = falg ? Number(sideItemX) - 1 : sideItemX
              break
            case 'right':
              falg = sideItemX < 3
              sideItemX = falg ? Number(sideItemX) + 1 : sideItemX
              break
            case 'up':
              falg = sideItemY > 0
              sideItemY = falg ? Number(sideItemY) - 1 : sideItemY
              break
            case 'down':
              falg = sideItemY < 3
              sideItemY = falg ? Number(sideItemY) + 1 : sideItemY
              break
          }
          let currentId = sideItemX + sideItemY
          let currentItem = falg
            ? [].concat(...this.gameList).filter(item => item.id === currentId)[0]
            : null
          // 判断移动方向是否有空位
          return currentItem
        },
        itemMove (currentItem, direction) {
          var sideItem = this.getSideItem(currentItem, direction)
          // 当前元素在最边上
          if (sideItem === null) return false
          // 当前元素不在最后一个且左(右、上、下)侧元素是空元素
          if (sideItem.num === null) {
            this.setGameList(sideItem, currentItem.num)
            sideItem.num = currentItem.num
            currentItem.num = null
            this.itemMove(sideItem, direction)
            this.isNewRndItem = true
          } else if (sideItem.num === currentItem.num) {
            sideItem.num = Number(currentItem.num) * 2
            currentItem.num = null
            this.gameScore += Number(sideItem.num) * 10
            this.maxScore =
              this.maxScore < this.gameScore ? this.gameScore : this.maxScore
            localStorage.setItem('maxScore', this.maxScore)
            this.itemMove(sideItem, direction)
            this.isNewRndItem = true
          }
        },
        // 游戏是否结束
        isGameOver () {
          let nonEmptyItems = [].concat
            .apply([], this.gameList)
            .filter(item => item.num !== null)
          let Items = [].concat
            .apply([], this.gameList)
          let gameOver = true
          if (Items.length === nonEmptyItems.length) { // 所有元素的个数 == 所有非空元素的个数  即没有空元素
            nonEmptyItems.forEach(currentItem => {
              // let up = this.getSideItem(currentItem, 'up') && this.getSideItem(currentItem, 'up').num
              // let down = this.getSideItem(currentItem, 'down') && this.getSideItem(currentItem, 'down').num
              // let left = this.getSideItem(currentItem, 'left') && this.getSideItem(currentItem, 'left').num
              // let right = this.getSideItem(currentItem, 'right') && this.getSideItem(currentItem, 'right').num
              // console.log(up + 'up' + down + 'down' + left + 'left' + right + 'right')
              // alert(currentItem.num + 'up' + this.getSideItem(currentItem, 'up').num + 'down' + this.getSideItem(currentItem, 'down').num + 'left' + this.getSideItem(currentItem, 'left').num + 'right' + this.getSideItem(currentItem, 'right').num)
              if (this.getSideItem(currentItem, 'up') && currentItem.num === this.getSideItem(currentItem, 'up').num) {
                gameOver = false
              } else if (this.getSideItem(currentItem, 'down') && currentItem.num === this.getSideItem(currentItem, 'down').num) {
                gameOver = false
              } else if (this.getSideItem(currentItem, 'left') && currentItem.num === this.getSideItem(currentItem, 'left').num) {
                gameOver = false
              } else if (this.getSideItem(currentItem, 'right') && currentItem.num === this.getSideItem(currentItem, 'right').num) {
                gameOver = false
              }
            })
          } else {
            gameOver = false
          }
          this.gameOver = gameOver
        },
        // 随机生成新数字
        newRndItem () {
          var newRndArr = [2, 2, 4]
          var newRndNum = newRndArr[this.getRandom(0, 2)]
          let emptyItemList = [].concat
            .apply([], this.gameList)
            .filter(item => item.num === null)
          var newRndSite = this.getRandom(0, emptyItemList.length - 1)
          var emptyItem = emptyItemList[newRndSite]
          this.setGameList(emptyItem, newRndNum)
        },
        // 设置数字
        setGameList (item, num) {
          if (!item) return false
          for (var row = 0; row < this.gameList.length; ++row) {
            for (var col = 0; col < this.gameList[row].length; ++col) {
              if (this.gameList[row][col].id === item.id) {
                this.gameList[row][col].num = num
              }
            }
          }
        },
        // 产生随机数,包括min、max
        getRandom (min, max) {
          return min + Math.floor(Math.random() * (max - min + 1))
        },
        // 刷新操作
        refreshGame () {
          this.gameList = this.matrix(4, 4, null)
          this.gameOver = false
          // 游戏初始化
          this.gameInit()
        },
        // 随机生成一个两位数组
        matrix (numrows, numcols, initial) {
          var arr = []
          for (var i = 0; i < numrows; ++i) {
            var columns = []
            for (var j = 0; j < numcols; ++j) {
              columns[j] = { id: j + '' + i, num: initial }
              // columns[j] = initial
            }
            arr[i] = columns
          }
          return arr
        }
      }
    }
    </script>
    
    <style scoped lang="scss">
    // @import "./index.scss";
    .gameMain {
      height: calc(100vh - 88px);
      font-size: 28px;
      background: #d7d3b6;
      .gameName {
        font-size: 28px;
        font-weight: bold;
        padding-top: 20px;
      }
      .maxScore {
        font-size: 38px;
        margin: 20px auto;
        span {
          color: red;
          font-weight: bold;
        }
      }
      .gameBody {
         80%;
        height: 50%;
        margin: 0 auto;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        padding: 10px;
        background: #999;
        border-radius: 8px;
        padding-top: 5px;
        padding-bottom: 5px;
        .row {
          display: flex;
          justify-content: space-between;
          .item {
             100px;
            height: 100px;
            border-radius: 10px;
            background: #fff;
            text-align: center;
            line-height: 100px;
            font-size: 30px;
            font-weight: bold;
            margin: 5px;
            color: #666;
          }
        }
      }
      .gameDirection {
        margin: 50px auto;
        font-size: 26px;
        font-weight: bold;
        span {
           100px;
          display: inline-block;
        }
      }
      .gameRule {
        font-size: 26px;
        font-weight: bold;
        margin-top: 5px;
      }
      .gameScore {
        font-size: 20px;
        font-weight: bold;
        line-height: 40px;
        span {
          color: red;
          font-size: 30px;
        }
      }
      .scoreAndRefresh {
        display: flex;
        justify-content: space-around;
            align-items: center;
         280px;
        margin: 20px auto;
        .refreshBtn {
          padding:10px 20px;
        line-height: 40px;
          margin-top: 8px;
          background: #093233;
          color: #fff;
          border-radius: 6px;
        }
      }
    
      .gameOver{
          color: red;
          font-size: 40px;
      }
    }
    </style>

    注释

    v-touch:left,v-touch:right,v-touch:up,v-touch:down
    使用vue自定义指令

    const touch = {
      bind (el, binding, vnode) {
        console.log(binding)
        // 滑动指令
        var touchType = binding.arg // 传入的模式 press swipeRight swipeLeft swipeTop swipeDowm Tap
        var timeOutEvent = 0
        var direction = ''
        // 滑动处理
        var startX, startY
    
        // 返回角度
        function GetSlideAngle (dx, dy) {
          return Math.atan2(dy, dx) * 180 / Math.PI
        }
    
        // 根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右,0:未滑动
        function GetSlideDirection (startX, startY, endX, endY) {
          var dy = startY - endY
          var dx = endX - startX
          var result = 0
    
          // 如果滑动距离太短
          if (Math.abs(dx) < 2 && Math.abs(dy) < 2) {
            return result
          }
    
          var angle = GetSlideAngle(dx, dy)
          if (angle >= -45 && angle < 45) {
            result = 'right'
          } else if (angle >= 45 && angle < 135) {
            result = 'up'
          } else if (angle >= -135 && angle < -45) {
            result = 'down'
          } else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
            result = 'left'
          }
          return result
        }
    
        el.addEventListener('touchstart', function (ev) {
          startX = ev.touches[0].pageX
          startY = ev.touches[0].pageY
    
          // 判断长按
          timeOutEvent = setTimeout(() => {
            timeOutEvent = 0
            if (touchType === 'press') {
              binding.value()
            }
          }, 500)
        }, false)
    
        el.addEventListener('touchmove', function (ev) {
          clearTimeout(timeOutEvent)
          timeOutEvent = 0
        })
    
        el.addEventListener('touchend', function (ev) {
          var endX, endY
          endX = ev.changedTouches[0].pageX
          endY = ev.changedTouches[0].pageY
          direction = GetSlideDirection(startX, startY, endX, endY)
    
          clearTimeout(timeOutEvent)
          switch (direction) {
            case 0:
              break
            case 'up':
              if (touchType === 'up') {
                binding.value(direction)
              }
              break
            case 'down':
              if (touchType === 'down') {
                binding.value(direction)
              }
              break
            case 'left':
              if (touchType === 'left') {
                binding.value(direction)
              }
              break
            case 'right':
              if (touchType === 'right') {
                binding.value(direction)
              }
              break
            default:
          }
        }, false)
      }
    }
    
    export default touch


     
  • 相关阅读:
    Python变量状态保持四种方法
    Python参数基础
    Django Form 表单
    Python开发第四篇
    Python开发第三篇
    设计模式(一)概述
    Python自学之路——自定义简单装饰器
    Python开发第二篇
    Python开发第一篇
    Python核心编程——多线程threading和队列
  • 原文地址:https://www.cnblogs.com/Adyblog/p/15419158.html
Copyright © 2011-2022 走看看