VUE+WebPack精美游戏设计:实现微信红包铜钱转动特性和页面数据的本地存储

上一节,我们完成了建筑物的动态生成效果。在三种建筑物中,有一种建筑物,也就是商店,一旦它生成后,能产生一种特殊效果,那就是有一个钻石精灵会动态的漂浮在它下方,一旦用户点击后,玩家的钻石数量可以相应增加。本节的主要目的就是实现浮动精灵的动画特效,完成本节代码后,效果如下:

商店下方的钻石图片在页面上回呈现出反复转动的动态效果,具体特效请点击‘阅读原文’参看视频:

大家在接收微信红包时,点开红包后就会看到有一个空心铜钱转了好几圈后才出现红包里面的金额,上面实现的就是铜钱转圈的特效。

在实现上述效果前,我们需要对代码做些许改动。当玩家点击右下角的Building按钮时,弹出来的选择面板,必须根据用户当前的钱币数和人口数来决定哪一种建筑物是可以建造的,我们以前的代码并没有考虑到这一点,先打开buildingpanelcomponent.vue进行相应的代码修改:

export default { 
    data () { 
      return { 
      .... 
      buttonsMap: {} 
      } 
    }, 
   .... 
   decideWhetherButtonDisableOrNot () { 
        // 判断当前是否有足够的钱币,电量和人口去建造建筑物 
        for (var i = 0; i < 3; i++) { 
          var b = this.buildings[i] 
          var hasEnoughPowerSupplies = Constant[b.name].needPopulations === 0 || (this.gameSceneComponent.powerSupplies - this.gameSceneComponent.populations >= Constant[b.name].needPopulations) 

          var hasEnoughCoins = (this.gameSceneComponent.coins >= Constant[b.name].needCoins) 
          var button = this.buttonsMap[b.name].enableButton 
          var buttonDisabled = this.buttonsMap[b.name].disableButton 

          if (hasEnoughPowerSupplies && hasEnoughCoins) { 
            button.visible = true 
            buttonDisabled.visible = false 
          } else { 
            button.visible = false 
            buttonDisabled.visible = true 
          } 
        } 
      }, 
      setupBuildingButton (i) { 
      .... 
     // change here 
      var buttons = {} 
      var _this = this 
      // change here 
      buttons['enableButton'] = button 
      .... 
      // change here 
      buttons['disableButton'] = buttonDisabled 
      this.buttonsMap[b.name] = buttons 
      } 
}

玩家在点击右下角的Building按钮,打开建筑物选择面板时,程序必须根据玩家当前的人口数,能源数以及钱币数来决定到底哪种建筑物是允许玩家选择的。上面代码中的decideWhetherButtonDisableOrNot所实现的逻辑就是做相应的判断,它计算玩家当前的各种资源,然后跟建筑物需要的资源数相比对,如果满足条件,那么在控制面板的相应建筑物按钮上就会有一个Build按钮,如果资源不满足,那么相应建筑物上就没有Build按钮。

setupBuildingButton用来实现控制面板上的按钮,它先为每个建筑物设计两种按钮,当建筑物可以建造时,采用代码中button对应的按钮对象,当建筑物不可以建造时采用代码中的disableButton对象。上面的代码完成后,每次点击Building按钮,控制面板显示出来的建筑物总会根据当前的资源条件来表明建筑物是否可以被玩家选择:

接着我们要实现的是城市的资源生长逻辑。建造一个发电厂,游戏就可以增加人口数量,每隔一定时间,城市的钱币数就可以自动增加,如果建造了造钱厂,那么钱币增加的时间间隔就会减少,如果建筑了商城,那么当钱币数目超过200,并且经过一定的时间间隔后,商城旁边就会跳动出一个旋转的钻石,点击钻石,城市的钻石数目就可以增加。由此回到gamescenecomponent.vue中增加相应代码:

export default { 
    data () { 
      return { 
      .... 
      // change here 
        // 经过800时间单位能创造一个钻石 
        // change here for test 
        tickCountForMerchantDiamond: 800, 
        // 200金币换一个钻石 
        coinsNeededForDiamond:  200, 
        // 每隔90个时间单位增加一个金币 
        coinGenerationCountDown: 90, 
        // 当前总共增加几个金币 
        coinGenerationCount: 0 
        } 
    } 
    .... 
    tick () { 
    .... 
    this.coinsTick() 
    .... 
    } 
    .... 
    calculateBuildingsEffects () { 
        // 根据当前建筑物,计算金币,钻石和人口数量 
        this.powerSupplies = 10 
        this.populations = 0 
        this.coinGenerationCountDown = 90 

        for (var i = 0, len = this.buildingList.length; i < len; i++) { 
          var b = this.buildingList[i] 
          var data = Constant[b.name] 
          // 计算总人口 
          this.evaluatePopulation(data.needPopulations) 

          if (b.isConstructionDone) { 
            this.evaluatePowerSupply(data.power) 
            if (b.name === 'CoinsGenerator') { 
              this.evaluateCoinsGeneration() 
            } 

            if (b.name === 'Merchant') { 
              this.evaluateMerchant(b) 
            } 
          } 
        } 
      }, 
      evaluatePopulation (value) { 
        this.populations += value 
      }, 
      evaluatePowerSupply (value) { 
        this.powerSupplies += value 
      }, 
      evaluateCoinsGeneration () { 
        this.coinGenerationCountDown -= 3 
      }, 
      evaluateMerchant (building) { 
        var b = building 
        if (!b.diamonTick) { 
          b.diamonTick = 0 
        } 

        b.diamonTick += 1 
        if (b.diamonTick >= this.tickCountForMerchantDiamond) { 
          if (this.coins >= this.coinsNeededForDiamond) { 
            this.coins -= this.coinsNeededForDiamond 
            this.popDiamond(b) 
            b.diamondTick = 0 
          } 
        } 
      }, 
      coinsTick () { 
        this.coinGenerationCount += 1 
        if (this.coinGenerationCount >= this.coinGenerationCountDown) { 
          this.coins += 1 
          this.coinGenerationCount = 0 
        } 

        this.calculateBuildingsEffects() 
      },

calculateBuildingsEffects函数的作用是根据当前建筑物的情况来决定城市系统资源的变化,如果当前建筑物有发电厂,那么就调用evaluatePowerSupply增加城市能源的数量,如果有造币厂,那么就调用evaluateCoinsGeneration,把钱币生成的时间间隔减短3个时间单位,如果有商城,那么就调用evaluateMerchant函数,它会判断当前钱币是否足够多,当钱币满足时,还需等待一段时间后,才会在商城附近调用popDiamond函数,实现钻石精灵旋转的特效。coinsTick负责每过一段时间后就给城市增加一个钱币,它会调用calculateBuildingsEffects函数来统计城市系统当前的资源数量。

在tick函数中会调用coinsTick,由于tick函数是每秒被调用40次,因此游戏在每一秒都会多次触发前面提到的各种资源计算函数。接下来我们就需要看看如何实现钻石转动的精灵特效,它的实现代码如下:

diamondSprite () { 
        var container = new this.cjs.Container() 
        var data = { 
          framerate: 16, 
          images: ['../../static/images/diamond-spritesheet.png'], 
          frames: {width: 90, height: 90} 
        } 
        var spriteSheet = new this.cjs.SpriteSheet(data) 
        var diamondSprite = new this.cjs.Sprite(spriteSheet) 
        diamondSprite.gotoAndPlay(0) 
        diamondSprite.scaleX = diamondSprite.scaleY = 0.5 
        container.addChild(diamondSprite) 
        container.on('click', function () { 
          this.diamonds += 1 
          this.stage.removeChild(container) 
        }.bind(this)) 

        return container 
      }, 
      // 在页面上弹出一个钻石 
      popDiamond (building) { 
        var screenCoord = this.isoToScreenCoord(building.x, building.y) 
        var globalScreenCoord = this.cityLayer.localToLocal(screenCoord.x, screenCoord.y, this.stage) 
        var diamond = this.diamondSprite() 
        diamond.x = globalScreenCoord.x 
        diamond.y = globalScreenCoord.y 
        this.stage.addChild(diamond) 
      },

diamondSprite函数用来创建一个钻石转动的动画精灵,他会把精灵特效对应的图片加载到页面上,我们要实现的精灵特效图片如下:

动画精灵的本质是把一系列图片连续显示,进而展现出一种动画效果。我们的钻石精灵就是把上面图片中的五个图案在单位时间内多次连续显示,上面图片连续显示后就会在页面上展现出一种转动不停的特效。

diamondSprite函数先创建一个动画精灵对象,它定义了一个变量叫framerate,这个值用来指定一秒内连续展示几幅图片,我们规定一秒内展示16幅,在我们上面的图片中,总共有5幅图案,一旦图案展示完了后,代码会重新从第一幅开始,再次循环展示。里面的gotoAndPlay调用就开启了图片连续显示过程。

当我们在转动的钻石精灵上点击后,程序会让游戏的总钻石数加一,并且把钻石精灵从舞台容器,也就是stage中拿掉,这样钻石精灵就从页面上消失了。函数popDiamond被调用时,他就会调用diamondSprite函数创建一个转动的钻石精灵,然后设置精灵在页面上的坐标轴,同时把精灵对象加入舞台容器,这样转动着的钻石精灵就会出现在页面上。

至此,游戏的设计进入到尾声阶段。最后我们要实现的是游戏数据的本地存储。我们这个游戏是一个较为消耗时间的过程,如果玩家玩到一半暂时不想玩了,那么他可以把页面关闭,下次打开页面上,页面上显示的情况要和上次关闭时一模一样,这就要求我们的游戏在页面关闭时,把各种数据,例如当前的页面上已经有的建筑物,游戏的钱币数,人口值等相关信息存储到本地,当下次页面开启时,将存储的数据再次读入页面,代码根据存储的数据把页面上次关闭时的情况再次重现出来。

最新的HTML5提供了相关机制,让我们能实现页面数据的局部保存,相应代码如下:

init () { 
    .... 
// change here 
        if (localStorage['city.buildinglist']) { 
          this.buildingList = JSON.parse(localStorage['city.buildinglist']) 
        } else { 
          this.buildingList = [] 
        } 
        // *1 将字符强行转换成数字 
        this.coins = localStorage['city.coins'] * 1 || 10 
        this.diamonds = localStorage['city.diamonds'] * 1 || 0 
        .... 
} 
.... 
tick () { 
.... 
 // change here 
  this.autoSave() 
} 
autoSave () { 
        if (this.cjs.Ticker.getTicks() % 100 === 0) { 
          localStorage['city.coins'] = this.coins 
          localStorage['city.diamond'] = this.diamonds 
          localStorage['city.buildinglist'] =       JSON.stringify(this.buildingList) 
        }

在autoSave中,代码利用HTML5提供的localStorage对象将相关信息存储起来,它保存了游戏当前的钻石数和钱币数,并调用JSON.stringify把buildingList中存储的建筑物信息全部转换成JSON格式的字符串后,存储在localStorage的city.buildinglist字段下。

在init函数中,也就是页面刚刚被浏览器加载时,他会被调用,在初始化时,代码会先从localStorage对象中读取city.buildinglist字段,获得存储的建筑物信息,把这些信息转换为二进制后重新存储在数组buildingList 变量中。然后分别读取city.coins 和 city.diamonds字段,获得上次页面关闭时游戏存储的钱币数和钻石数,并把他们恢复到本次游戏进程中来。在tick函数中会调用autoSave函数,后者会判断,每过100个时间单位后,才会把当前数据存储到localStorage对象中。完成这部分代码后,我们可以尝试着关闭或刷新当前页面,当下次再次打开页面时,我们可以看到,页面上的情形与上一次关闭时是一模一样的。

至此,整个游戏的设计就结束了,其实游戏本身还有很多需要改进的地方。例如例如不同的建筑物,它的建筑完成时间是不一样的,有些建筑物例如商城需要玩家等待很长时间,这时候我们可以提供一个功能,玩家只要缴纳一点钱,我们便能开个后门,减少建筑物建筑的时间。同时我们还可以增加更多种类,功能也独特的建筑物,只有付费玩家才能选择等等。

原文发布于微信公众号 - Coding迪斯尼(gh_c9f933e7765d)

原文发表时间:2017-12-15

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏天天

网页图片的压缩优化

在网页建设过程中,图片的使用时必不可少的,甚至有些网站的80%~90%的部分都是图片,那么如此之多的图片怎么才能保证良好的用户体验,好的加载速度呢,其实从很多角...

23440
来自专栏量子位

苹果新推出的CoreML怎么用?有哪些bug?这里有一份教程

安妮 编译自 Hackernoon 量子位出品 | 公众号 QbitAI 昨天,年仅18岁的iOS app开发者Alex Wulff在Hackrnoon上发布了...

36370
来自专栏肖洒的博客

基于Python的微信好友分析

“如果我比别人看得远,那是因为我站在巨人的肩膀上”–不知道牛顿说了没 本文利用Python3的itchat包简单的分析了一下自己的微信好友。

62420
来自专栏PPV课数据科学社区

【课程推荐】数据可视化神器-tableau入门

数据可视化——Tableau Tableau Desktop 是基于斯坦福大学突破性技术的软件应用程序。Tableau 是桌面系统中最简单的商业智能工...

37330
来自专栏企鹅号快讯

python-pcl以及相关资料分享

PCL(Point Cloud Library)是在吸收了前人点云相关研究基础上建立起来的大型跨平台开源C++编程库,它实现了大量点云相关的通用算法和高效数据结...

81950
来自专栏数据小魔方

Xcelsius(水晶易表)系列9——动态选择器应用(过滤器)

今天继续跟大家分享关于水晶易表的动态选择器高级用法——过滤器。 这个部件可以将多层帅选筛选自动化,比如我们前两篇所讲解的多重筛选案例中, 需要为每一个筛选字段单...

35460
来自专栏机器学习算法与Python学习

资源 | 让你事半功倍的小众Python库

Python 是世界上发展最快的编程语言之一。它一次又一次地证明了自己在开发人员和跨行业的数据科学中的实用性。Python 及其机器学习库的整个生态系统使全世界...

12420
来自专栏数据小魔方

R语言可视化——ggplot携手plotly,让你的图表灵动起来!

这段时间一直在研究ggplot2这个神奇的可视化利器,可是ggplot2纵然所向披靡,唯独无法呈现动态效果! 最近发现R语言的官方CRAN中有一款名叫plotl...

60360
来自专栏DeveWork

为你的WordPress 主题添加结构化数据/丰富文本摘要,高亮搜索结果(上)

对于SEO ,咱们这些业余人士只能是从技术的角度来驾驭。网站经营的前期需要做好搜索引擎优化,对于WordPress 网站,其实最好的方式是在WordPress ...

35660
来自专栏Web行业观察

我是如何爱上ag-grid框架的

与每个管理系统一样,我们需要选择一个网格来显示我们的数据,而我的前任已经在应用程序中使用了两个网格 -  ag-Grid(v2.7)和Ng-Table(v0.8...

1.3K40

扫码关注云+社区

领取腾讯云代金券