上一节已经讲了常见演员的使用,本篇就整体说一下演员.
Actor类
API定义:
在二维场景图中,一个演员拥有的位置,矩形的大小,起点,规模,旋转,和颜色等属性。位置对应且不成比例。演员的位置是相对于演员的父母,它的起点是相对位置,同时可用于缩放和旋转。一个演员也有一个行动,可以操纵的演员在时间段内活动,同时可以加入监听来实现演员接收事件通知。
功能分析:
(1)实现一个可以移动的人物。
(2)人物在不同时间段是播放不同的动画。
(3)人物分3中状态:左走、右走、空闲。
(4)通过2个按钮来实现状态的切换。
(5)添加游戏背景。
编码步骤:
(1)在核心代码项目中,新建一个Person的类,使Person继承Actor类,然后重写其中的draw方法。
public class Person extends Actor
(2)声明变量,将坐标、时间、imagebutton、texture、动画、以及枚举类型等变量声明。
public class Person extends Actor { public float x; public float y; public float statetime; //按钮 ImageButton btn_L; ImageButton btn_R; //人物当前状态(枚举类) STATE state; //对应的动画 Animation animation_left; Animation animation_right; Animation animation_idle; //实时动画 TextureRegion currentFrame; enum STATE { L,R,I; }; }
(3)设置成员变量。
public Person(float x, float y) { super(); this.x = x; this.y = y; this.statetime = 0; this.show(); state = STATE.I; }
(4)动画设置。
动画设置,都写在了show方法里面,这样其实不太好,很乱思路不清晰,这里作为例子就暂且这样
TextureRegion中有一个flip(boolean x, boolean y) 方法,他有2个参数。
第一个参数是负责确定是否沿X轴方向翻转,
第二个参数是负责确定是否沿Y轴方向翻转。
public void show() { //分割动画 Texture animation_file = new Texture(Gdx.files.internal("data/animation2-2.png")); TextureRegion[][] animation_split_right = TextureRegion.split(animation_file,42,51); TextureRegion[][] animation_split_left = TextureRegion.split(animation_file,42,51); Texture animation_file2 = new Texture(Gdx.files.internal("data/idle.png")); TextureRegion[][] animation_split_idle = TextureRegion.split(animation_file2,42,51); //实例化动画图片组 TextureRegion[] textureRegion_right = new TextureRegion[30]; TextureRegion[] textureRegion_left = new TextureRegion[30]; TextureRegion[] textureRegion_idle = new TextureRegion[1]; //向右动画图片组 int i = 0; for(TextureRegion[] animation_split_right_split:animation_split_right){ for(TextureRegion animation_pic:animation_split_right_split){ textureRegion_right[i] = animation_pic; i++; } } //向左动画图片组 i = 0; for(TextureRegion[] animation_split_left_split:animation_split_left){ for(TextureRegion animation_pic:animation_split_left_split){ textureRegion_left[i] = animation_pic; textureRegion_left[i].flip(true,false); i++; } } //原地动画图片组 textureRegion_idle[0] = animation_split_idle[0][0]; //合成动画 animation_right = new Animation(0.08f,textureRegion_right); animation_right.setPlayMode(Animation.LOOP); animation_left = new Animation(0.08f,textureRegion_left); animation_left.setPlayMode(Animation.LOOP); animation_idle = new Animation(1f,textureRegion_idle); animation_idle.setPlayMode(Animation.LOOP); //按钮图片读取 Texture button_file = new Texture(Gdx.files.internal("data/button.png")); TextureRegion[][] button_split = TextureRegion.split(button_file,100,100); //按钮实例化 btn_R = new ImageButton( new TextureRegionDrawable(button_split[0][0]), new TextureRegionDrawable(button_split[0][1])); btn_L = new ImageButton( new TextureRegionDrawable(button_split[0][2]), new TextureRegionDrawable(button_split[0][3])); //按钮位置 btn_R.setPosition(150,20); btn_L.setPosition(20,20); }
(5)设置按钮同时加入监听。
PS:这里的touchdown()方法重写的时候一定要将后面的super返回值,
一定要修改为return true。因为只有按下方法返回true的情况下,touchup方法才执行,
这个需要大家注意,同时还touchup执行的时候要将状态赋会idle。
//按钮监听 (show 方法中继续添加监听即可) btn_R.addListener(new InputListener(){ @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { state = STATE.R; return true; } @Override public void touchUp(InputEvent event, float x, float y, int pointer, int button) { state = STATE.I; super.touchUp(event, x, y, pointer, button); } }); btn_L.addListener(new InputListener(){ @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { state = STATE.L; return true; } @Override public void touchUp(InputEvent event, float x, float y, int pointer, int button) { state = STATE.I; super.touchUp(event, x, y, pointer, button); } });
(6)状态判断与动画选择
由于我们将人物动画分为左走的动画、右走的动画、和空闲的动画,这样我们就要在不同的状态下,使用不同的动画,这样才能符合游戏逻辑,我们创建一个check()方法来实现动画和状态的关联。这里我们用currentFrame来给不同的状态赋值,最后将currentFrame画出来,这样可以节省许多代码。
//状态控制与动画选择 public void check() { if(this.state==STATE.L){ currentFrame = animation_left.getKeyFrame(statetime,true); }else if(this.state==STATE.R){ currentFrame = animation_right.getKeyFrame(statetime,true); }else if(this.state==STATE.I){ currentFrame = animation_idle.getKeyFrame(statetime,true); } }
(7)人物移动。
其实人物移动的原理很简单,但是由于人类思考的误区,总是理解的不很清楚。为了构造人物移动的效果,我们只是在不断变化的坐标的上,绘画出我们做好的动画。这个坐标,我们需要和人物的状态联系起来,人物的状态又是按钮改变的,通过这几种联系,最后就实现了,通过按钮来控制动画的效果了。所以,我们通过update()方法来实现状态和坐标的联系,顺便设置一下“空气墙”,其实就是不让人物超过屏幕。
//人物移动 public void update(){ if(state==STATE.L && this.x>20){ this.x -= 1f; }else if(state==STATE.R && this.x<700){ this.x += 1f; } }
(8)draw()方法
演员类的draw方法中,默认提供给我们一个SpriteBatch和parentAlpha (透明度的意思),
然后我们需要在这里调用判断状态和负责移动的方法,即check()和update()方法。特别注意的是,重写draw方法的时候SpriteBatch中已经给我们写好了 batch.begion 和batch.end方法,
所以我们只需要写batch.draw()就可以了。这样我们就可以将我们做好的动画,在绘画出来.
@Override public void draw(SpriteBatch batch, float parentAlpha) { statetime += Gdx.graphics.getDeltaTime(); this.update(); this.check(); batch.draw(currentFrame, x, y); }
(9)修改MyGame类
演员类必须需要使用到舞台,这是大家都知道的,所以我们在主类MyGdxGame里面,
添加一个Image控件作为背景,然后将Marion和Mario中的button控件加入到stage中。
background = new Image(new Texture(Gdx.files.internal("data/background.jpg"))); stage = new Stage(800, 480, false); Gdx.input.setInputProcessor(stage); Person p = new Person(100,170); stage.addActor(background); stage.addActor(p); stage.addActor(p.btn_L); stage.addActor(p.btn_R); stage.act(); stage.draw();
完整的例子代码如下:
Comments NOTHING