Friday, 27 April 2012

Good games ask good questions

While there is no one universally-accepted definition of "game", one thing all games must do is ask the player questions. The following are common questions found in many games:

- "What is the correct path through this maze?"
- "From what angle should you launch this projectile?"
- "How fast can you finish this race?"

Two-player games are no different; the players are still posed questions, only usually from each-other instead of from the game itself.
The Queen's Gambit, Black to move. Should Black take the pawn on c4?
Like a good teacher, games that ask interesting questions in a compelling way can be rewarding to the player. If at the end of each level or section the player feels he or she has learned something then the game has done its job.

In Drawdle, most levels ask some combination of the following:

1) What is the correct shape to draw?
2) With what speed and from what angle should it be launched?
3) (if more than one drawing) What order should they be launched in, and with what timing?

Of the three, the first is by far the most interesting question Drawdle asks. Not only are the possible shapes one can draw practically endless, but drawing is what makes Drawdle unique. Allowing the user to draw their own objects is what separates Drawdle from the many other physics-based puzzle games out there. Many games deal with timing and angles; fewer games involve creation. And for all of the "doodle" games out there, almost none of them let the player actually doodle.

I kept this in mind when I set out to create new levels for the latest Drawdle update (see previous post). I wanted most of the new levels to require the user to draw unique shapes in order to complete them. Also important was ensuring that each level was sufficiently different from previous levels; even good questions become uninteresting if they are repeated too often.

A new level in Drawdle. What shape should you draw in the square box?
The level pictured above is a good example. There are no tricky timings or angles required; the challenge comes from figuring out a shape that will snap all of the rubber bands (brown lines) while not piercing the balloon as well.

Below is a level that I experimented with but ultimately rejected. As you can see, the player is restricted to launching two pre-drawn doodles. I originally thought that figuring out which one to launch first (and where) would be interesting for players, but testing revealed that the solution was too obvious.


Making matters worse, the solution (pictured below) required extreme levels of precision for the angle taken, precision far beyond what players could reasonably be expected to input when playing on a phone or tablet. The result was that success on this level felt flukey and random.


In short, this level did not ask Drawdle's best questions, and the questions it did ask were neither interesting nor fun to answer. Leaving this level out was an easy call.

Monday, 23 April 2012

Trailer

I FINALLY managed to get my arse in gear and make a trailer for the game:




Music: 'una spiaggia a mezzogiorno' by Ennio Morricone, from the film 'Vergogna schifosi' (me neither).


It's in the final stages of testing now so it should be out in a couple of weeks max.










Tuesday, 17 April 2012

Drawdle 1.6 Released on Android

Drawdle 1.6 for Android is now available on Google Play! This update includes ten new levels for Drawdle and three for Drawdle Lite. Corresponding updates for the Nook, Amazon and iOS versions should be available soon.

One of the new levels in Drawdle
All of the levels feature smaller balloons and drawings, which allows for considerably more flexibility. Look for a post here soon discussing some of the factors that go into level design, including an example of a level that didn't make the cut (and why). In the meantime, try the new ones out for yourself!

Sunday, 1 April 2012

Imagine my suprise, when, completely unsolicited and out of the blue, Kate from www.katewillaert.com sent me this brilliant Apple Jack 2 box cover:



Apparently Kate read my comment in the last post about trying to do a cover loosly based on the Mario 2 box art, and with her advanced drawing skills did it herself, properly.

Now, clearly it's a lot better than the mouldy old cover from my last post and I'd love to use it. What concerns me is the legal / moral issue of using something SO similar to the original:


...especially when the game already 'borrows' the pick-up-and-throw game mechanic from SMB2. Even if there isn't a legal problem in using it, I don't want the game to be seen as some sort of Mario tribute, since it's very much its own thing. That said, there's no doubt many more people would click on the game if it had Kate's box art. Hmm.

Anyone have any opinions on this?

Monday, 26 March 2012

Extract, Inject, Kill: Breaking hierarchies (part 3)

In part one I explain the main idea behind this approach and in part two I start this example. Please read parts one and two before reading this post

Although the main ideas of Extract, Inject, Kill is already expressed, it's good to finish the exercise just for completion's sake. Here is where we stopped:

Let's have a look at the VoucherPricingService, that now is the only concrete class at the bottom of our hierarchy. 


Note that it uses the VoucherService class to calculate the voucher value.

Before anything, let's write some tests to VoucherPricingService.java




Once thing to notice is that the User parameter is not used for anything. So let's remove it.

Now it is time to user the Extract, Inject, Kill on the VoucherPricingService. Let's Extract the content of the VoucherPricingService.applyAdditionalDiscounts(double, String) method and add it to a class called VoucherDiscountCalculation. Let's call the method calculateVoucherDiscount(). Of course, let's do that writing our tests first. They need to test exactly the same things that are tested on VoucherPricingService.applyAdditionalDiscounts(double, String). We also take the opportunity to pass the VoucherService object into the constructor of VoucherDiscountCalculation.

If you noticed, when doing the extraction, we took the opportunity to give proper names to our new classes and methods and also to pass their essential dependencies to the constructor instead of using method injection.
 
Let's now change the code in the VoucherPricingServiceto use the new VoucherDiscountCalculation and see if all the tests still pass.


Cool. All the tests still pass, meaning that we have the same behaviour, but now in the VoucherDiscountCalculation class, and we are ready to move to the Inject stage.

Let's now inject VoucherDiscountCalculation into PricingService, that is the top class in the hierarchy. As always, let's add a test that will test this new collaboration.

And here is the changed PriningService.

Now it is time to kill the VoucherPricingService class and kill the PricingService.applyAdditionalDiscounts(double total, String voucher) template method, since it is not being used anymore. We can also kill the VoucherPricingServiceTest class and fix the PricingServiceTest removing the applyAdditionalDiscounts() method from the testable class.

So now, of course, we don't have a concrete class in our hierarchy anymore, since the VoucherPricingService was the only one. We can now safely promote UserDiscountPricingService to concrete.

That is now how our object graph looks like:


Our hierarchy is another level short. The only thing we need to do now is to apply  Extract, Inject, Kill once again, extracting the logic inside UserDiscountPricingService into another class (e.g. UserDiscountCalculation), inject UserDiscountCalculation into PricingService, finally kill UserDiscountPricingService and the calculateDiscount(User user) template method.  UserDiscountPricingService, 

Since the approach was described before, there is no need to go step by step anymore. Let's have a look at the final result.

Here is the diagram representing where we started:

  After the last Extract, Inject, Kill refactoring, this is what we've got:


The cool thing about the final model pictured above is that now we don't have any abstract classes anymore. All classes and methods are concrete and every single class is independently testable. 


That's how the final PricingService class looks like:


For a full implementation of the final code, please look at https://github.com/sandromancuso/breaking-hierarchies

Note: For this three part blog post I used three different approaches to drawing UML diagrams. By hand, using ArgoUML and Astah community edition. I'm very happy with the latter. 

Saturday, 17 March 2012

My first attempt at 'box art' for the game, adapted from one of the intro frames (drawn by Neilw). Honest opinions and improvment advice welcome, since I can't decide whether it's any good or not.

Wednesday, 7 March 2012

Drawdle out now on iPhone and iPad!

It took a lot of work, but Drawdle is out now for iPhone and iPad! Click on the image below to view Drawdle in the App Store:


Whereas Drawdle was broken up into separate "Lite" and Full versions on the Android Market (and Amazon App store), I've decided to combine them into one app for this version. Levels beyond the first twelve are "locked" and can be unlocked via a 0.99 USD in-app purchase. This is a little less work for me in terms of maintenance (I won't have to upload multiple apps for each version upgrade) and hopefully produces a better conversion rate. It will be interesting to see how this performs; unfortunately a direct comparison to the performance of the Android version won't mean much since the platforms are apples and oranges anyway.