专栏首页Coding迪斯尼VUE+WebPack前端游戏设计:实现物体的拖拽动态特效

VUE+WebPack前端游戏设计:实现物体的拖拽动态特效

上一节,我们介绍了太空版植物大战僵尸游戏的整体情况,并详解了如何建立游戏的基本框架,本节我们实现游戏中,道具的动态拖动特效,完成本节代码后,大家可以实现以下效果:

玩家先在底部的按钮中选择点击某个按钮,点击后图中的黄色方框会显示在页面上,这个方框是动态的,它会在指定位置一放一缩。当玩家在页面上移动鼠标时,方框会跟着鼠标移动,它会落入到鼠标所在的白色方块中。当玩家选定方块后,点击鼠标,那么在相应方块里就会出现对于的道具。道具的种类是根据玩家在底部点击哪个按钮决定的,接下来我们看看实现代码。

首先打开gamescenecomponent.vue,首先我们要创建一个二维数组来对应页面上的白色方框网格,在文件里添加如下代码:

create2DArray (rows, cols, initialValue) {
        var array = []
        for (var i = 0; i < rows; i++) {
          array[i] = []
          for (var j = 0; j < cols; j++) {
            array[i][j] = initialValue
          }
        }

        return array
      },

该函数会根据给定参数,创建一个二维数组,数组中每个元素对应传入的初始值。接着我们添加用于创建道具图像的代码:

building () {
        var b = new this.cjs.Container()
        b.cost = 0
        return b
      },

      satellite () {
        var b = this.building()
        b.addChild(new this.assetsLib.Satellite())
        b.cache(-50, -50, 100, 100)
        b.hp = 150
        b.cost = 30
        return b
      },

      satellite2 () {
        var b = this.building()
        b.addChild(new this.assetsLib.Satellite2())
        b.cache(-50, -50, 100, 100)
        b.hp = 150
        b.cost = 600
        return b
      },

      castle () {
        var b = this.building()
        b.addChild(new this.assetsLib.Castle())
        b.hp = 300
        b.shield = 5
        b.damageDeal = 2
        b.attackSpeed = 120

        return b
      },

      castle2 () {
        var b = this.building()
        b.addChild(new this.assetsLib.Castle2())
        b.cache(-50, -50, 100, 100)
        b.hp = 300
        b.shield = 10
        b.damageDeal = 10
        b.attackSpeed = 200

        return b
      },

      spaceJunk () {
        var b = this.building()
        b.addChild(new this.assetsLib.SpaceJunk())
        b.hp = 60
        b.cost = 5
        return b
      },

building()函数先通过createjs库创建一个图片容器,接下来的几个函数satellite(),satellite2(),castle(),castle2(),spacejunk()分别从assetsLib函数库中调用相关接口,导出对应的图片数据。例如在satellite()函数中,它会从资源库创建一个卫星素材资源,并把它添加到building()函数返回的资源容器中,它创建的图片素材如下:

也就是说,代码语句new this.assetsLib.Satellite() 创建的就是上面显示的图片素材。接着我们调用cache接口把图片缓存在内存里,下次再显示时,我们不用重新加载,其中变量hp表示该道具的能量值,一旦能量耗尽后,它就会从页面上消失,cost表示要建造这个道具需要损耗多少能源。其他几个函数的逻辑以此类似。

现在我们回到board函数,这个函数是创建的图层就是用来显示各种道具的。我们在该函数中添加如下代码:

Board () {
    ....
    // change here
        // selection对应的就是黄色方框
        board.selection = new this.assetsLib.Selection()
        board.addChild(board.selection)
        board.selection.visible = false

        // 创建二维数组对应页面上的白色网格
        board.isAddingBuilding = false
        board.buildingMap = this.create2DArray(board.cols, board.rows)

        // 让舞台容器响应鼠标移动和点击事件
        this.stage.on('stagemousemove', this.onStageMouseMove)
        this.stage.on('stagemouseup', this.onStageClick)
        return board
      },

新增的代码中,selection对应我们上图中那个黄色方框。接着调用create2DArray函数构建一个二维数组,用来对应页面上的白色网格方框,最后我们添加两个响应函数,用来对应鼠标在页面上的移动和点击。

当用户点击底部某个按钮,选择一件道具后,他会挪动鼠标,然后点击。当鼠标点击时,我们需要根据鼠标所在的坐标,判断当前鼠标落入了哪个网格,确定网格后,我们需要计算网格在页面上的坐标,然后把选中的道具图片素材显示到指定网格里。于是我们添加两个函数,用来根据鼠标坐标来确定鼠标所在的网格:

screenToRowCol (x, y) {
        var col = Math.floor(x / this.tileWidth)
        var row = Math.floor(y / this.tileHeight)
        return {col: col, row: row}
      },

      rowColToScreen (row, col) {
        var x = this.tileWidth * (col + 0.5)
        var y = this.tileHeight * (row + 0.5)
        return {x: x, y: y}
      },

这两个函数的逻辑不重要,大家只要知道他们的作用是根据鼠标坐标确定网格位置即可。一旦玩家在页面上点击鼠标后,我们就需要把对应的道具素材图片加载到指定位置了,为了完成这个功能,我们添加如下代码:

getBuilding (buildingClass) {
        if (buildingClass === 'SpaceJunk') {
          console.log('build SpaceJunk')
          return this.spaceJunk()
        }

        if (buildingClass === 'Satellite') {
          console.log('build Satellite')
          return this.satellite()
        }

        if (buildingClass === 'Satellite2') {
          return this.satellite2()
        }

        if (buildingClass === 'Castle') {
          return this.castle()
        }

        if (buildingClass === 'Castle2') {
          return this.castle2()
        }
        return null
      },
addBuildingAtTile (buildingClass, col, row) {
        var sprite = this.getBuilding(buildingClass)
        this.boardLayer.addChild(sprite)

        var pos = this.rowColToScreen(row, col)
        sprite.x = pos.x
        sprite.y = pos.y

        sprite.row = row
        sprite.col = col
        this.boardLayer.buildingMap[col][row] = sprite
      }

addBuildingAtTile()函数的作用是,根据输入参数buildingClass,创建相应的道具图片素材对象,然后根据传入的row,col两个参数,调用前面说过的两个坐标转换函数,确定道具图片要显示的网格,然后把图片显示到页面的指定位置。它先调用getBuilding()接口获取道具图片对象,getBuilding()根据输入的道具名称,调用对应的函数将道具图片素材加载到程序内存里,this.boardLayer.addChild(sprite)这句代码执行后,图片就会显示到页面上了。同时我们把道具图片对象存储在二维数组buildingMap中,这样我们在下次显示图片时,通过该数组就可以判定对应的位置是否已经被占据了。

当玩家点击页面底部按钮是,我们就能确定用户想创建哪种类型的道具,我们看看鼠标点击的响应代码后鼠标移动的响应代码:

onStageMouseMove (e) {
        if (!this.boardLayer.isAddingBuilding) {
          return
        }

        var pos = this.boardLayer.globalToLocal(e.stageX, e.stageY)
        var rowCol = this.screenToRowCol(pos.x, pos.y)
        pos = this.rowColToScreen(rowCol.row, rowCol.col)
        this.boardLayer.selection.visible = true

        this.boardLayer.selection.x = pos.x
        this.boardLayer.selection.y = pos.y
      },

      onStageClick (e) {
        if (!this.boardLayer.isAddingBuilding) {
          return
        }

        var pos = this.boardLayer.globalToLocal(e.stageX, e.stageY)
        var rowCol = this.screenToRowCol(pos.x, pos.y)
        var row = rowCol.row
        var col = rowCol.col

        if (row < 0 || row >= this.boardLayer.rows || col < 0 || col >= this.boardLayer.cols) {
          return
        }

        if (this.boardLayer.buildingMap[col][row] === undefined) {
          this.addBuildingAtTile(this.boardLayer.upcomingBuildingType, col, row)
          this.boardLayer.isAddingBuilding = false
          this.boardLayer.selection.visible = false
        }
      }

当鼠标在页面移动时,OnStageMouseMove会被调用,它先判断当前是否运行道具拖拽到页面上,如果可以,那么它通过globalToLocal,screenToRowCol,两个函数将当前鼠标所在的位置转换为对应的白色网格,然后将黄色方框显示到页面上。前面我们讲过selection对应的就是黄色方框图片素材,把它的visible属性设置成true之后,他就可以在页面上显示了。

当玩家在页面上选定位置点击鼠标后,onStageClick()函数会被调用。它先进鼠标所在的坐标转换成对应的白色网格,然后通过buildMap二维数组判断当前网格是否已经有道具占据了,如果没有,它就调用addBuildingAtTile函数将道具图片显示在指定网格。

最后我们看看代码如何处理用户点击底部按钮,相应的处理代码如下:

addButtonOnMouseDown (e) {
        if (this.cjs.Ticker.getPaused()) {
          return
        }

        var buildingType = e.target.dataset.type
        var cost = this.getBuildingCostByType()
        if (this.energies >= cost) {
          this.energies -= cost
          this.buildingType = buildingType
          this.readyToPlaceBuilding(buildingType)
        }
      },

      setHud () {
        var addButtons = document.querySelectorAll('.add-button')
        this.livesSpan = document.getElementById('lives')
        this.energiesSpan = document.getElementById('energies')
        this.wavesSpan = document.getElementById('waves')
        console.log(this.addButtonOnMouseDown)
        for (var i = 0, len = addButtons.length; i < len; i++) {
          var button = addButtons[i]
          button.onmousedown = this.addButtonOnMouseDown
        }
      },
      ....
      readyToPlaceBuilding (type) {
        console.log('ready to place building')
        this.boardLayer.upcomingBuildingType = type
        this.boardLayer.isAddingBuilding = true
      },

在setHud()函数中,它先获取底部按钮的对象,也就是addButtons数组,然后为每个按钮对象设立鼠标点击时的响应函数,这个相应函数就是addButtonOnMouseDown,在后者的实现中,它先获得当前被点击按钮的对象,然后通过dataset获得按钮的”data-set”属性。回忆上一节代码,每个按钮实际上就是一个超链接对象:

<a></a>

它有一个附带属性叫data-type,该属性的值是一个字符串,这个字符串决定了该按钮对应哪种道具,在addButtonOnMouseDown函数里,通过dataset.type这个字段获取了属性对应的内容,以此代码就能确定用户想在页面上显示哪种道具。函数判断当前玩家是否有足够的资源创建该道具,如果资源足够,函数就调用readyToPlaceBuilding()函数把要创建的道具名称记录下来,然后当用户在页面上移动鼠标或点击鼠标时,相应代码就根据存储的信息将相应道具的素材图片显示到相应位置。

上面代码完成后,我们就可以实现道具在页面上的动态拖拽特效了

本文分享自微信公众号 - Coding迪斯尼(gh_c9f933e7765d),作者:陈屹

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-02-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 寿司快卖:实现游戏主流程--制作寿司和客户显示动画特效

    上一节我们搭建了游戏的基本框架。游戏界面被分为若干个板块,其中一个板块显示了各种制作寿司的材料,它的目的是用于玩家根据信息组装各种寿司,本节我们进入游戏的主流程...

    望月从良
  • 实现小球在弹射前的拉伸特效和动态障碍物特效

    当前我们实现小球弹射时,会先用鼠标点击小球,然后移动鼠标,当松开鼠标时,小球会弹射向鼠标松开的位置。我们按住小球的时间越长,小球弹射的力度就越大,但有一个问题是...

    望月从良
  • ReactJs开发自制Monkey语言编译器:实现内嵌函数调用以及增加数组类型

    望月从良
  • jsencrypt参数前端加密c#解密

          写程序时一般是通过form表单或者ajax方式将参数提交到服务器进行验证,如何防止提交的请求不被抓包后串改,虽然无法说绝对安全却给非法提交提高了难度...

    用户1055830
  • Hadoop数据分析平台实战——250JSSDK数据收集引擎编写离线数据分析平台实战——250JSSDK数据收集引擎编写

    离线数据分析平台实战——250JSSDK数据收集引擎编写 JsSDK设计规则 在js sdk中我们需要收集launch、pageview、chargeReque...

    Albert陈凯
  • canvas 绘点图

    deepcc
  • JS高级-数据结构的封装

    最近在看了《数据结构与算法JavaScript描述》这本书,对大学里学的数据结构做了一次复习(其实差不多忘干净了,哈哈)。如果能将这些知识捡起来,融入到实际工作...

    小古哥
  • SpringBoot源码分析 顶

    一:创建SpringApplication对象过程:new SpringApplication(primarySources)

    须臾之余
  • 面试官:你分析过mybatis工作原理吗?

    当然,还有很多可以在XML 文件中进行配置,上面的示例指出的则是最关键的部分。要注意 XML 头部的声明,用来验证 XML 文档正确性。environment ...

    阮键
  • Promise的简单实现

    这个fetch()的方法返回了一个Promise对象,接着我们就可以用then来对获得的数据进行处理,catch来捕获可能的错误。

    IMWeb前端团队

扫码关注云+社区

领取腾讯云代金券