Stage API changes: Viewport added

noone had a great idea, to provide a Viewport class for determining how world coordinates are scaled to screen coordinates. This was already possible using Camera of course, but it was not noob friendly. Viewport is standalone and just manages a Camera. This means any app that uses Camera can use Viewport to control the strategy for scaling the world to the screen. For example, maybe you want to stretch the world to the screen, or scale it up without changing the aspect ratio by using black bars.

After a couple iterations we’ve now integrated the Viewport class. It’s quite slick, you just pick from one of the ready made Viewport implementations and you’re good to go. See the nice wiki page for docs.

Here’s where I tell you about the pain you are in for! It makes sense for Stage to have a Viewport instead of a Camera (remember Viewport has a Camera). This makes controlling scaling for scene2d super easy, but the bad part is Stage had to change. Instead of telling the Stage the viewport size, you give it a Viewport instance that does what you want.

If your old Stage construction code looked like this:

stage = new Stage(width, height, false); // OR
stage.setViewport(width, height, false);

Then you need to change it to:

stage = new Stage(new StretchViewport(width, height)); // OR
stage.setViewport(new StretchViewport(width, height));

If your old code looked like this:

stage = new Stage(width, height, true); // OR
stage.setViewport(width, height, true);

Then you need to change it to:

stage = new Stage(new ExtendViewport(width, height)); // OR
stage.setViewport(new ExtendViewport(width, height));

There is another important change, resize used to look like:

public void resize (int width, int height) {
    stage.setViewport(width, height);
}

Now you’ll do this:

public void resize (int width, int height) {
    stage.getViewport().update(width, height, true);
}

The boolean centers the camera if true (only really needed for UIs). It can be omitted, which is the same as false.

The other changes that may affect you are where you are using the Stage’s Camera. You can use stage.getViewport().getCamera(), but note that Viewport has project/unproject methods that should be used instead, since they take the viewport into account.

Not too bad for you guys I hope!

scene2d.ui Selection

scene2d.ui’s List has never been terribly feature-packed, mostly because it only really sees use in SelectBox. I ended up needing it for skinning in Spine, so it got some love.

First, it can now draw a background which makes it easier to use outside of a ScrollPane. I figured even a Label has a background in its style, so why not.

Next I needed multiple selection, so I set off implementing it. While this seems like such a simple task, just managing a list of selected objects, it turns a proper implementation is quite a chunk of code: more than 250 lines. This is literally larger than the rest of the List implementation! SelectBox and Tree also have selection, and their implementations aren’t really complete. Given this, I decided to create a class called Selection which handles that, and List, SelectBox, and Tree can use it.

Selection turned out pretty nice. At its core it is an ObjectSet with set, add, remove, clear methods. The choose method handles the logic for changing the selection based on user interaction and has features like multiple selection, holding ctrl, toggle, etc. When the selection is changed a ChangeEvent is fired on an actor. If the event is cancelled, the change to the selection is reverted.

Now the bad news, List, SelectBox, and Tree had to change to accomodate the new class. Here are the API changes that may impact you:

  • List and SelectBox previously used strings for the items and you had to correlate the string or selected index back to your list of actual objects. Now they use generics, so you can store your actual objects in the widget, eg List. To get the old behavior, use List or SelectBox.
  • List and SelectBox no longer take items in their constructor. Instead, call setItems after construction. There is now a setItems that takes varargs, which is convenient.
  • Most selection methods having moved to Selection, which you get from getSelection(), but a few stayed behind:
    • getSelection() -> getSelected() or getSelection().first()
    • setSelection() -> setSelected() or getSelection().set()
    • getSelectionIndex() -> getSelectedIndex()

As always, sorry for the API breakage! This effort and your pain is for the greater good. I had to fix up my 50k+ LOC scene2d.ui application so, as your dad probably used to say, this hurts me more than it hurts you. ;)

Global Game Jam 2014 – Holy Cow, that was fun


Despite my unwillingness to do anything but couching on weekends, i got my lazy ass up this friday to check in on the crowd gathering for the first Global Game Jam here in Graz. The Graz event was organized by Spraylight, a young startup working on gaming middleware called Murl Engine which you should totally check out, cause it’s awesome (and in C++!).

It was my first Global Game Jam and my first jam working in a team. What follows is my account of what happened from friday to sunday, more from a social than from a technical perspective.

Friday, Getting to Know the Folks

The event started at 4:00pm local time and was taking place at Graz University of Technology. Upon arrival all participants where greeted with free snacks and drinks and a few tables to gather around to get to know each other. At 5:00pm we went to one of the bigger lecture rooms to watch the key notes and theme announcement. Around 30 people found their way to the jam, a number i didn’t anticipate. I always thought Graz was free of game devs. The theme turned out to be

We don’t see things are they are, we see them as we are

Naturally, it was received with blank stares. Wolfgang, organizer of the event and co-founder of the previously mentioned Spraylight randomly assembled 4 teams through a fancy Excel sheet. Each team had to brainstorm game concepts for the next 30 minutes. After that period, the teams returned to the lecture room to pitch their game ideas. Each pitch lasted 1:30.

After the pitch round, people had to decide which game idea they want to work on, building new teams. Out of 8 ideas, only 4 survived, with team sizes from 5-8 people per team. Our team was largely composed of the same people that already brainstormed the idea (changing worlds). Here’s team awesome, which i had the luck to be a part of:

teamawesome

From left to right: Jörg (programmer/generalist), Markus (programmer, co-founder of Xcessity), Stefan (audio, neorate music), Andreas (programmer, Spraylight), Veit (programmer), Gabe (visuals) and yours truely (lazy bum). Not in the picture: Dizzy (programmer, Spraylight), who sadly didn’t make it back for the group photo.

After our team was assembled, we were assigned a room to work in. We had a few more hours until midnight to improve on the game idea. The discussion was going slow as molasses. Nobody had a clear idea of what the end result should look like. We discussed everything; from turn/dice based mechanics to hack n’ slash. In the end we were none the wiser. However, it was the perfect way to get to know the personas i would be working with for the next two days. We got kicked out at midnight, to return the next morning, saturday, 9pm.

Saturday, Split Personality

One of the last things we decided upon friday night was how to implement this vague idea of ours. We had 6 programmers, one visual artist and one audio guy. We agreed that having 6 programmers work on a tiny code base would do more harm than good, so we split the programmers into two teams. We figured that we could implement different game mechanics in parallel on day one and then go with whatever works best.

Team Murl was composed of Andreas, Dizzy and Markus. Since Andreas and Dizzy are the makers of Murl Engine, they naturally decided to try it out in a jam environment. Markus joined them to balance out the teams (and cause he’s interested in Murl Engine’s capabilities). Team Murl went on to create a 3D version of the idea, using their in-house engine (C++, cross-platform, scenegraph based, fancy).

Team libgdx was composed of Jörg, Veit, and myself. I was open to try something new, e.g. Jörg proposed to use some HTML5 framework or vanilla canvas. I honestly do not know why, but in the end we decided to use libgdx. Jörg comes from C++/Blender Game Engine and didn’t have previous experience with libgdx. Veit knew about libgdx, but didn’t have direct coding experience. Jörg’s more of a veteran than Veit, so he simply blew through our docs, created a quick few tests for rendering and input, and was comfortable after an hour or so. Veit and i figured out Tiled in the meanwhile. Additionally, i gave him a very rough intro to libgdx, showing him just enough basics so he could code along. We agreed to use Github to share the code between us (Veit only had SVN experience, so he received a Git crash course as well). Once everyone was setup, we started to delegate work. I quickly threw together a basic engine for screen management and the business logic of the gameplay, allowing us to work on separate things in parallel. In the meantime Jörg got the rendering and level loading going, while Veit created the first map of the game in Tiled.

Gabe and Stefan started doing their thing in parallel, sharing graphics and audio via SVN with both Team Murl and Team libgdx.

As the day went by, there was barely any downtime for anyone on Team libgdx (plus Gabe, who arted his little heart out :D). Through some magic we managed to keep ourselves busy, without creating permanent merge conflicts. At the end of saturday, we had a pretty playable thing together, lacking polish, audio and most of the screens necessary for a full game experience.

Team Murl also soldiered on. Dizzy and Andreas alternated between teaching Markus the basics of Murl Engine and working on the jam game. This went pretty well until some mysterious person showed up, who had commercial interested in Murl Engine. All of saturday afternoon, Dizzy and Andreas essentially did an improvised sales meeting and couldn’t work on the jam entry. Markus had to leave early, which meant that the Murl Engine version of the game was quite a bit behind. My highlight was when we shared our collision detection code with Team Murl, prompting them to recognize that “Java guys can do something right sometimes as well”.

It was a strange day. I have worked in a lot of teams in my life, amateur and professional (though the difference is usually non-existant). I can’t remember that i’ve experienced anything like what i experienced on saturday. Team libgdx just worked, with occasional synch points where we reprioritized the work that needed to be done. All tasks where kept on a whiteboard. If someone finished a task, it was marked as such, allowing folks to see the current state without interrupting the others.

I was especially impressed with Gabe and Veit. As far as age is concerned they are still essentially babies (early 20ies), but they both have really strong organizational skills on top of their coding/design/art skills. Gabe blew me away by intuitively considering proportions, pixel densities, file naming and anything else that makes a great technical artist. It has taken me weeks to explain the importance of these things to a bunch of other “professional” game artists i previously worked with. On top of that, he’s a brilliant visual artist. Veit demonstrated his organizational skills early on during the game pitch design phase. He was the only one taking notes, without being asked to, guided the discussions, and made sure there was at least some outcome at the end. He carried that over into the implementation phase, adding level design and smaller coding jobs to his task list. I’m pretty sure we’ll hear about these guys sometime in the future.

Stefan’s impact on the project was inversely proportional to his on-site attendance. He’s been with us only for a few hours, gathering requirements concerning the sound track of the game. Only to drop 2 amazing music tracks and around 20 extremly fitting sound effects in record time, simultaniously creating the audio for two other games (much like Gabe who helped other teams out as well). I had the honor of integrating his work into our version of the game, and boy did i have a grin on my face the first time i played it with audio. It’s sad how little attention is paid to audio by both developers and players alike. It has as much impact on a game than the visual style. Stefan nailed it. If you are interested in Stefan’s services, go to Neorate Music. He’s actively searching for movie and game dev related audio work.

No special shout out to Jörg, cause he already knows how fucking good he is :D Check out his brilliant Blender audio library.

I got home at 0:30am, took a shower, and hit the pillows.

Sunday, Good Guys Finish First

We were told the deadline would be 3pm local time, sunday. I suggested we set our own deadline to 2pm to have a 1 hour buffer for deploying and uploading our stuff. Turned out that was a good idea, the Global Game Jam servers were flooded, and it took us quite some time to get our zip up there. Shortly after we were ready to publish our build, Wolfgang told us that the actual deadline is 5pm :O. We were already pretty happy with what we had, so we took another hour to do some more play testing and add some final polish. We handed our build in at 3:30pm, without any stress.

Team Murl regained their spirits after their unlucky saturday. Both Andreas and Dizzy worked frantically to get as much of the 3D version done as possible. In a matter of a few hours they closed in on our feature set, only missing enemy AI and the menu screens. Despite not delivering a full featured game, they demonstrated that Murl Engine is more than suitable for fast prototyping, provided you can actually spend your jam time on coding, not sales.

All teams managed to submit their games in time. You can find all of them here. Team libgdx’s entry is Dodgeball Hospital (yes, we used a name generator), Team Murl’s is Dodgeball Hospital 3D. Here’s what the gameplay looks like (in one of its modes):

Play It!
Source!

With all the games done, it was time for demos. Each team had 10 minutes to demo their game to the other teams, using the big ass lecture room projector and sound system. After that it was hands-on time outside the lecture room. Every team setup a table with their game for others to try out. Eventually each team had to rate each others game, to determine who won Global Game Jam Graz.

Our team won!

My personal winner was Gone. It features a brilliant 2 player mechanic: the first player is in control of a character that needs to navigate a set of rooms towards a goal. Twist: that player is not allowed to look at the screen. Instead she is supposed to wear headphones and use sound to navigate the level. The second player can guide the first player through the rooms by clicking objects that will then generate positional audio. I only played it once, as player one, and i felt right at home. It’s a brilliant concept and i hope the guys develop it into a full featured game.

Special thanks goes to the organizers, especially Wolfgang Moser. We jammers had everything we could ask for, from tidy rooms, to drinks, breakfast, snacks, pizza, whiteboards and so on. All free of charge. You guys outdid yourself, i’m sure we’ll all be back for GGJG 2015 :)

And that’s that. What better way to spend a weekend: working with gifted and fun folks, creating something you’re proud of, and making new friends (even some who know what int 21h and 0xa000 mean).

p.s.: 2 games where made with libgdx, 1 with Murl Engine, 1 with Unity, 1 with Go. :D