最近几天没有更新博客,是因为我这两天在学习Libgdx的一个游戏源码,毕竟再怎么研究libgdx游戏引擎的原理,如果不去实践一下,掌握起来还是比较费劲的。(我个人对于一个新的东西的掌握,都是先从HelloWorld开始,然后开始写一些例子,从各个方位去了解他,其中自然有很多底层原理性的东西,不懂是肯定的!但我不会去深究它,因为这样太浪费时间,而且很容易走偏,我会在学完基本上如何使用和了解了它的大体以后,再去慢慢深入其原理,这样的一来一回,学习效率会倍增!)
好了不多说了,在以后的几篇博客里我会逐步分版本的讲解一下SuperJumper这款游戏,让大家(当然还有我,毕竟我也是初学者嘛! 嘿嘿!)逐渐掌握libgdx这款游戏引擎(框架)的使用方法。
1.游戏介绍:
这是一款跳跃型的游戏,主人物会一直往上跳,我们只需控制左右移动让其踩在适当的跳台上即可继续的往上跳,最终加到的金币越多, 到达城堡就胜利了。(貌似有点无聊哈,不过我们是来学习它的框架和使用方法的,相信大家学习完之后,自己也能做一个更好玩的游戏哦!)
上个图:
这里游戏源码我们可以从官网提供的SVN上下载(http://libgdx.googlecode.com/svn),我试过了可以的!连接成功后直接检出即可
当然,这里蜗牛已经将superjumper检出,同时也为大家配置好环境,直接使用即可。下载地址:http://down.51cto.com/data/893457
这里,我想说一下,因为本人也是初学者,第一次看到源码后不知道从何下手,所以每讲我会将每个版本的源码放出来,方便初学者循序渐进的学习它,相信这样的效率会更高!
好了不多说了,我们一步一步的开始吧!
2.项目创建
2.1为了方便测试起见,我们整个项目都在desktop上开发运行,大家也可以在android模拟器上试试,真机上就不行了(因为这款游戏需要左右按键的哦)
步骤:1.点击libgdx文件夹中的gdx-setup-ui.jar
2.在弹出的窗体中我们来新建项目:
3.下一步,点击launch即可,
4.这样我们的项目已经建立成功,接下来就是找到刚才我们建立项目的文件目录下,用eclipse将其导入到工程下。
导入成功!(第一个:源代码; 第二个:Android版本;第三个: 桌面版本)
ok! 项目已经创建成功!现在我们点击desktop版本右击运行 Java Application 进行测试,弹出一个窗体说明框架正常!以后我们的代码都在第一个MySuperJumper中编写,在desktop中进行测试!!
3.游戏代码框架搭建
SuperJumper类:启动入口
package com.zhf.mylibgdx; import com.badlogic.gdx.Game; import com.badlogic.gdx.graphics.FPSLogger; /** * 启动入口 * @author ZHF * */ public class MySuperJumper extends Game{ boolean firstTimeCreate = true; //是否是第一次创建 FPSLogger fps; //帧频 @Override public void create () { Settings.load(); Assets.load(); setScreen(new MainMenuScreen(this)); fps = new FPSLogger(); } @Override public void render() { super.render(); fps.log(); } @Override public void dispose () { super.dispose(); getScreen().dispose(); //销毁 } }
Settings类:
package com.zhf.mylibgdx; /** * 设置类:三个方法: 1.load()读取声音开关和最高分. 2.save()保存配置 3.addScore()最高分排行榜,对数组赋值。 * @author ZHF * */ public class Settings { //记录声音开起与关闭 public static boolean soundEnabled = true; /**加载配置文件**/ public static void load (){ } }
Assets类: 各种资源的读取
package com.zhf.mylibgdx; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; /** * 各种资源的读取(这里TextureRegion的用法可以学习,还有Music类,Sound类的使用方法) * @author ZHF * */ public class Assets { public static Texture background; public static TextureRegion backgroundRegion; //背景 public static Texture items; //一系列的图片 public static TextureRegion mainMenu; //主菜单 public static TextureRegion logo; public static TextureRegion soundOn; //声音按钮 public static TextureRegion soundOff; public static Sound clickSound; //按下音效 public static Music music; //背景音乐 /**通过资源名获取资源**/ public static Texture loadTexture (String file) { return new Texture(Gdx.files.internal(file)); } /**加载各种资源**/ public static void load () { //背景 loadTexture("data /background.png"); backgroundRegion = new TextureRegion(background, 0, 0, 320, 480); //主画面中的UI控件 items = loadTexture("data/items.png"); logo = new TextureRegion(items, 0, 352, 274, 142); mainMenu = new TextureRegion(items, 0, 224, 300, 110); soundOff = new TextureRegion(items, 0, 0, 64, 64); soundOn = new TextureRegion(items, 64, 0, 64, 64); //点击音效 clickSound = Gdx.audio.newSound(Gdx.files.internal("data/click.ogg")); //背景音乐 music = Gdx.audio.newMusic(Gdx.files.internal("data/music.mp3")); music.setLooping(true); //循环 music.setVolume(0.5f); //大小 if (Settings.soundEnabled) music.play(); } /**播放游戏音效**/ public static void playSound (Sound sound) { if (Settings.soundEnabled) sound.play(1); } }
MainMenuScreen类:主菜单界面
package com.zhf.mylibgdx; import com.badlogic.gdx.Game; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.GLCommon; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector3; /** * 主菜单界面 * @author ZHF * */ public class MainMenuScreen implements Screen{ Game game; OrthographicCamera guiCam; SpriteBatch batch; Rectangle soundBounds; Rectangle playBounds; Rectangle highscoresBounds; Rectangle helpBounds; Vector3 touchPoint; public MainMenuScreen(Game game) { // TODO Auto-generated constructor stub //得到Game对象,以便能调用Game切换到下一个画面,目前无用 this.game = game; //相机,大小是320*480像素,这里作者把像素都按屏幕分辨率320*480写死了,等下会介绍如何适配到不同像素 guiCam = new OrthographicCamera(320, 480); //相机位置 guiCam.position.set(320 / 2, 480 / 2, 0); //渲染器 batch = new SpriteBatch(); //喇叭图标 soundBounds = new Rectangle(0, 0, 64, 64); playBounds = new Rectangle(160 - 150, 200 + 18, 300, 36); highscoresBounds = new Rectangle(160 - 150, 200 - 18, 300, 36); helpBounds = new Rectangle(160 - 150, 200 - 18 - 36, 300, 36); //点击点向量(就是用于记录用户点击的位置) touchPoint = new Vector3(); } /**刷新**/ public void update (float deltaTime) { //如果屏幕有被点击 if (Gdx.input.justTouched()) { //此句是难点,重点分析 //touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0)是把得到的点击坐标弄成touchPoint向量 //unproject函数查看源码,得出两部分信息, //第一,把得到的点击坐标,由左上为(0,0)的坐标系--》左下为(0,0)的坐标系。 //(呃,还是详细说下吧,真实的设备的坐标起点都是左上角,而本游戏的矩形框是以左下角为起点弄的坐标) //第二调用了vec.prj(invProjectionView);这么一个语句 //invProjectionView这个参数的意思是结合了“视图”和“投影”矩阵的逆矩阵,vec就是touchPoint向量 //大家其实可以结合刚才draw中重点将的语句来理解, //理想像素(320*480)---经过矩阵(“视图”和“投影”矩阵)----实际像素(x*x) //实际像素(x*x)-----经过矩阵(“视图”和“投影”逆矩阵)----理想像素(320*480) //这样拉伸和压缩的变换以后便能适应大多数设备 guiCam.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0)); //调用辅助类OverlapTester,检测已经转换成理想像素的touchPoint向量是否在理想的playBounds矩形框内 if (OverlapTester.pointInRectangle(playBounds, touchPoint.x, touchPoint.y)) { //播放点击音效 Assets.playSound(Assets.clickSound); //game.setScreen(new GameScreen(game)); return; } if (OverlapTester.pointInRectangle(highscoresBounds, touchPoint.x, touchPoint.y)) { Assets.playSound(Assets.clickSound); //game.setScreen(new HighscoresScreen(game)); return; } if (OverlapTester.pointInRectangle(helpBounds, touchPoint.x, touchPoint.y)) { Assets.playSound(Assets.clickSound); //game.setScreen(new HelpScreen(game)); return; } if (OverlapTester.pointInRectangle(soundBounds, touchPoint.x, touchPoint.y)) { Assets.playSound(Assets.clickSound); //依据Settings类中的成员变量决定声音的开关 Settings.soundEnabled = !Settings.soundEnabled; if (Settings.soundEnabled) Assets.music.play(); else Assets.music.pause(); } } } public void draw (float deltaTime) { //清空画面 GLCommon gl = Gdx.gl; gl.glClearColor(1, 0, 0, 1); gl.glClear(GL10.GL_COLOR_BUFFER_BIT); //更新照相机位置(此处多余,因为这个照相机位置压根没动过) guiCam.update(); //此句是难点,详细分析 //guiCam.combined参数是一个矩阵,兼具“投影”和“视图”矩阵的功能 //“投影”矩阵的作用是改变照相机的大小 //“视图”矩阵的作用是改变照相机的位置 //setProjectionMatrix函数的作用是把矩阵送给batcher计算 //这整个语句可以理解为,batcher这个本来是320*480像素的渲染范围的渲染器, //在经过矩阵的计算后可以batcher的渲染范围可以适应当前像素 batch.setProjectionMatrix(guiCam.combined); //关闭混合(这个貌似是作者为了节约GPU多加的一句,只在渲染背景的时候加) batch.disableBlending(); batch.begin(); batch.draw(Assets.backgroundRegion, 0, 0, 320, 480); batch.end(); //关闭混合 batch.enableBlending(); batch.begin(); batch.draw(Assets.logo, 160 - 274 / 2, 480 - 10 - 142, 274, 142); //这里注意是将3个选项(“play”“HighscoresScreen”"help")只用一个图片表达 batch.draw(Assets.mainMenu, 10, 200 - 110 / 2, 300, 110); batch.draw(Settings.soundEnabled ? Assets.soundOn : Assets.soundOff, 0, 0, 64, 64); batch.end(); } @Override public void render(float delta) { //这里系统会开一个线程不断地调用此方法的 update(delta); draw(delta); } @Override public void resize(int width, int height) { // TODO Auto-generated method stub } @Override public void show() { // TODO Auto-generated method stub } @Override public void hide() { // TODO Auto-generated method stub } @Override public void pause() { // TODO Auto-generated method stub } @Override public void resume() { // TODO Auto-generated method stub } @Override public void dispose() { // TODO Auto-generated method stub } }
OverlapTester类:
package com.zhf.mylibgdx; import com.badlogic.gdx.math.Rectangle; /** * 工具类:检测各种碰撞 * @author ZHF * */ public class OverlapTester { /**检测输入的X,Y是否在输入的矩形框r内**/ public static boolean pointInRectangle(Rectangle r, float x, float y) { return r.x <= x && r.x + r.width >= x && r.y <= y && r.y + r.height >= y; } }
恩,注解都写得很清楚,我想可能还是有初学者还是不太明白其中的细节,其实我有的也不太懂,还是第一段的话,不影响大家整体思路的情况下,我们继续前进,有些东西到后面你就会有整体的把握!
经过上面的代码框架的搭建,运行起来的的效果:
点击“play”“HighscoresScreen”"help"会有音效,点击喇叭会关闭和开启背景音乐
ok ! 第一讲就到这里! 下一讲我们继续学习一下,屏幕之间的切换!
源码下载:http://down.51cto.com/data/893642