最近几天没有更新博客,是因为我这两天在学习Libgdx的一个游戏源码,毕竟再怎么研究libgdx游戏引擎的原理,如果不去实践一下,掌握起来还是比较费劲的。(我个人对于一个新的东西的掌握,都是先从HelloWorld开始,然后开始写一些例子,从各个方位去了解他,其中自然有很多底层原理性的东西,不懂是肯定的!但我不会去深究它,因为这样太浪费时间,而且很容易走偏,我会在学完基本上如何使用和了解了它的大体以后,再去慢慢深入其原理,这样的一来一回,学习效率会倍增!)


   好了不多说了,在以后的几篇博客里我会逐步分版本的讲解一下SuperJumper这款游戏,让大家(当然还有我,毕竟我也是初学者嘛! 嘿嘿!)逐渐掌握libgdx这款游戏引擎(框架)的使用方法。


1.游戏介绍:

  这是一款跳跃型的游戏,主人物会一直往上跳,我们只需控制左右移动让其踩在适当的跳台上即可继续的往上跳,最终加到的金币越多, 到达城堡就胜利了。(貌似有点无聊哈,不过我们是来学习它的框架和使用方法的,相信大家学习完之后,自己也能做一个更好玩的游戏哦!)

上个图:

115016556.png    115018651.png

这里游戏源码我们可以从官网提供的SVN上下载(http://libgdx.googlecode.com/svn),我试过了可以的!连接成功后直接检出即可

115629305.png

  当然,这里蜗牛已经将superjumper检出,同时也为大家配置好环境,直接使用即可。下载地址:http://down.51cto.com/data/893457


  这里,我想说一下,因为本人也是初学者,第一次看到源码后不知道从何下手,所以每讲我会将每个版本的源码放出来,方便初学者循序渐进的学习它,相信这样的效率会更高!

   

  好了不多说了,我们一步一步的开始吧!


2.项目创建

  2.1为了方便测试起见,我们整个项目都在desktop上开发运行,大家也可以在android模拟器上试试,真机上就不行了(因为这款游戏需要左右按键的哦)


   步骤:1.点击libgdx文件夹中的gdx-setup-ui.jar

121921403.png


           2.在弹出的窗体中我们来新建项目:

122459777.png

   

      3.下一步,点击launch即可,

122701914.png

   

   4.这样我们的项目已经建立成功,接下来就是找到刚才我们建立项目的文件目录下,用eclipse将其导入到工程下。

122918595.png

导入成功!(第一个:源代码; 第二个:Android版本;第三个: 桌面版本)

123109994.png

 

   ok! 项目已经创建成功!现在我们点击desktop版本右击运行 Java Application 进行测试,弹出一个窗体说明框架正常!以后我们的代码都在第一个MySuperJumper中编写,在desktop中进行测试!!

132819376.png


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;
    }
}


   恩,注解都写得很清楚,我想可能还是有初学者还是不太明白其中的细节,其实我有的也不太懂,还是第一段的话,不影响大家整体思路的情况下,我们继续前进,有些东西到后面你就会有整体的把握!


     经过上面的代码框架的搭建,运行起来的的效果:

142724656.png

   点击“play”“HighscoresScreen”"help"会有音效,点击喇叭会关闭和开启背景音乐


 ok ! 第一讲就到这里! 下一讲我们继续学习一下,屏幕之间的切换!


×××:http://down.51cto.com/data/893642