Tweens & Jugglers: Animating Your Stage

A little late, but hey! better than never ;-) , we will have a look at the linchpin of Sparrow’s animating powers: Tweening.

What’s a Tween, you ask? Let’s have a look at Wikipedia: It tells us that tweening is “the process of generating intermediate frames between two images to give the appearance that the first image evolves smoothly into the second image. Inbetweens are the drawings between the key frames which help to create the illusion of motion.”

That’s about right for Sparrow too. Like e.g. in Flash/ActionScript Sparrow allows you to smoothly transition the (numerical) properties of your stage objects from an initial value N to a final value M in time X.

Tweening Object Properties

Let’s go with a simple real-world example: Imagine a nice little stage containing a blast door that is going to be shut.

For those of you who need a background story: “It’s Oct-13 in 2043. Ruth Lezz, your 25-year old female main character and down-and-dirty mercenary, just intentionally overheated the central nuclear power core of the first human colony on Mars. The automated disaster containment sub-routine of the station’s master control program requires all blast doors to be shut down immediately in order to minimize station personnel casualty numbers.” Knock yourself out! ;-)

What we are going to do is animate the closing of the blast door:

  //Create a door of the blast persuasion.
  //The initial Y value is -440 which means that the door is wide
  //open. (We are going to see 40px of the door.)
  BlastDoor *blastDoor = [[BlastDoor alloc] initWithY:-440];
  [self addChild:blastDoor];

  //Create the corresponding tween and feed him the door object,
  //state the time it takes to close and the final value for Y.
  //In our case this is 0, since we want the door to shut
  //completely.
  SPTween *tween = [SPTween tweenWithTarget:blastDoor
    time:4.0f transition:SP_TRANSITION_LINEAR];
  //Delay the tween for two seconds, so that we can see the
  //change in scenery.
  [tween setDelay:2.0f];
  //Tell the tween that it should transition the Y value to 0.
  [tween animateProperty:@"y" targetValue:0];

  //Register the tween at the nearest juggler.
  //(We will come back to jugglers later.)
  [self.stage.juggler addObject:tween];

…aaand that’s it! We now have an animated blast door that moves (closes) from Y=-440 to Y=0 in 4.0 seconds. Cool, right? But wait, it gets better!

Transition Types

Sparrow offers a variety of transition types which you can use for your tweens. A transition type defines the way the object properties value will travel from N to M, in our case from -440 to 0. Typically you will start with a linear transition (SP_TRANSITION_LINEAR) and your property value will travel from -440 to 0 in a straight fashion. There are, however, some other cool transition types that help adding fun to your animations. Here is a chart of the other currently available transition types:

Sparrow's transition types

For our blast door example it makes sense to let the door fall down from the ceiling instead of slowly lowering it to the floor. So instead of using SP_TRANSITION_LINEAR we are going to do this:

  //Change the transition type to an ease-out-bounce and
  //adjust the tween duration to fit our needs.
  SPTween *tween = [SPTween tweenWithTarget:securityDoor
    time:1.5f transition:SP_TRANSITION_EASE_OUT_BOUNCE];

  //Leave the rest of the code as is.

Alright! The door finally slams into the ground as one would expect it to. It feels way heavier now and heavier means more secure. We achieved that by changing only two variables of our code.

But what if Ruth Lezz needs to get off the station, hacks into the security system and stops the doors from closing? Read on…

Canceling A Tween

Sometimes it may be necessary to cancel a tween while it is already in its tweening phase. There are three ways to achieve that:

  1. You can keep track of your SPTween object and remove it from its juggler when the time has come.
  2. You can remove all tweens of a certain object.
  3. Or you can stop the whole juggler from executing any more tweens.

We are going to use the second option and stop all tweens targeting the door as soon as Ruth Lezz has successfully hacked into the security system:

- (void) closeTheDoor {
  //Create the tween.
  SPTween *tween = [SPTween tweenWithTarget:securityDoor
    time:1.5f transition:SP_TRANSITION_EASE_OUT_BOUNCE];
  [tween animateProperty:@"y" targetValue:0];
  [self.stage.juggler addObject:tween];
}

//This method gets called when Ruth Lezz has hacked the
//security system.
- (void) onSecuritySystemHacked {
  //Remove the tween when the time has come.
  [self.stage.juggler removeTweensWithTarget:securityDoor];
}

So what we did is react to the players actions and stop the blast door from closing as soon as the security system got hacked. That’s enough for today. Keep in touch, because there is going to be more on tweens and jugglers soon!

Soon To Come

  • Jugglers: What are jugglers and how to use them elegantly?
  • The Stage Juggler: What is the stage juggler?
  • Delaying Invocations: How am i supposed to delay method calls?
4 Comments

Twins

In 2009 we decided to develop three iPhone games (namely Find it!, PenguFlip and Twins) with our Austria-based partner Funworld. During the development of our first iPhone game Find it! we saw that there was a need (at this time at least for us) to create a gaming framework that was easy and fast to develop with. Sparrow is the dogfood that came out of it.

While Sparrow and PenguFlip were released at nearly the same time, the third game called “Twins” was waiting in the queue for attention. But now, after several months the release of Twins has come! That is why i thought it would be fun to share some Twins-related info with you.

The Game

Twins was originally released on Funworld’s PHOTO PLAY console and is a fusion between a typical arcade puzzle and a fast-paced action game. While the original release was themed in a very technical style (“Pick a futuristic lock”) we thought it best to put the game into a “Heal an infected patch of body cells” scenario. The rules of the game thou are still the same: Find two equal connectible bacteria aka twins and connect them. Do this as fast as you possibly can.

Twins comes in two editions: Full and Free. Check it out!

Twins Full

Creating The Menu

For Twins we chose a very similar approach as we did for PenguFlip: The game itself is based purely on Sparrow, whereas the main menu (which includes facebook integration, online highscore system, etc. etc.) is based on our house-internal menu system that uses Cocoa. Those lines of code keep us from reinventing the wheel over and over again for each new game and wasting precious time that could have otherwise been invested into improved game-play. After all developers are lazy people, right? ;-)

Twins Menu

Everytime a player starts a round of Twins the menu system seamlessly fades into Sparrow. On each game-over we fade back to the menu system and unload Sparrow and the game code. This is not only pretty straight-forward, but it also helps us to keep track of possible memory leaks. We just need to check memory consumption before and after a game session. If those numbers do not equal, something’s wrong.

Creating The Game Field

Since the game field of Twins consists of hexagons (body cells) which may or may not be infected with twins, it was necessary to separate the twins textures from the background layer as well as the other functional layers such as selection overlays, warnings, beams and such. This allows to easily create some appealing animations.

Twins Game Field

The game field now consists of a maximum of 52 twin cells each containing 4 layers. That is a number of 208 Sparrow objects (+1 parent) for the game field alone. What’s not included is all the dashboard stuff that is displayed around the game field such as a progress meter, a score display, hint texts, message boxes, buttons and the background. Sparrow handles these numbers very well.

Also, in the picture you can see how Sparrow bubbles events up the object tree. For example: a touch on one of the stars textures (4th layer) bubbles up into the Game Field. In order to keep Twins code clean it was obvious to register one single touch event handler on the “Game Field” to catch those user touches.

Creating The Textures

As so many real-life stories do, it all begins with a pizza. One day we were sitting in a pizzeria and started drawing possible twins on the check. Behold the divine finesse of those sketches!

Twins First Sketches

After redrawing a selection of these sketches on A4 and scanning them into the digital world of Apple I fired up Inkscape and created vector graphics for the twins. Here are the scans of the redraws:

Twins Second Drawing

These vector graphics then went into the Gimp, got sliced and diced and received some nice coloring and shading. What came out of it are our final game textures:

Twins Final Drawing

Take Away

So that’s basically it – the rest was iterative coding, drawing and testing. I hope you had some fun reading this and gained a little insight into our ways.

Before i let you off the hook, i have a few questions:

  • We are re-using a Cocoa-based menu system for our Sparrow games. What is your approach with Sparrow and a game menu?
  • The way i created those textures may or may not be the best way to do this. How do you create your textures?

I am looking forward to your comments!

5 Comments

Collision Detection

Collision detection is a substantial part of almost all games. Unfortunately it is also a part where lots of CPU cycles can get lost, resulting in choppy game-play and short battery life. In order to keep calculation costs down, it helps to exit collision detection code as soon as possible. Gradually refining the detection complexity helps doing so. Using Sparrow, we recommend a 3 step approach to collision detection:

Bounding Sphere Check

Start by checking collisions of the bounding spheres of the object. (That’s just another way of saying: check the distance between your objects.) To do that, it helps if your objects have their origin roughly in the center of your objects.
Let’s use an example: the 2 objects you want to check are both images of space-ships. You could make a class “Ship”:

@interface Ship : SPSprite
@end

@implementation Ship

- (void)init
{
  if (self = [super init])
  {
    SPImage *img = [SPImage imageWithContentsOfFile:@"spaceship.png"];
    img.x = -img.width / 2;
    img.y = -img.height / 2;
    [self addChild:img];
  }
  return self;
}

@end

The important thing here is that we moved the image into the center of the SPSprite. If you rotate the spaceship now, it rotates about its center – probably, that’s what you would have needed, anyway.

The image shows the red bounding spheres and the center distance of our two spaceships. Now, to check if the two spaceships collide, we just need to check how far they are apart:

SPPoint *p1 = [SPPoint pointWithX:ship1.x y:ship1.y];
SPPoint *p2 = [SPPoint pointWithX:ship2.x y:ship2.y];

float distance = [SPPoint distanceFromPoint:p1 toPoint:p2];
float radius1 = ship1.width / 2;
float radius2 = ship2.width / 2;

if (distance < radius1 + radius2)
  NSLog(@"Collision!")

That's the bounding sphere test - easy, isn't it? In the image, you can see that the bounding spheres are slightly bigger than the spaceships, so the test is not accurate enough yet. If the bounding sphere test resulted in a collision, we can refine the detection and move on to the next, more exact, check.

Bounding Box Check

For this test, imagine that you draw a rectangle around your object (instead of the circle): a rectangle that is just big enough that all contents of your object fits into it:

Again, we have a look at our spaceships: If both of them are part of the same coordinate system, the bounding box check is super easy:

SPRectangle *bounds1 = image1.bounds;
SPRectangle *bounds2 = image2.bounds;

if ([bounds1 intersectsRectangle:bounds2])
   NSLog(@"Collision!");

The bounds-property is supported by all display objects - including Sprites. It calculates a bounding box that contains all its child elements. Sometimes, the objects are not in the same coordinate system (perhaps they are in different sprites). Fortunately, you can get the bounding box in just the coordinate system you need:

SPRectangle *bounds = [someObject boundsInSpace:self];

Keep in mind, however, that all those bounding boxes are upright rectangles. An SPRectangle object does not have a rotation property! So, if you have a rotated image, the bounding rectangle will grow during the rotation so that the image fits in.

Thus, this method might still be not exact enough - but it will suffice for many purposes. And if it's not exact enough, you can advance to an even more exact collision detection check.

Custom Point Check

In order to check for different shapes of objects, you can test for collisions of special points of an object (e.g.: in a rectangle: the corners.). The SPRetangle class has the method containsPoint:, for exactly that reason.

Custom point checks make it possible to test for even the most peculiar object shapes. However, this test is also the most CPU intensive one and should be avoided if possible.

Conclusion

In the end it's all about starting rough, and then getting more exact. Exiting collision detection early keeps you from bothering the CPU with unnecessary tasks. This not only saves a lot of time in every frame, but can also save precious battery life. Happy colliding!

10 Comments

Sparrow Forum Online

Hello everyone,

my name is Holger and I am, amongst other things, responsible for the Sparrow website.

In order to have a place where we can have discussions and answer your Sparrow questions, I would like to draw your attention to the new Sparrow Forum, which went online just a few minutes ago. This is going to be the place where all of the supporting and helping happens.

We are looking forward to your posts and comments!

’nuff said, see you there!
Holger

2 Comments