android游戏开发框架libgdx的使用(四)--舞台和演员

82
回复
458378
查看
  [复制链接]

0

主题

0

帖子

-11

安币

限制会员

发表于 2012-1-17 11:42:14 | 显示全部楼层 |阅读模式
本帖最后由 loveand 于 2012-1-17 11:45 编辑

我们先看几个游戏截图再来理解何为舞台。

1.jpg

请仔细观察图片中的元素,有些东西是不能动,有些可以动,有些有特效,有些没有。有些是按钮,有些是图片,但是其实它们都可以统一称为演员(Actor)。

而整个游戏界面就是我们的舞台。

2.jpg

再看一个射击类游戏

3.gif

而其中的演员是

4.gif

演员是游戏设计中常用的一个对象,它接受舞台的统一管理,拥有一些公共的事件,比如触摸,点击,但是同时还有自身的响应和属性。

而舞台就是容纳演员的场所。它统一管理所有演员,接受输入,同时提供一个方便的框架操作演员的时间变化。

我们来看一下Stage类:


  1. protected final Group root;
  2. protected final SpriteBatch batch;
  3. protected Camera camera;
复制代码
它拥有一个Group,一个SpriteBatch,还有一个相机。SpriteBatch我们在前几篇说过,这里就不再重复了。Group是一个类,用于容纳和控制演员。但是这里要注意Group本身其实也是继承自Actor。相机我们这里跳过,以后再说,可以暂时理解成一个控制观察视角和指标转化的工具。当我们拥有一个演员后就可以调用addActor方法加入舞台。舞台可以获取输入,但是需要设置。
  1. Gdx.input.setInputProcessor(stage);
复制代码
下面来个列子,控制一个人物前进。

5.gif
控制人物的按钮:

6.png


将所需的图片放到assert中

7.jpg


新建三个类:FirstGame,实现接口ApplicationListenerFirstActor,继承ActorNarrowButton,继承Actor先看一下FirstGame声明一个Stage,然后实例化FirstActor和NarrowButton,将二者加入舞台中,最后设置输入响应为Stage。
  1. package com.cnblogs.htynkn.listener;

  2. import java.util.Date;
  3. import java.util.Random;

  4. import javax.microedition.khronos.opengles.GL;

  5. import android.util.Log;

  6. import com.badlogic.gdx.ApplicationListener;
  7. import com.badlogic.gdx.Gdx;
  8. import com.badlogic.gdx.graphics.GL10;
  9. import com.badlogic.gdx.graphics.g2d.BitmapFont;
  10. import com.badlogic.gdx.scenes.scene2d.Stage;
  11. import com.cnblogs.htynkn.domain.FirstActor;
  12. import com.cnblogs.htynkn.domain.NarrowButton;

  13. public class FirstGame implements ApplicationListener {

  14.     private Stage stage;
  15.     private FirstActor firstActor;
  16.     private NarrowButton button;

  17.     @Override
  18.     public void create() {
  19.         stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),
  20.                 true);
  21.         firstActor = new FirstActor("renwu");
  22.         button = new NarrowButton("narrow");
  23.         stage.addActor(firstActor);
  24.         stage.addActor(button);
  25.         Gdx.input.setInputProcessor(stage);
  26.     }

  27.     @Override
  28.     public void dispose() {
  29.         stage.dispose();
  30.     }

  31.     @Override
  32.     public void pause() {
  33.         // TODO Auto-generated method stub

  34.     }

  35.     @Override
  36.     public void render() {
  37.         Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  38.         stage.act(Gdx.graphics.getDeltaTime());
  39.         stage.draw();
  40.     }

  41.     @Override
  42.     public void resize(int width, int height) {
  43.         // TODO Auto-generated method stub

  44.     }

  45.     @Override
  46.     public void resume() {
  47.         // TODO Auto-generated method stub

  48.     }
  49. }
复制代码
再看一下FirstActor。声明一个Texture用于绘制。在构造方法中获取到高度和宽度,以便于后期的hit时间判断。
  1. package com.cnblogs.htynkn.domain;

  2. import com.badlogic.gdx.Gdx;
  3. import com.badlogic.gdx.graphics.Texture;
  4. import com.badlogic.gdx.graphics.g2d.SpriteBatch;
  5. import com.badlogic.gdx.scenes.scene2d.Actor;

  6. public class FirstActor extends Actor {

  7.     Texture texture;

  8.     @Override
  9.     public void draw(SpriteBatch batch, float parentAlpha) {
  10.         batch.draw(texture, this.x, this.y);
  11.     }

  12.     @Override
  13.     public Actor hit(float x, float y) {
  14.         if (x > 0 && y > 0 && this.height > y && this.width > x) {
  15.             return this;
  16.         } else {
  17.             return null;
  18.         }
  19.     }

  20.     @Override
  21.     public boolean touchDown(float x, float y, int pointer) {
  22.         // TODO Auto-generated method stub
  23.         return false;
  24.     }

  25.     @Override
  26.     public void touchDragged(float x, float y, int pointer) {
  27.         // TODO Auto-generated method stub

  28.     }

  29.     @Override
  30.     public void touchUp(float x, float y, int pointer) {
  31.         // TODO Auto-generated method stub

  32.     }

  33.     public FirstActor(String name) {
  34.         super(name);
  35.         texture = new Texture(Gdx.files.internal("actor1.gif"));
  36.         this.height = texture.getHeight();
  37.         this.width = texture.getWidth();
  38.     }
  39. }
复制代码
NarrowButton中代码绘制部分和上面的以下,主要是有个点击后控制人物行动的问题。修改touchDown事件:通过Group获取到FirstActor,控制x值。
  1. public boolean touchDown(float x, float y, int pointer) {
  2.         Actor actor = this.parent.findActor("renwu");
  3.         actor.x += 10;
  4.         return false;
  5.     }
复制代码
效果:



9.jpg
8.jpg


到此为止一个最简单的人物控制我们已经实现了。但是这个有实例还有很多可以改进的地方,比如方向按钮没有点击效果,人物没有移动效果。我们可以使用Animation来实现。添加一张图片
10.gif


具体的原理我们看一下Animation类:
  1. public class Animation {
  2.     final TextureRegion[] keyFrames;
  3.     public float frameDuration;

  4.     /** Constructor, storing the frame duration and key frames.
  5.      *
  6.      * @param frameDuration the time between frames in seconds.
  7.      * @param keyFrames the {@link TextureRegion}s representing the frames. */
  8.     public Animation (float frameDuration, List keyFrames) {
  9.         this.frameDuration = frameDuration;
  10.         this.keyFrames = new TextureRegion[keyFrames.size()];
  11.         for(int i = 0, n = keyFrames.size(); i < n; i++) {
  12.             this.keyFrames[i] = (TextureRegion)keyFrames.get(i);
  13.         }
  14.     }
  15.      
  16.     /** Constructor, storing the frame duration and key frames.
  17.      *
  18.      * @param frameDuration the time between frames in seconds.
  19.      * @param keyFrames the {@link TextureRegion}s representing the frames. */
  20.     public Animation (float frameDuration, TextureRegion... keyFrames) {
  21.         this.frameDuration = frameDuration;
  22.         this.keyFrames = keyFrames;
  23.     }

  24.     /** Returns a {@link TextureRegion} based on the so called state time. This is the amount of seconds an object has spent in the
  25.      * state this Animation instance represents, e.g. running, jumping and so on. The mode specifies whether the animation is
  26.      * looping or not.
  27.      * @param stateTime the time spent in the state represented by this animation.
  28.      * @param looping whether the animation is looping or not.
  29.      * @return the TextureRegion representing the frame of animation for the given state time. */
  30.     public TextureRegion getKeyFrame (float stateTime, boolean looping) {
  31.         int frameNumber = (int)(stateTime / frameDuration);

  32.         if (!looping) {
  33.             frameNumber = Math.min(keyFrames.length - 1, frameNumber);
  34.         } else {
  35.             frameNumber = frameNumber % keyFrames.length;
  36.         }
  37.         return keyFrames[frameNumber];
  38.     }
  39. }
复制代码
可以看出所谓的动画其实是一张一张的图片不断切换(其实所有的动画都是这个样子的)。我们构造一个图片列表然后根据事件变动不停取出,重新绘制就形成动画了。注意一下传入的时间和图片列表大小的问题,修改FirstActor代码如下:
  1. package com.cnblogs.htynkn.domain;

  2. import com.badlogic.gdx.Gdx;
  3. import com.badlogic.gdx.graphics.Texture;
  4. import com.badlogic.gdx.graphics.g2d.Animation;
  5. import com.badlogic.gdx.graphics.g2d.SpriteBatch;
  6. import com.badlogic.gdx.graphics.g2d.TextureRegion;
  7. import com.badlogic.gdx.scenes.scene2d.Actor;

  8. public class FirstActor extends Actor {

  9.     Texture texture1;
  10.     Texture texture2;
  11.     Animation animation;
  12.     TextureRegion[] walksFrame;
  13.     float stateTime;

  14.     @Override
  15.     public void draw(SpriteBatch batch, float parentAlpha) {
  16.         stateTime += Gdx.graphics.getDeltaTime();
  17.         TextureRegion currentFrame = animation.getKeyFrame(stateTime, true);
  18.         batch.draw(currentFrame, this.x, this.y);
  19.     }

  20.     @Override
  21.     public Actor hit(float x, float y) {
  22.         Gdx.app.log("INFO", x + " " + this.width);
  23.         if (x > 0 && y > 0 && this.height > y && this.width > x) {
  24.             return this;
  25.         } else {
  26.             return null;
  27.         }
  28.     }

  29.     @Override
  30.     public boolean touchDown(float x, float y, int pointer) {
  31.         // TODO Auto-generated method stub
  32.         return false;
  33.     }

  34.     @Override
  35.     public void touchDragged(float x, float y, int pointer) {
  36.         // TODO Auto-generated method stub

  37.     }

  38.     @Override
  39.     public void touchUp(float x, float y, int pointer) {
  40.         // TODO Auto-generated method stub

  41.     }

  42.     public FirstActor(String name) {
  43.         super(name);
  44.         texture1 = new Texture(Gdx.files.internal("actor1.gif"));
  45.         texture2 = new Texture(Gdx.files.internal("actor2.gif"));
  46.         this.height = texture1.getHeight();
  47.         this.width = texture1.getWidth();
  48.         TextureRegion region1;
  49.         TextureRegion region2;
  50.         region1 = new TextureRegion(texture1);
  51.         region2 = new TextureRegion(texture2);
  52.         walksFrame = new TextureRegion[30];
  53.         for (int i = 0; i < 30; i++) {
  54.             if (i % 2 == 0) {
  55.                 walksFrame[i] = region1;
  56.             } else {
  57.                 walksFrame[i] = region2;
  58.             }
  59.         }
  60.         animation = new Animation(0.25f, walksFrame);
  61.     }
  62. }
复制代码
效果:

11.gif


这里注意一下,为什么我们要Texture转为TextureRegion。这是因为在实际开发中的图片是集成在一起的,比如所有角色要用的图片都是放在一张图里,然后分割截取的,对应的辅助方法TextureRegion.split。另外我们可以发现NarrowButton和FirstActor中有大量代码重复了,可能有朋友觉得应该提取一下,其实libgdx已经帮我们做了,可以参考

12.jpg
这里有一些常用的UI控件,估计下一篇可以讲到。


0

主题

19

帖子

4

安币

初级码农

Rank: 1

发表于 2012-1-21 02:39:56 | 显示全部楼层
讲得很详细。
图片也齐全。赞一个
穿拖鞋的学长!

主题

帖子

安币

游客

发表于 2012-1-25 13:52:36 | 显示全部楼层
引用NarrowButton  和  package com.cnblogs.htynkn.listener   中加上.cnblogs.htynkn就出现错误

0

主题

24

帖子

31

安币

初级码农

Rank: 1

发表于 2012-1-28 21:46:08 | 显示全部楼层
真的不错哦

0

主题

14

帖子

22

安币

初级码农

Rank: 1

QQ达人

发表于 2012-2-9 11:32:06 | 显示全部楼层
GOOD!好东西

0

主题

14

帖子

33

安币

初级码农

Rank: 1

发表于 2012-2-15 10:18:44 | 显示全部楼层
不错,有时间学习一下!

2

主题

125

帖子

243

安币

攻城狮

Rank: 3Rank: 3

最佳新人

发表于 2012-2-16 14:52:12 | 显示全部楼层
学习一下

0

主题

10

帖子

19

安币

初级码农

Rank: 1

发表于 2012-3-31 13:48:12 | 显示全部楼层
好~虽然看不懂~。。。。(初学者)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粤ICP备15117877号 )