LibGDX重建Flappy Bird——(8)屏幕切换与播放声音(终结)
本章源码链接:http://pan.baidu.com/s/1sjYE0sH 密码:q4n2
正如标题上所标注的,本章将完成FlappyBird的所有剩余内容。对比原版游戏我们可以发现FlappyBird现在还差两个界面,如下所示:
LibGDX提供Game和Screen两个类使我们可以将游戏拆分为多个界面。其中Game实现了ApplicationListener接口,所以他也可以作为项目的主类(也就是共享项目的启动类)。而Screen是LibGDX提供的一个具有完整生命周期的界面类。Game类提供了一个setScreen()方法可以让我们切换界面。
现在我们将游戏拆分为三个界面,分别是欢迎界面(WelcomeScreen)、预览界面(PreviewScreen),这两个界面分别对应上述两张截图,最后一个界面就是我们的游戏开始界面(FlappyBirdScreen)。那么游戏主类就是继承于Game的一个类了,这里我们命名为FlappyBirdGame。
在欢迎界面我们有两个目的,第一个目的是显示一个具有标志性的logo,第二个目的是加载资源。这两个目的是相辅相成的,我们知道,当资源过多时从硬盘加载到内存是需要相当大的开销,如果我们直接加载的话,屏幕可以能会出现短暂的黑屏甚至可能导致ANR(应用程序无响应),这样的情况对于用户来说是一种极为糟糕的体验。可能你已经发现前面我们一直使用的是直接加载应用资源。接下来我们将实现异步加载应用,并且在加载资源的这段时间里我们会在屏幕上显示一个标志性的logo背景,这样就可以完美的避免ANR和糟糕的体验。
首先让我们改造一下Assets类,让我们可以异步加载资源:
public class Assets implements Disposable, AssetErrorListener {...public void init (AssetManager assetManager) {this.assetManager = assetManager;// 设定资源管理器的错误处理对象句柄assetManager.setErrorListener(this);// 载入纹理集assetManager.load(Constants.TEXTURE_ATLAS_OBJECTS, TextureAtlas.class);// 载入声音文件assetManager.load("sounds/sfx_die.ogg", Sound.class);assetManager.load("sounds/sfx_hit.ogg", Sound.class);assetManager.load("sounds/sfx_point.ogg", Sound.class);assetManager.load("sounds/sfx_swooshing.ogg", Sound.class);assetManager.load("sounds/sfx_wing.ogg", Sound.class);}public boolean isLoaded() {if(!assetManager.update()) return false;// 打印资源信息Gdx.app.debug(TAG, "# of assets loaded: " + assetManager.getAssetNames().size);for(String a : assetManager.getAssetNames()) {Gdx.app.debug(TAG, "asset: " + a);}atlas = assetManager.get(Constants.TEXTURE_ATLAS_OBJECTS, TextureAtlas.class);fonts = new AssetFonts();bird = new AssetBird(atlas);pipe = new AssetPipe(atlas);land = new AssetLand(atlas);number = new AssetNumber(atlas);assetUI = new AssetUI(atlas);sounds = new AssetSounds(assetManager);decoration = new AssetDecoration(atlas);return true;}...
}
我们发现我们删除了init()方法中加载资源和创建分类资源的代码,剩下的代码仅仅是预加载资源而已。这里我们添加了一个isLoaded()方法,该方法具有两个功能,第一是判断资源是否加载成功,第二是创建分类资源对象。在isLoaded()中,我们首先调用AssetManager的update()方法,该方法也具有两个功能,第一是触发资源开始加载,并且是异步触发,也就死说update()方法不会阻塞当前线程,第二个是判断资源是否加载成功。所以当我们第一次调用isLoaded()的时候触发了资源开始异步加载,接着后面每次调用isLoaded()都会判断资源是否加载成功,如果成功则创建分类资源对象,然后返回true,否则返回false。
接下来我们创建第一个界面WelcomeScreen:
package com.art.zok.flappybird;import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Texture;
import com.art.zok.flappybird.game.Assets;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.utils.viewport.StretchViewport;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;public class WelcomeScreen implements Screen {private Stage stage;private FlappyBirdGame game;public WelcomeScreen(FlappyBirdGame game) {this.game = game;}@Overridepublic void show() {Image background = new Image(new Texture(Gdx.files.internal("images/splash.png")));background.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());Action fadeIn = Actions.fadeIn(1);background.addAction(fadeIn);stage = new Stage(new StretchViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()));stage.addActor(background);// 预加载资源Assets.instance.init(new AssetManager());}@Overridepublic void hide() {stage.dispose();}private void update() {if(Assets.instance.isLoaded()) game.setScreen(new PreviewScreen(game));}@Overridepublic void render(float delta) {update();stage.act();stage.draw();}...}
...public Bird(float x, float y) {init((int) (Math.random() * 3), x, y);}// 初始化public void init(int selected, float x, float y) {super.init(); // 保证对父类的初始化contacted = false;flashed = false;if (selected == 1) {birds = Assets.instance.bird.bird0;} else if (selected == 2) {birds = Assets.instance.bird.bird1;} else {birds = Assets.instance.bird.bird2;}birdAnimation = new Animation(0.1f, birds);birdAnimation.setPlayMode(Animation.PlayMode.LOOP);dimension.set(3.72f, 2.64f);position.set(x, y);}...
我们为构造方法和初始化方法分别添加了两个float类型数据表示Bird的初始化位置,最后我们将x和y设置为position的值。
private void initBird() {if(bird == null) {bird = new Bird(-4.5f, 1.3f);} else {bird.init((int) (Math.random() * 3), -4.5f, 1.3f);}}
package com.art.zok.flappybird;import com.art.zok.flappybird.game.Assets;
import com.art.zok.flappybird.game.UI.CustomButton;
import com.art.zok.flappybird.game.object.Bird;
import com.art.zok.flappybird.game.object.Land;
import com.art.zok.flappybird.util.Constants;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.utils.viewport.StretchViewport;public class PreviewScreen implements Screen {private Bird bird; // bird objectprivate Land land; // land objectprivate Stage stage; // stageprivate Image title; // text title imageprivate Image copyRight; // text copyright imageprivate float viewWidth; // last viewport widthprivate SpriteBatch batch; // sprite render batchprivate FlappyBirdGame game; // main classprivate AtlasRegion background; // random background texture regionprivate OrthographicCamera camera; // 正交投影相机private CustomButton play, score, rate; // three buttonspublic PreviewScreen(FlappyBirdGame game) {this.game = game;}@Overridepublic void show() {batch = new SpriteBatch();viewWidth = Constants.VIEWPORT_HEIGHT * Gdx.graphics.getWidth() / Gdx.graphics.getHeight(); // bird and landbird = new Bird(0, 2);land = new Land();// cameracamera = new OrthographicCamera(Constants.VIEWPORT_WIDTH, Constants.VIEWPORT_HEIGHT);camera.position.set(0, 0, 0);camera.update();// stagestage = new Stage(new StretchViewport(Constants.VIEWPORT_GUI_WIDTH,Constants.VIEWPORT_GUI_HEIGHT));// background texture regionbackground = Assets.instance.decoration.bg.random();// title imagetitle = new Image(Assets.instance.assetUI.textTitle);title.setBounds(93, 553, 295, 90);// copyright imagecopyRight = new Image(Assets.instance.assetUI.copyRight);copyRight.setBounds(137, 110, 206, 21);// three buttonsplay = new CustomButton(Assets.instance.assetUI.buttonPlay);play.setBounds(43, 175, 173, 108);score = new CustomButton(Assets.instance.assetUI.buttonScore);score.setBounds(263, 175, 173, 108);rate = new CustomButton(Assets.instance.assetUI.buttonRate);rate.setBounds(189, 313, 102, 65);stage.addActor(title);stage.addActor(copyRight);stage.addActor(play);stage.addActor(score);stage.addActor(rate);//input handlerGdx.input.setInputProcessor(stage);// touch up event (touchDown must be return true)play.addListener(new InputListener() {public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {return true;};public void touchUp(InputEvent event, float x, float y, int pointer, int button) {game.setScreen(new FlappyBirdScreen());}});}@Overridepublic void hide() {batch.dispose();stage.dispose();}private void update(float deltaTime) {bird.update(deltaTime); // wave animationland.update(deltaTime); // move animation}@Overridepublic void render(float delta) {update(Gdx.graphics.getDeltaTime());Gdx.gl.glClearColor(0f, 0f, 0f, 1f);Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);batch.setProjectionMatrix(camera.combined);batch.begin();batch.draw(background, -viewWidth / 2, -Constants.VIEWPORT_HEIGHT / 2, viewWidth, Constants.VIEWPORT_HEIGHT);bird.render(batch);land.render(batch);batch.end();stage.act();stage.draw();}@Overridepublic void resize(int width, int height) {camera.viewportWidth = Constants.VIEWPORT_HEIGHT * width / height;camera.update();}@Overridepublic void pause() {}@Overridepublic void resume() {}@Overridepublic void dispose() {}
}
虽然PreviewScreen类中添加的东西比较多,但是并没有什么难以理解的内容。我们可以简单的介绍一下实现思路,首先我们维护了一个Stage对象用于承载相应的组件对象,如文本图片(“FlappyBird”)、开始按钮(play)、分数按钮(score)、还有速度按钮(rate)和版权图片。接着我们创建了一个Bird对象和一个Land对象,然后创建了一个相机对象,该对象用于渲染Bird和Land,并且我添加了update()方法更新Bird和Land对象。最后我们在hide()中释放了batch和stage两个对象。
package com.art.zok.flappybird;import com.art.zok.flappybird.game.WorldController;
import com.art.zok.flappybird.game.WorldRenderer;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;public class FlappyBirdScreen implements Screen {private WorldController worldController;private WorldRenderer worldRenderer;public boolean paused;@Overridepublic void show() {paused = false;worldController = new WorldController(this);worldRenderer = new WorldRenderer(worldController);}@Overridepublic void hide() {worldController.dispose();worldRenderer.dispose();}@Overridepublic void render(float delta) {if(!paused) {float deltaTime = Math.min(Gdx.graphics.getDeltaTime(), 0.018f);worldController.update(deltaTime);}Gdx.gl.glClearColor(0x64/255.0f, 0x95/255.0f, 0xed/255.0f, 0xff/255.0f); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); worldRenderer.render(); }@Overridepublic void resize(int width, int height) {worldRenderer.resize(width, height);}@Overridepublic void pause() {paused = true;}@Overridepublic void resume() {paused = false;}@Overridepublic void dispose() {}
}
上述的类和之前的FlappyBirdMain类几乎一样,稍有不同的是我们将初始化放在了show()方法中,将对象释放的代码放在了hide()方法中。并且我们不在resume()中重新加载资源了。我们之前说Android在应用进入后台后可能会释放部分资源,所以在重返前台时必须重新加载资源,但是这里指的是我们直接使用文件句柄加载资源的情况,如果我们使用AssetManger加载并管理资源就不需要担心这个问题了。
package com.art.zok.flappybird;import com.art.zok.flappybird.game.Assets;
import com.badlogic.gdx.Game;public class FlappyBirdGame extends Game {@Overridepublic void create() {setScreen(new WelcomeScreen(this));}@Overridepublic void dispose() {super.dispose();Assets.instance.dispose();}
}
该类的初始化化函数依然是create(),所以我们只是在create()初始化界面为欢迎界面,然后重载dispose()方法保证游戏退出时资源的释放。
// 通知碰撞事件public void contact() {contacted = true;Assets.instance.sounds.hit.play();Assets.instance.sounds.die.play();}
小鸟煽动翅膀应该是在每次触发跳跃时:
// 触发跳跃public void setJumping() {if(body != null) {body.setLinearVelocity(0, 35f);Assets.instance.sounds.wing.play();}}
下面是point,point应该在WorldController的score增加1时播放,所以:
// 计算分数private void calculateScore () {for(Pipe pipe : pipes.pipes) {if(pipe.position.x < bird.position.x) {if(pipe.getScore() == 1) {score += 1;Assets.instance.sounds.point.play();Gdx.app.debug(TAG, "Your current score:" + score);}}}}
最后是swooshing应该在每个自定义按钮被按下时调用,所以修改CustomButton:
public class CustomButton extends Button {...public CustomButton(AtlasRegion reg) {...addListener(new InputListener() {@Overridepublic boolean touchDown(InputEvent event, float x, float y,int pointer, int button) {Assets.instance.sounds.swooshing.play();return super.touchDown(event, x, y, pointer, button);}});}
我们在CustomButton的构造函数添加了一个监听器,并重写了touchDown方法,在该方法中我们只是播放了swooshing声音,这样凡事继承于CustomButton的按钮都会在按下时播放该声音。
转载于:https://my.oschina.net/u/2432369/blog/610410
LibGDX重建Flappy Bird——(8)屏幕切换与播放声音(终结)相关推荐
- LibGDX重建Flappy Bird——(4) 创建游戏对象
在本章,我们将为Flappy Bird项目创建一个真正的场景.该游戏场景由几个具有共同属性和功能的游戏对象组成.但是,这些对象被渲染的方式和行为却各有不同, 简单的 对象直接渲染其所分配的纹理,复 ...
- LibGDX_8.2: LibGDX 项目实战: 开发跨平台 Flappy Bird(像素鸟)游戏
本文链接: http://blog.csdn.net/xietansheng/article/details/50188319 LibGDX 基础教程(总目录) 声明: 游戏中使用到的图片和音频资源来 ...
- cmd小游戏_使用pygame制作Flappy bird小游戏
原文链接: [Python]使用Pygame做一个Flappy bird小游戏(一)mp.weixin.qq.com 最近看到很多大佬用强化学习玩Flappy bird.所以打算也上手玩一玩,但是苦 ...
- 使用cocos2d-x实现一款类似《Flappy Bird》的游戏
最近,一只8比特位像素的小鸟霸占了IOS免费游戏排行榜的第一名,这款<Flappy Bird>游戏可谓是一夜爆红,简单并不粗糙的画面.超级玛丽游戏中的绿色通道.眼神有些呆滞的小鸟和几朵白云 ...
- 利用python开发的flappy bird 游戏
python 中 pygame模块能让我们很方便的编写游戏,16年我用python 仿制了flappy bird 游戏,下面是游戏的完整代码以及素材,分享给大家. 第一个python文件,flappy ...
- Compose 正式发布,来打造一个 Flappy Bird! | 开发者说·DTalk
本文原作者: 小虾米君,原文发布于: TechMerger https://mp.weixin.qq.com/s/Hpd2NF0hOw4xOo3wVb_VFg 之前看到 fun 神用 Compose ...
- cocos2dx-html5 实现网页版flappy bird游戏
我也是第一次使用cocos2d_html5,对js和html5也不熟,看引擎自带的例子和引擎源码,边学边做,如果使用过cocos2d-x的话,完成这个游戏还是十分简单的.游戏体验地址: http:// ...
- flappy bird游戏源代码揭秘和下载
背景: 最近火爆全球的游戏flappy bird让笔者叹为观止,于是花了一天的时间山寨了一个一模一样的游戏,现在把游戏的思路和源码分享出来,代码是基于javascript语言,cocos2d-x游戏引 ...
- java实现Flappy Bird游戏(附免费素材+代码+详细注解)
目录 前言 一.实现效果 二.实现代码 前言 该小游戏我设计成BackGroundView类(背景图).Bird类.Pipe类,Main类四部分 图片素材地址:https://download.csd ...
最新文章
- 最实用的机器学习算法优缺点分析,没有比这篇说得更好了
- JavaScript学习--闭包
- 关于bcp的那些事儿
- Spring-Spring整合MyBatis详解
- drtek收音机使用说明_一百年前的便携式矿石收音机长啥样?这台1919年产品给你答案...
- jsp实现数据禁用和只读
- C点滴成海------Dev C++怎么修改成简体中文
- html语言怎样设置密码类型,html – 在使用contenteditable div时模仿密码类型输入
- 何小鹏退出UC浏览器母公司股东名单
- Map 3D 2012定制和应用程序开发Webcast将于明天(6月23号)进行
- selenium调用edge driver的坑
- 悠歌“即时”游戏回合文案
- 江苏科技大学MATLAB考试,江苏科技大学精品课程申报表.DOC
- 省市区级联SQL文件(MySQL)
- form表单提交时传递额外的参数
- php的 提示无效字符,ORA-00911: 无效字符
- Android 游戏破解修改金币
- SQLSyntaxErrorException: SELECT command denied to user ‘XXXXX‘@‘xxxx‘ for table ‘XXXX‘ 异常解决
- 漏洞检测~SQL注入
- 第14章 Linux终端设备驱动之终端设备
热门文章
- 2023最新豆十三沙雕视频教学全套课程/附带完整素材和插件
- java并发学习03---CountDownLatch 和 CyclicBarrier
- vscode 使用Java Extension Pack插件导致的Java版本不合问题的解决方案
- fiddle导出jmx文件_Fiddler导出JMX文件配置
- LVDS-CML-LVPECL 原理及转换
- 有趣的数学 依靠想象力的微积分
- 女生25岁转行软件测试晚吗?
- 华强北刷机经历 type password to decrypt storage
- defy手机 小技能 问题
- ubuntu18.04上安装ROS机器人操作系统