libGDX Scene2d

来源:互联网 发布:java程序员如何赚外快 编辑:程序博客网 时间:2024/06/05 05:13

概述

相关名词:actor演员stage舞台
scene2d是一个使用actor的层级结构的为了构建程序和UI的2D场景图。它提供了以下功能:
1.对一个group的旋转和缩放也使用于它所有的子actor。子actor总是在它自己的坐标系统中工作,父坐标显然会影响子actor的坐标。
2.简化了使用SpriteBatch的绘制。每一个演员都在它自己的没有旋转没有缩放的坐标系中绘制,它的左下角坐标为(0,0)
3.对于旋转和缩放的的演员的碰撞检测。每个演员决定是否使用它自己的无旋转无缩放的坐标系统来进行碰撞。
4.对于合适的演员的输入和其他事件的处理。事件系统是复杂的。
5.由时间控制的对演员进行控制的Action系统。多个Action可以连接、混合来达到更复杂的效果。
scene2d对于绘制、处理输入事件、HUD、工具和其他的UI都提供了有力的支持。scene2d.ui这个包提供了许多可以用来构建ui的演员。
场景图有一个缺点,就是它结合了模型和视图。存储了数据的演员经常被认作游戏中的模型数据,比如演员的大小和位置。演员也是视图,它知道如何绘制自己。这种耦合使得MVC的分离变得困难。如果单一的使用ui或者应用不在乎MVC,耦合就不是一个问题了。
scene2d中有3个核心的类。Actor类是一个图形节点,它拥有位置,矩形的大小,原点,缩放,旋转和颜色。Group类是一个可以有子演员的演员类。Stage类有一个相机、SpriteBatch和一个根Group,Stage还处理演员的绘制并且分发输入事件。

Stage (舞台类)

Stage是一个InputProcessoress            输入处理器。当它接收到了输入事件,它就把事件传动给合适的演员。如果舞台被当做UI使用的话,就可以使用一个InputMultiplexer来先给舞台一个机会来处理事件。如果舞台中的一个演员处理了事件,舞台的InputProcessor的方法就会返回true,表名事件已经被处理了,不应该被传递给下一个InputProcessor。
舞台有一个act方法,它有一个从上一帧所持续的事件的变量delta time。这造成了每一个演员的act方法都会被调用,允许演员表现出基于时间的动作,即action。默认情况下,演员类中的act方法更新了演员中的所有action。是否调用舞台类中的act方法是可选的,但是如果没有调用的话,那么演员的action和一些其他的事件就不会发生。

Viewport(检视区)

一个舞台的检视区由一个Viewport的实例决定。viewport管理了一个舞台,并且控制了舞台在屏幕上是如何显示的,比如屏幕的宽高比(是否拉伸)和是否显示黑条。
viewport在舞台的构造器中通过使用setViewport方法被指定。如果游戏的窗口时可以被改变大小的,那么就应该在窗口大小发生改变的时候设置舞台的viewport。
下面是一个没有演员的一个游戏的例子,使用了一个ScreenViewport。在这个viewport中,每一个小单元相当于一个像素。这就意味着这个舞台永远不会被拉伸,但是通常情况下舞台要根据屏幕或者窗口的大小来改变大小。
private Stage stage;public void create () {    stage = new Stage(new ScreenViewport());    Gdx.input.setInputProcessor(stage);}public void resize (int width, int height) {    // See below for what true means.    stage.getViewport().update(width, height, true);}public void render () {    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);    stage.act(Gdx.graphics.getDeltaTime());    stage.draw();}public void dispose() {    stage.dispose();}
上面代码中stage.getViewport().update(width,height,true)方法更新了viewport以适应屏幕或者窗口大小的改变。第三个参数设置成ture,这样就能保证在更新viewport的同时,相机的位置也被改变,它被放在舞台的中介,左下角为(0,0)点。如果要自己控制相机的位置,那就传递false。如果舞台的位置没有被设定的话,那么(0.0)点就将在屏幕的中间。
下面是一个使用StretchViewport的例子。舞台的640*480大小将会被拉伸成屏幕的大小,这有可能会改变舞台的宽高比。
stage = new Stage(new StretchViewport(640, 480));
下面是一个使用FitViewport的例子,舞台的640*480的大小将被拉伸来适应屏幕的大小,但是不会改变舞台的宽高比。剩下的空白部分就被黑条占据了。
stage = new Stage(new FitViewport(640, 480));
下面是使用了ExtendViewport的一个例子。舞台的640*480的大小将首先被拉伸到适应屏幕大小但是不改变宽高比,然后舞台的较短的一边将增大来填满屏幕。宽高比没有改变也没有黑条,但是舞台可能会在某个方向上被拉长。
stage = new Stage(new ExtendViewport(640, 480));
下面是一个使用了ExtendViewport的一个例子,但是它有一个最大大小的参数。像前面那样,舞台的640*480的大小首先被在不改变长宽比的条件下被拉伸,然后舞台的较短的一边增大来填满屏幕。然而屏幕的大小不会超过参数中设置的800*480。这个方法允许你在不显示黑条的情况下支持多种宽高比。
 stage = new Stage(new ExtendViewport(640, 480, 800, 480));
大多数使用glViewport的舞台都会显示黑条,所以舞台不能在黑条中进行绘制。glViewprit能够被设置成全屏来在舞台的外边的黑条中进行绘制。
// Set the viewport to the whole screen.Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());// Draw anywhere on the screen.// Restore the stage's viewport.stage.getViewport().update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);

Drawing(绘制)

当在舞台中调用draw函数的时候,它会去条用舞台中每个actor的draw函数。演员的draw函数可以被重写来进行绘制。
public class MyActor extends Actor {    TextureRegion region;    public MyActor () {        region = new TextureRegion(...);    }    @Override    public void draw (Batch batch, float parentAlpha) {        Color color = getColor();        batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);        batch.draw(region, getX(), getY(), getOriginX(), getOriginY(),            getWidth(), getHeight(), getScaleX(), getScaleY(), getRotation());    }}
draw使用了演员的位置,原点,大小,缩放,旋转的属性绘制了一个区域。SpriteBatch被传到draw参数中,这样就是在这个演员的父坐标中进行绘制了,所以(0,0)点就是演员的父亲的左下角。这使得绘制变得简单,尽管父亲被旋转或者缩放。SpriteBatch已经被调用了。如果像上面那样,parentAlpha和演员的透明度结合到了一起,那么演员就会被父亲的透明度所影响。注意,SpriteBatch的颜色可能被其他的演员改变,所以应该在绘制之前设置每个演员的使用的spritebatch的颜色。
如果演员的setVisible(false)方法被调用了,那么它的绘制方法就不会被调用。它也不会接收到输入事件。

InputListner

EventListeners可以添加到演员上来让演员可以被通知到事件。EventListener是一个有handle(Event)方法的接口。实现了EventListener接口的方法使用intanceof来决定是否应该处理事件。为了方便,对于大多数类型的事件都有指定的监听器类。比如,InputListener是用来接受和处理输入事件的。一个演员只需要添加一个InputListener来开始接受输入事件。InputListner有很多可以被重写的方法,下面展示了两个:
actor.setBounds(0, 0, texture.getWidth(), texture.getHeight());actor.addListener(new InputListener() {    public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {        System.out.println("down");        return true;    }    public void touchUp (InputEvent event, float x, float y, int pointer, int button) {        System.out.println("up");    }});
注意,演员必须要设置他的bounds,这样才能在bounds的范围内来接收输入事件。
如果要处理触摸和鼠标事件,重写touchDown,touchDragged,和touchUp。touchDragged和touchUp事件只有在touchDown返回true的时候才会被接收。
要处理触摸或者鼠标进入或者离开一个演员的事件,重写enter和exit方法。
要处理鼠标移动而没有任何鼠标按键被按下的事件,冲下scrolled方法。(只在桌面游戏中)这个方法只有在拥有滑动焦点的演员上被回调,而焦点可以通过调用舞台类的setScrollFouces方法来设置。
要处理按键输入,重写keyDown,keyUp和keyTyped方法。这些都只是在演员拥有键盘焦点的情况下才会被回调,这个焦点可以通过舞台类的setKeyboardFocus方法来设置。
如果演员的setTouchable(false)和setVisible(false)方法被调用了,那么这个演员就不会接收任何的输入事件。

其他监听器

ClickListner有一个布尔常量,当触摸或者点击了这个演员上的一个按钮,这个常量就是ture,并且clicked方法会在演员被点击的时候回调。ActorGestureListner检测单击、长按、滑动、缩放等手势。
actor.addListener(new ActorGestureListener() {    public boolean longPress (Actor actor, float x, float y) {        System.out.println("long press " + x + ", " + y);        return true;    }    public void fling (InputEvent event, float velocityX, float velocityY, int button) {        System.out.println("fling " + velocityX + ", " + velocityY);    }    public void zoom (InputEvent event, float initialDistance, float distance) {        System.out.println("zoom " + initialDistance + ", " + distance);    }});
0 0
原创粉丝点击