关闭

Libgdx专题系列:实例篇 打飞机

标签: Libgdxandroidopengl es游戏移动
11776人阅读 评论(26) 收藏 举报
分类:

声明:

本系列文章使用的Libgdx版本均为0.99版本

Libgdx游戏开发交流群 323876830

 

最近打飞机游戏比较火, 但是这个游戏本身的确没啥好说的, 比较简单, 火的原因可能跟微信平台有关吧,也许还有他本身的意思。 哈哈。

但是对于使用Libgdx练手,算是个好的例子了,四五天时间基本上可以搞定了,这里帖出来自己制作的过程 , 对于新手来说也算是个帮助。  

 

先上截图看看效果吧

声明:以上游戏中用到的图片资源来自于网络,如果冒犯,请告诉我,我会替换掉, 不会用于商用

 

现在来说说这个游戏有哪些需要说明的地方吧。 也是实际Libgdx开发中,注意的。 如果不合适的, 望指正, 再改进。

 

图片资源规格

这里使用的图片来自于网络,基本上不是2的幂次方的宽和高,所以使用了opengl2.0,使用手机在2.2以上

 

菜单界面

包含了背景按钮什么的, 这里使用UI组件就好了,自定义了一个敌机的actor,用于他的动画展示

    private Image bg;
    private Image logo;
    private ImageButton start;
    private Image player;
    private EnemyPlane enemy1;
    private EnemyPlane enemy2;

这里用到了Action的组合,用户敌机和我机的规定路径动作,例如敌机2

        enemy2.setPosition(-enemy2.getWidth(),
                Gdx.graphics.getHeight() / 4f * 2);// 2/4
        MoveByAction enemy2MoveByAction = Actions.moveBy(
                Gdx.graphics.getWidth() + enemy2.getWidth(), 0, 4);// 向右走动
        MoveToAction enemy2MoveToAction = Actions.moveTo(
                -enemy1.getWidth(),
                Gdx.graphics.getHeight() / 4f * 2, 0);// 返回
        SequenceAction enemy2SequenceAction = Actions.sequence(
                enemy2MoveByAction, enemy2MoveToAction);//序列化这两个动作
        DelayAction enemy2DelayAction = Actions.delay(2, enemy2SequenceAction);//延迟2s
        enemy2.addAction(Actions.forever(enemy2DelayAction));// 循环动作
        enemy2.setOrigin(enemy2.getWidth()/2f, enemy2.getHeight()/2f);//设置中心点
        enemy2.setRotation(90);//逆时针旋转90°

 

游戏界面

游戏界面包含了我机、敌机、我机炮弹、敌机炮弹、爆炸、分数显示等

这里的对象没有继承actor,也没有使用stage,其实刚开始是使用这个的,但是由于对象的管理和碰撞检测方便,自己实现了这些绘制逻辑。

 

GameObject

这是所有游戏对象的超类, 主要保存一些坐标,碰撞区域,状态等信息

    private float x;
    private float y;
    private float width;
    private float height;

    protected float stateTime;
    protected int state;
    protected CollisionGeometry geometry;// 碰撞区域集合,相对坐标


敌机,我机,爆炸,子弹

这里都是继承GameObject,实现自己的逻辑和绘制部分,对于碰撞后的处理等操作

例如敌机

    private GameScreen screen;
    private Texture texture;
    private Animation animation;
    private float stateTime;
    private Vector2 speed;
    private int fireNum;

在update和draw中实现自己的逻辑和绘制部分

public void update()
public void draw(SpriteBatch batch)

 

背景的移动
这里刚开始是使用uv变换, 滚动图片的方式实现,但是没有实现成功, uv超过1就出现拉伸现象,没有循环展示,

Texture设置成repeat也不行, 有谁可以实现的可以告诉我下。谢谢啦 。所以我就换了种方式,基本原理是绘制纹理两次,

有一个y来动态改变绘制的位置,也很简单。

private float deltaY;
        spriteBatch.draw(bgTexture, 0, deltaY % Config.HEIGHT, Config.WIDTH,
                Config.HEIGHT, 0, 1, 1, 0);// u v u2 v2
        spriteBatch.draw(bgTexture, 0, Config.HEIGHT + deltaY % Config.HEIGHT,
                Config.WIDTH, Config.HEIGHT, 0, 1, 1, 0);// u v u2 v2

 

对象的管理
这里使用了Libgdx的Array和Pool,基本原理是 把用到的放到array里面,把不用的放到pool里,这样可以节省频繁释放的开销,

有点数据库连接池的味道。

    private final Pool<PlayerBullet> playerBulletPool;// 主角子弹池
    private final Pool<Enemy> enemyPool;// 敌人池
    private final Pool<EnemyBullet> enemyBulletPool;// 敌人子弹池
    private final Pool<Explode> explodePool;// 爆炸池
    private Array<PlayerBullet> playerBulletList;
    private Array<Enemy> enemyList;
    private Array<EnemyBullet> enemyBulletList;
    private Array<Explode> explodeList;


对象的碰撞

这里使用了Colliders和CollisionGeometry两个类,来处理碰撞,配合array使用,非常方便,碰撞后,

会回调,我们可以在里面进行逻辑处理。

例如

Colliders.collide(player, enemyList, playerEnemyCollisionHandler);
Colliders.removeOutOfBounds(playerBulletPool, playerBulletList,
                roomBounds);
Colliders.removeMarkedCollisions(enemyPool, enemyList,
                enemyRemovalHandler);

Handler的处理

    private RemovalHandler<Enemy> enemyRemovalHandler = new RemovalHandler<Enemy>()
    {
        @Override
        public void onRemove(Enemy t)
        {
            notifier.onEnemyDestroyed(t);
        }
    };


分数

分数的显示这里使用了ttf字库,具体的使用方法是

加入gdx-freetype.jar包,和libgdx-freetype.so文件

使用

    private FreeTypeFontGenerator generator;
    private FreeTypeBitmapFontData fontData;
    private BitmapFont mScoreFont;
        generator = new FreeTypeFontGenerator(
                Gdx.files.internal("font/font.ttf"));
        fontData = generator.generateData(40,
                FreeTypeFontGenerator.DEFAULT_CHARS, false);
        mScoreFont = new BitmapFont(fontData, fontData.getTextureRegion(),
                false);

绘制

        mScoreFont.setColor(Color.BLACK);
        mScoreFont.draw(spriteBatch, "score:" + score, 100, 100);
        mScoreFont.setColor(Color.WHITE);
        mScoreFont.draw(spriteBatch, "score:" + score, 100 - 5, 100 + 5);

这里为什么绘制两遍呢,目的是想让他有个不同颜色重叠的效果。

Screen切换

当我们跳到暂停界面,而又想看到我们的游戏界面需要怎么做呢?

这里可以让PauseScreen界面保留一个GameScreen的引用 , 绘制的时候,绘制就行了, 不要执行逻辑就行了。

        gameScreen.draw(delta);
        stage.act(delta);
        stage.draw();

这里就牵涉到个问题, 事件触摸的问题, 有两个界面接受事件, 这里我们可以设置事件为我们的界面处理

        //舞台响应事件
        Gdx.input.setInputProcessor(stage);

当我们回到游戏界面的时候, 在设置回去就ok了。

 

监听事件
这里有个WorldListener和WorldNotifier来监听我机碰撞、敌机销毁等事件,可以播放音乐,添加爆炸等等。

public interface WorldListener {

	public void onPlayerFired (Player player);

	public void onPlayerHit (Player player);
	
	public void onEnemyFired (Enemy enemy);

	public void onEnemyDestroyed (Enemy enemy);

}

可以注册多个, 实现不同的目的,这样逻辑也分的很清楚。

 

好了, 基本上就这样了, 有什么问题,可以留言反馈。

 

PS:

1.这里有人对碰撞的那个Colliders和CollisionGeometry感兴趣, 这里我上传了一个官网的机器人游戏项目,可以参考下

下载地址 http://download.csdn.net/detail/wu928320442/6771707

2.Pool的概念,可以参考Api解释,不难理解的

 

应广大同学的对于源码的关注,代码我已经上传了, 希望对你有所帮助 下载地址

http://download.csdn.net/detail/wu928320442/6777211

 

 

转载请链接原文链接地址:http://blog.csdn.net/wu928320442/article/details/17578125

11
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:187430次
    • 积分:2150
    • 等级:
    • 排名:第18696名
    • 原创:37篇
    • 转载:0篇
    • 译文:0篇
    • 评论:123条
    Android开发交流群
    323876830
    博客专栏