当前位置: 首页 > news >正文

使用Hilo.JS快速开发Flappy Bird

http://hiloteam.github.io/tutorial/flappybird.html#_9

 

Flappy Bird是一款前不久风靡世界的休闲小游戏。虽然它难度超高,但是游戏本身却非常简单。下面我们就使用Hilo来快速开发HTML5版的Flappy Bird。

源文件结构

大家可以先下载Flappy Bird的项目源文件作为参考,以下是整个项目的文件结构:

flappybird/
├── index.html //游戏主页面 ├── js/  ├── game.js //游戏主模块  ├── Asset.js //素材加载类  ├── ReadyScene.js //准备场景  ├── OverScene.js //结束场景  ├── Bird.js //小鸟类  ├── Holdbacks.js //障碍类  ├── hilo-standalone.js //hilo独立版 └── images/

预加载图片

为了让玩家有更流畅的游戏体验,图片素材一般需要预先加载。Hilo提供了一个队列下载工具LoadQueue,使用它可以预加载图片素材。如下所示,在Asset类中,我们定义了load方法:

load: function(){ var resources = [ {id:'bg', src:'images/bg.png'}, {id:'ground', src:'images/ground.png'}, {id:'ready', src:'images/ready.png'}, {id:'over', src:'images/over.png'}, {id:'number', src:'images/number.png'}, {id:'bird', src:'images/bird.png'}, {id:'holdback', src:'images/holdback.png'} ]; this.queue = new Hilo.LoadQueue(); this.queue.add(resources); this.queue.on('complete', this.onComplete.bind(this)); this.queue.start(); }

从上面代码中可以看到,resources是我们要下载的图片素材列表,使用queue.add()方法把素材列表加入到下载队列中,再使用queue.start()方法来启动下载队列。

提示:下载队列LoadQueue当前仅支持图片等资源的下载,其他资源文件可通过自定义扩展方式实现。具体可参考API文档。

为了获得下载情况,LoadQueue提供了三个事件:

  • load - 当单个资源下载完成时发生
  • complete - 当所有资源下载完成时发生
  • error - 当某一资源下载出错时发生

在这里我们仅监听了complete事件。

onComplete: function(e){ this.bg = this.queue.get('bg').content; this.ground = this.queue.get('ground').content; this.birdAtlas = new Hilo.TextureAtlas({ image: this.queue.get('bird').content, frames: [ [0, 120, 86, 60], [0, 60, 86, 60], [0, 0, 86, 60] ], sprites: { bird: [0, 1, 2] } }); //删除下载队列的complete事件监听 this.queue.off('complete'); //发送complete事件 this.fire('complete'); }

下载完成后会触发onComplete回调方法。我们可以通过queue.get(id).content来获取指定id的图片素材下载完成后的Image对象。 在这里我们创建了游戏中需要用到的素材以及精灵纹理集等。

其中纹理集TextureAtlas实例由三部分组成:

  • image - 纹理集图片。
  • frames - 纹理集图片帧序列。每个图片帧由图片在纹理集中的坐标x/y和宽高width/height组成,即[x, y, width, height]。
  • sprites - 精灵定义。sprites可包含多个精灵定义。每个精灵由多个frames中的图片帧组成,其中数值代表图片帧在frames中的索引位置。比如bird,则由索引为0、1、2的图片帧组成。

在game.js中使用Asset类来下载完图片素材后,再调用initStage方法初始化舞台:

this.asset = new game.Asset(); this.asset.on('complete', function(e){ this.asset.off('complete'); this.initStage(); }.bind(this)); this.asset.load();

初始化舞台

由于我们的图片素材是高清图片,且背景大小为720x1280。因此,我们设定游戏舞台的大小为720x1280,并设置其x和y轴的缩放比例均为0.5,这样舞台实际的可见大小变为360x640。最后,我们把canvas画布添加到body中。

initStage: function(){ this.width = 720; this.height = 1280; this.scale = 0.5; var stage = this.stage = new Hilo.Stage({ width: this.width, height: this.height, scaleX: scale, scaleY: scale }); document.body.appendChild(stage.canvas); }

注意:舞台是一个各种图形、精灵动画等的总载体。所有用Hilo创建的可见的对象都必须添加到舞台或其子容器后,才会被渲染和显示出来。

舞台创建好后,我们需要一个定时器来不断更新和渲染舞台。这里可以使用Ticker类:

//设定舞台刷新频率为60fps
this.ticker = new Hilo.Ticker(60); //把舞台加入到tick队列 this.ticker.addTick(this.stage); //启动ticker this.ticker.start();

场景分析

如果你玩过原版的Flappy Bird,就知道此游戏的场景非常简单,大致可以划分以下几个部分:

背景 - 背景图和移动的地面是贯穿整个游戏,没有变化的。 准备场景 - 一个简单的游戏提示画面。游戏开始前和失败后重新开始都会进入此场景。 游戏场景 - 障碍物不断的从右往左移动,玩家控制小鸟的飞行。 结束场景 - 游戏失败后,显示得分以及相关按钮等。 接下来,我们就开始用Hilo来创建这4个场景。

游戏背景

由于背景是不变的,为了减少canvas的重复绘制,我们采用DOM+CSS来设置背景。先创建一个div,设置其CSS背景为游戏背景图片,再把它加入到舞台的canvas后面。

initBackground: function(){ var bgWidth = this.width * this.scale; var bgHeight = this.height * this.scale; document.body.insertBefore(Hilo.createElement('div', { id: 'bg', style: { position: 'absolute', background: 'url(images/bg.png) no-repeat', backgroundSize: bgWidth + 'px, ' + bgHeight + 'px', width: bgWidth + 'px', height: bgHeight + 'px' } }), this.stage.canvas); }

地面也是背景的一部分,处于画面最下端。地面我们使用可视对象Bitmap类。一般的,不需要使用精灵动画的普通图片对象都可使用此类。Bitmap类只要传入相应的图片image参数即可。此外,为了方便查找对象,一般我们都为可视对象取一个合适的id。

initBackground: function(){ /* all previous code here */ this.ground = new Hilo.Bitmap({ id: 'ground', image: this.asset.ground }); //放置地面在舞台的最底部 this.ground.y = this.height - this.ground.height; //循环移动地面 Hilo.Tween.to(this.ground, {x:-60}, {duration:300, loop:true}); }

地面不是静止的。它是从右到左的不断循环的移动着的。我们注意到地面的图片素材比背景要宽一些,而地面图片本身也是一些循环的斜四边形组成的。这样的特性,意味着如果我们把图片从当前位置移动到下一个斜四边形的某一位置时,舞台上的地面会看起来是没有移动过一样。我们找到当地面的x轴坐标为-60时,跟x轴为0时的地面的图形是没有差异的。这样,若地面在0到-60之间不断循环变化时,地面就循环移动起来了。

Hilo提供了缓动动画Tween类。它的使用也非常简单:

Hilo.Tween.to(obj, newProperties, params);
  • obj - 要缓动的对象。
  • newProperties - 指定缓动后对象的属性改变后的新值。这里指定x为-60,也就是地面运动到x为-60的位置。
  • params - 指定缓动参数。这里指定了缓动时间time为300毫秒,loop表示缓动是不断循环的。

Tween类不会自动运行,也需要加入到tick队列才能运行:

this.ticker.addTick(Hilo.Tween);

准备场景

准备场景很简单,由一个Get Ready!的文字图片和TAP提示的图片组成。这里,我们创建一个ReadyScene的类,继承自容器类Container。它的实现只需要把getready和tap这2个Bitmap对象创建好并放置在适当的位置即可。而它们的图片素材image会传给ReadyScene的构造函数。

var ReadyScene = Hilo.Class.create({ Extends: Hilo.Container, constructor: function(properties){ ReadyScene.superclass.constructor.call(this, properties); this.init(properties); }, init: function(properties){ //准备Get Ready! var getready = new Hilo.Bitmap({ image: properties.image, rect: [0, 0, 508, 158] }); //开始提示tap var tap = new Hilo.Bitmap({ image: properties.image, rect: [0, 158, 286, 246] }); //确定getready和tap的位置 tap.x = this.width - tap.width >> 1; tap.y = this.height - tap.height + 40 >> 1; getready.x = this.width - getready.width >> 1; getready.y = tap.y - getready.height >> 0; this.addChild(tap, getready); } });

在游戏主文件game.js中,实例化ReadyScene并添加到舞台stage上。

this.readyScene = new game.ReadyScene({ width: this.width, height: this.height, image: this.asset.ready }).addTo(this.stage);

结束场景

结束场景跟准备场景相似。

var OverScene = ns.OverScene = Hilo.Class.create({ Extends: Hilo.Container, constructor: function(properties){ OverScene.superclass.constructor.call(this, properties); this.init(properties); }, init: function(properties){ //Game Over图片文字 var gameover = this.gameover = new Hilo.Bitmap({ id: 'gameover', image: properties.image, rect: [0, 298, 508, 158] }); //结束面板 var board = this.board = new Hilo.Bitmap({ id: 'board', image: properties.image, rect: [0, 0, 590, 298] }); //开始按钮 var startBtn = this.startBtn = new Hilo.Bitmap({ id: 'start', image: properties.image, rect: [590, 0, 290, 176] }); //等级按钮 var gradeBtn = this.gradeBtn = new Hilo.Bitmap({ id: 'grade', image: properties.image, rect: [590, 176, 290, 176] }); //玩家当前分数

转载于:https://www.cnblogs.com/Unknw/p/6427086.html

相关文章:

  • STAR法则
  • Openlayer4 - 最好最强大的开源地图引擎
  • shell中${}的妙用
  • 重定向监听端口并持久化路由配置
  • apiCloud结合layer实现动态数据弹出层
  • Win7 VS2015编译wxWidgets-3.1.0
  • html5 class
  • 2008 R2 Remote Desktop Server driver RDPDR.sys cannot be started, error 577
  • html5/css3
  • 三层与mvc
  • ERPS实例演示
  • SuSE Linux 开启VNC服务
  • HDU1572:下沙小面的(2)(DFS)
  • Android-实现Animation everywhere
  • 使用agvtool更改app version/build
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • CSS盒模型深入
  • js正则,这点儿就够用了
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • Python学习笔记 字符串拼接
  • React-flux杂记
  • SAP云平台里Global Account和Sub Account的关系
  • 动态规划入门(以爬楼梯为例)
  • 将回调地狱按在地上摩擦的Promise
  • 经典排序算法及其 Java 实现
  • 马上搞懂 GeoJSON
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 前端_面试
  • 深度学习中的信息论知识详解
  • 手机端车牌号码键盘的vue组件
  • 我的业余项目总结
  • 一起参Ember.js讨论、问答社区。
  • 再谈express与koa的对比
  • 白色的风信子
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • ​iOS实时查看App运行日志
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • ​人工智能书单(数学基础篇)
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #控制台大学课堂点名问题_课堂随机点名
  • $().each和$.each的区别
  • (1)SpringCloud 整合Python
  • (pytorch进阶之路)扩散概率模型
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (没学懂,待填坑)【动态规划】数位动态规划
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (七)Java对象在Hibernate持久化层的状态
  • (生成器)yield与(迭代器)generator
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (转)winform之ListView
  • (转)编辑寄语:因为爱心,所以美丽