scene2d updates

libgdx has a 2D scene graph, cleverly named scene2d. It supports rotated and scaled actors, hit detection, input, etc. On top of it we’ve built a small UI framework, scene2d.ui. Even though all of this has been a bit messy and severely underdocumented, lots of people make use of it. It’s been a while without an update and it has become obvious that it could be improved in a few areas. Lots of refuctoring has been done over the past few weeks. Mostly only scene2d has been affected, but there were a few other changes that may affect you. I will mix them in so you have to read about all the super cool scene2d stuff, even if you don’t care! Some highlights:

  • Public fields are gone, replaced with setters and getters. This turned out not to be so bad. It is often more convenient, since you can now call setBounds(x,y,w,h) on one line, rather than four lines of field assignments. The methods also help make the API more consistent. While most are simple, in a few cases methods are needed to do something more interesting, and mixing fields and methods gets ugly. BTW, Eclipse has a Quick Fix (ctrl+1) for “replace field access with getter/setter”.
  • The action system has been rewritten. It is simpler, more powerful, and has more actions. Action pooling is easier. Relative actions (moveBy, rotateBy, etc) can be combined, even if they operate on the same properties. The syntax has improved, utilizing a static import rather than weird dollar signs, eg:

  • The input event system has been replaced with a generic event system. This system can be used for any kind of event that actors might care about. Eg, touch events, a slider value changing, a selectbox selection change, or your own events. Previously, to handle an input event, the actor needed to be subclassed. Now a listener can be added to any actor to receive input events. Listeners are provided for common handling, such as detecting clicks. There is even an ActorGestureListener that makes it easy to receive gestures like pinch zoom, fling, pan, long press, etc.

    Each actor has a list of listeners that are notified for each event. Similar to the DOM event model, events are propagated in two phases. First, during the “capture” phase an event is given to each actor from the root down to the target actor. This gives parents a chance to intercept and potentially cancel events before children see them. Next, the event is given to each actor from the target up to the root. This allows actors to handle an event themselves or let the parent have a try at it.

  • Two new input events have been added: enter and exit. These are fired whenever the mouse or a finger touch enters or exits an actor. This was difficult to achieve with the old system, now it is provided.
  • InputProcessor has changed, touchMoved has been renamed to mouseMoved. touchMoved didn’t make sense, as this event only occurs on the desktop when the mouse moves, no touch is involved.
  • TextureRegions and NinePatches in all UI widgets have been replaced with an interface called Drawable. This has a draw method and some simple metrics. A few implementations are provided: TextureRegionDrawable, NinePatchDrawable, SpriteDrawable, etc. This allows for more powerful UI skinning, as you can draw anything you like for backgrounds, etc. SpriteDrawable enables whitespace stripped regions from a texture atlas to be used in a UI. Skin automatically handles drawables in JSON style definitions.
  • FlickScrollPane is gone and ScrollPane has become more powerful, gaining all the abilities from FlickScrollPane and more. Scrollbar drawables are optional, so it can be configured to operate exactly like FlickScrollPane used to. If scrollbar drawables are provided, they can be configured to fade away after touch scrolling. Touch scrolling can be disabled, so it can behave exactly like the old ScrollPane. With the new event system, you have control over propagation of events inside the scrollpane. Widgets that would normally trigger touch scrolling, such as a slider, now work inside a scrollpane.
  • Various utility classes have been added. Pool.Poolable is an interface with a reset method that is called when an instance is put back in a pool, making it easier to recycle objects. ReflectionPool uses reflection to construct instances, which can often get rid of the boilerplate involved with subclassing Pool. The Pools class has a Map and static methods for obtaining and freeing objects, which makes pooling very easy. The Timer class is an efficient way to have tasks executed in the future. DelayedRemovalArray and SnapshotArray provide different ways of handling concurrent modification.
  • GestureDetector has been changed to use floats. Previously it only worked with screen coordinates, so it used ints. For it to work with scene2d it needed to be changed.
  • Everything has proper javadocs. That is, proper by my own crazy standards, which are an attempt at providing all the information without leaving out anything crucial OR being too verbose. We don’t pretend javadocs are the only documentation needed. Real documentation is in the works.

Various other refuctoring has been done in scene2d, methods renamed, constructors changed. We know this causes many of you a small amount of pain, but it improves the quality of the library. Hopefully you find the improvements worthwhile. Of course, if you are planning to release soon, now may not be a good time to upgrade.

All of the above work has been done in the “scene2d-new” branch. We would love your feedback, so if you have a little time, please feel free to do a code review. You can submit your feedback via email or come on IRC and chat. Act now, because in a couple days we will merge the branch with trunk. Now is a good time to give feedback on parts of libgdx you’d like to see improved, in scene2d and beyond.


Edit: The first part of the scene2d documentation is done. This is for the core of scene2d, so it is a little low level if you are only using it to build UIs. More coming soon.

24 thoughts on “scene2d updates

  1. Great news. I love that $ is gone and that there is color action now. Would be nice if we could also count how many seconds/frames of animation are left – so we can stop rendering when there are none (for group, stage, actor).

  2. The problem I have is that I start a lot of actions sometimes (for example for animating cards in solitaire) – every one of them with different number of frames (so they end at different frames) and it’s hard to keep track for how many frames I have to keep rendering (I tried counting it and I ended up having the rendering stop too soon – probably because I ommited some action by mistake). “boolean stillAnimating()” method would be enough. By RunnableAction you mean a callback, with a counter maybe to acertain how many actions are still working?

  3. Yes, you could use a RunnableAction with a counter at the end of your action sequence. Or you could check each of the actors to see if they have actions running.
    boolean stillAnimating = actor.getActions().size > 0;

  4. Ow it’s not in trunk yet, but here’s my first suggestion, can all ui elements (eg labels) be made to work with all animation actions?

  5. The “actor.getActions().size” is exactly what I was looking for. Is it a new thing though? Because I don’t have “getActions()” method in my older project’s Actors (I use a month old version of libgdx).

  6. Could be. The entire codebase was gone through to make sure things made sense, stuff has getters, etc.

  7. The way i integrated non-continuous rendering with actions was to subclass the few actions i had and set a static boolean to true everytime the act() method was invoked. Works pretty well and is totally independent of the silly action itself.

    We should totally make a release before we merge the branch with trunk :p

  8. Nate, you push your new scene2d code to a “scene2d-new” branch, and it not complete yet, right? And when it complete it will merge to the master, right? It is in 0.9.5 version ?

    My project use lots of scene2d.ui (my game ui almost fully use Widget or WidgetGroup), I think maybe change many code. ╮(╯▽╰)╭

    But it’s a great job.

  9. @frustaci, all actors work with actions. scene2d.ui widgets have some limitations, they need to be screen aligned for clipping to work. UIs can be animated though.

    @mingming, we will do a new version before merging scene2d-new with trunk. You can stick with that if you don’t want to change all your code.

  10. Nice, sounds like using this would have saved me a lot of time 😀

    I’ll have to check it out on the next game. I also still need to get LibGDX compiling so I can see how everything works.

  11. @Nate Sounds great.. i’m refactoring right now with the new trunk. Having a hell of a time to remove all these .$ signs and such =)

  12. Any reason not to include the method removeActor(…) in the new re-factored:
    com.badlogic.gdx.scenes.scene2d.Stage ?

    Thanks for the great stuff you are making by the way.

  13. Hi there! What about “name” variable of actors and “setParent” method? I think it’s very helpful, i use it often, and now it’s gone. “setParent” method is sometimes needed when you want to change the parent, i think it’s necessary. Comment my post please. Thanks!

  14. It’s hard to arrive just now on Java and LibGDX 🙂
    Most of the tutorials are now a bit deprecated.
    Nice thing about the .$ as it was the first clueless moment I had during the learning.

    By the way, the native Pyramid example for Box2D is running extremely slow. Like 1 frame every 5 seconds. Can you confirm this?

  15. Edit, sorry my mistake: I wasn’t running it from the gdx-tests-lwjgl project. Now it’s working as intended 😀

    I wonder through if any backend to JavaFX 2.0 is planned?
    Or SWT, at least including the one from Marc into the gdx-setup-ui ( I don’t know if it’s still up-to-date?

    Now that TWL is deprecated too I feel a bit unsure about ingame editor for my game…
    Maybe I need to give scene2D.ui a try and be creative about it.

  16. @vasil, too many ways to remove actors. Just use actor.remove().

    @Alex, we decided actor names were not worth the overhead of a map per group. You can easily implement a named actor map yourself, but usually you’ll manage references of actors in fields or data structures and won’t need to look up anything. As for setParent, same reason stage.removeActor is gone, too many ways to do the same thing. Just use parent.addActor methods, which are also better because you can control z-index. Removal from any previous parent is done automatically if an actor is added to a new parent.

  17. I just updated to latest nightly yesterday to prepare for the next release. The refactoring seems promising but I encountered a few problems.

    I’m having troubles with NinePatch int the JSON file, I didn’t figure out how to add one. I saw the new wiki article about scene2d but the JSON section is a bit slim (or it’s just me that doesn’t get it 😉 )

    Also, the Label constructor that takes a string for the LabelStyle doesn’t do anything, it always looks for “default” instead of the specified string.

    Keep up the good work 🙂

  18. Label is fixed, thanks!

    Ninepatches come from the texture atlas now. I updated the documentation to be more clear.

  19. Ah! I see. I mistook the link at the top of the page as a bit of a ‘check out our book’ message. My mistake. Thank you.

Leave a Reply

Your email address will not be published.