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:
actor.addAction(parallel(moveTo(250, 250, 2, elasticOut), color(RED, 6), rotateTo(180, 5, swing))); actor.addAction(forever(sequence(scaleTo(2, 2, 0.5f), scaleTo(1, 1, 0.5f), delay(0.5f))));
- 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.