ESSSquareProgressIndicator for iOS and OS X

ESSSquareProgressIndicator animating

What Is ESSSquareProgressIndicator?

It’s an indeterminate progress indicator originally developed for the iOS game ZEN.

It uses Core Animation (specifically, CAShapeLayers) to do its job and it’s pretty straight forward.

CGPathRefs, CAShapeLayer

CAShapeLayer has two animatable properties – -strokeStart and -strokeEnd (with a minimum value of 0.0 – start of path – and 1.0 – end of path). Going beyond 1.0 or below 0.0 doesn’t work.

So when trying to animate those values along a rectangular path – which was the first thing I tried when creating this – you do get a nice animation, but it ends at the 0.0/1.0 (which is, basically, the same) mark. So you end up with something like this:

glitchy progress indicator animation

The goal, then, was to animate beyond 1.0. The solution I came to – I’m sure there are other ways – was to use a second CAShapeLayer that animated alongside the first for the last/first part of the animation.

For a square, the values of the CAShapeLayer’s -strokeStart and -strokeEnd are as follows (starting at the top left corner):

CAShapeLayer strokeStart strokeEnd values

The CGPath begins and ends in the top left corner because I drew the path that way (you could make it start in the lower left corner or in the middle of a side, it all depends on where you start the CGPath with CGPathMoveToPoint).

The progress indicator starts at the middle of the left line and reaches to the middle of the top line. These are the two CAShapeLayers at work. The left part is one shape layer, the top line is another. I’ll do this in pictures I drew in code so it’s simpler to understand (the lines represent where the layer animated to, the dots are the invisible rest of the square).

Animating

Animation Part 1We start at this position. The line to the left is layer2(strokeStart:0.875, strokeEnd:1.0), the line at the top is layer1(strokeStart:0.0, strokeEnd:0.125).

Animation Part 2The transition to this is the reason we need two layers as we can not animate one layer beyond the 1.0 value.
So we animate layer2 to (1.0, 1.0) and at the same time animate layer1 to (0.0, 0.25) which makes it look like one line moving.

Animation Part 3This next part is easy. We animate layer1 to (0.75, 1.0).

Animation Part 4Lastly, we animate with two layers again to get to the initial position so we can repeat the whole thing from there on.
We animate layer2 from (0.75, 1.0) to (0.875, 1.0) and layer1 from (0.0, 0.0) to (0.0, 0.125) at the same time, again making it look like one line moving.

The Source Code

The repository (a sample iOS app, but the class works the same on OS X) is available on Github.

It was developed for iOS 7.1 but should work on earlier systems, and has been tested on OS X Yosemite, but should work on earlier systems as well.

You just drop in an ordinary UIView or NSView and set its class to ESSSquareProgressIndicator. Done. You can then set the color and stroke width right within Interface Builder thanks to the fairly new Xcode macros IB_Designable and IBInspectable.

Open Source

I have some more source code available here (or directly on my github profile page) if you’re interested. If you have any questions or feedback regarding this progress indicator, please be sure to mail or tweet me 😉

Enjoy!

—-
My name is Matt, I’m the developer of Eternal Storms Software. If you’d like to comment, you can catch me on twitter here: [twitter-follow screen_name=’eternalstorms’ show_count=’yes’] or by eMail.

Making ZEN (Part 2)

First Concept of ZENFirst concept of ZEN

After last week’s guest blog post by my cousin Sebastian about how he came up with the idea of the iOS game ZEN, the design and conception process behind it and the soundtrack, today it’s my turn to talk about putting it in code and making it all come to life.

The Premise

Like a lot of developers I know, I became intrigued with programming because of games. As a kid, I always wanted to develop games for a living, make the next Diablo. So of course I jumped at the idea of creating a game when my cousin asked me if I was interested.

I had never actually programmed a game before, so when Sebastian approached me about developing a game with him, I was already seeing myself having to learn OpenGL and everything that comes with it.

Luckily, it soon became clear that it would be a 2D game, almost 8-bit-ish, like an old Super Mario Bros game. So my fears of having to learn something new* were put to rest and the more he told me about the game, the more I realized that Core Animation would be the perfect fit for this project.

The game is about a cube with random numbers on it. Your goal is to reach ten with these numbers by turning the cube and selecting the appropriate sides within ten seconds.

ZEN Cube Animation

*just kidding, I love learning new stuff, but for a side-project having to learn OpenGL would have been a little much, especially with all my other apps that need constant attention

Core Animation actually was pretty much made for this kind of stuff. Even if the game had had some 3D effects (for example, some sort of perspective distortion when turning the cube, etc), it would have been fairly easy to implement.

First Blood

The first thing I did in the process of developing ZEN was to prototype the cube itself. I began by mapping out the cube because a) I didn’t have one handy and b) to get a visual on each side:

Mapping out the cube

Because I was using Core Animation and it was all in 2D space, I had to figure out what side would go where when the cube was turned from left to right, right to left, from the top or the bottom, so that the numbers would stay on the same side and not end up any place they shouldn’t be. I went so far to write down which side would go where once the cube was turned in any direction

Mapping out which cube side would go whereWhich side goes where when turning the cube?

To make the animation possible, I would have to use at least two CALayers that changed in shape and color, and would have to be kept up to date in terms of data (which side holds which number).

One layer would always be hidden, the layer to turn to, so to speak, the other layer would always be visible. They would alternate in doing that.
For example:

Layer 1 is visible with the front number of the cube.
You turn the cube right and layer 2 (still hidden) gets the number of the left side of the cube.
Layer 1 is animated to fold to the right
Layer 2 shows and animates to the full size of the front cube side.
Layer 1 is hidden

Turning Cube Down on PaperTurning the cube from the top on paper

With that done, I had the cube – of course, there were some kinks to be worked out (for example, sometimes the hidden layer would suddenly be visible with a completely wrong size), but basically, the cube was working.
In code, turning the cube upwards looks like this:

- (void)turnUp
{
ESSCubeSide *oldUp = self.topSide;
ESSCubeSide *oldFront = self.frontSide;
ESSCubeSide *oldDown = self.bottomSide;
ESSCubeSide *oldBack = self.backSide;
self._cubeDict[ESSCUBE_FRONT] = oldDown;
self._cubeDict[ESSCUBE_TOP] = oldFront;
self._cubeDict[ESSCUBE_BACK] = oldUp;
self._cubeDict[ESSCUBE_BOTTOM] = oldBack;
}

This is only the data model, of course. The view code just the two layers – resizing them in unison, hiding one layer and showing the other, etc.

Random Numbers

The next thing that had to be done was to fill the cube with random numbers, some of which would add up to ten.

I chose to do the following:

  1. Decide how many sides it takes to solve the current cube (a number between 2 and 6); let’s say it’s 3 – 3 sides to solve the cube.
  2. Loop while we create 3 random numbers between 1 and 9 that add up to ten.
  3. Fill the rest of the cube (3 more sides) with random numbers between 1 and 9.
  4. Shuffle the resulting array of six numbers so the solving sides aren’t always on the same sides
The same principle works for the minus mode, where there are positive and negative integers that you need to select to add up to ten.

Interface

The first interface concept, as you can see in the first screenshot of this blog post, was pretty simple. The title and three buttons. There was no mention of animations!

As it always happens, things change during the development process, you iterate on everything, and the interface gets overhauled as well. This new one was, in my opinion, much nicer as it demonstrates the “cube-y” nature of the game very nicely.

ZEN Line animation

But it took me some time to get there. I was hoping that Sebastian could define the animations in svg or gif or something like that and I could just load them in and display them.
However, I could not do that – apparently iOS doesn’t support svgs or gifs out of the box (and I didn’t want to rely on 3rd party libraries to do the job). After googling around for a couple of days (because, you know, you want to be thorough), I tried doing it in a web view, because these animations would work in the browser. However, I wouldn’t have that amount of control over them as I did with the final approach I took – code it in Core Animation as well.

So I have one view class that, depending on the width and height of the bounds of the view either expands horizontally or vertically. That was the easy part.

The hard part was creating all the views in Xcode’s Interface Builder with the proper dimensions and positioning them so they would define the buttons and letters. I’m just glad the Help – view is not animated 😉 :

Help ViewThe Help View – thankfully for me, not animated

Creating ZEN was a very exciting experience and I learned a lot during the process. As I usually work alone, working within a team on this project (even if it’s just two people) was a breath of fresh air and is a lot of fun, bouncing ideas off of each other, inspiring each other – there’s a whole lot of energy there.
While I do have a few dear friends with whom I can exchange ideas over the internet for my own projects, it’s quite different when you’re one on one, face to face.

It’s been  a lot of fun.

—-
My name is Matt, I’m the developer of Eternal Storms Software. If you’d like to comment, you can catch me on twitter here: [twitter-follow screen_name=’eternalstorms’ show_count=’yes’] or by eMail.

Making ZEN (Part 1)

[Note: This is a guest blog post written by my cousin, Sebastian Gansrigler, about the iOS game ZEN (App Store) he and I developed during 2014]

It was around March 2014, I started to set up a basic idea for a game I wanted to create in my spare time. How about combining a Rubik’s Cube and 3D game mechanics with complex mathematical theory and provide all of this with minimalistic pixel art on a touch interface? ZEN was born.

Basic concept on paper, pixel measurements, final screenBasic concept on paper, pixel measurements, final screen

I can’t really say where the idea came from, the game was always based on the concept of a rotating cube, about revealing something that’s hidden, about stress, learning, advancing and getting better and better by repeating it over and over again. ZEN was a good name: …a school of Mahayana Buddhism that developed in China during the 6th century. The word might be translated as something like “absorption” or “meditative state”.

Since I didn’t want to use any fonts, plugins or other preset assets, I created everything from scratch. Beginning with first scribbles on paper, I subsequently moved on to Photoshop and Illustrator to build a basic grid system, alignment rules, colors, etc. I tried to treat pixels like real pixels, there’s not one element in the game that’s round or off grid. Everything had to be perfectly consistent and at the end, of course, fun to play. From then on I went into After Effects for animations and interactions.

All game elementsAll game elements

One musician I had in mind for ZEN’s sound design was Brian Grainger aka Milieu. He created the original score for “Eufloria”, which I played a few years ago on PS3 and totally loved. I wanted something relaxing, yet stressful and packed with tension. Somewhere between Mount Kimbie, Kavinsky and Baiyon. I wrote him, Brian got on board and created an amazing soundtrack (soon available on his Bandcamp) and all sound effects.

Matthias Gansrigler, my cousin, has created some great apps for OS X and iOS, so I contacted him about the game. He did all the code and actual implementation of graphics and animations. The bug fixing was most fun, as soon as something had been fixed, something else came up. Special thanks to Das Möbel in Vienna for a great location to brainstorm and discuss (and of course for the ham & cheese toasts).

Funny button bugFunny button bug

After quite a bit over half a year of production, the game was completed and went online on December 21 2014 on the App Store for iPhone and iPad.


Sebastian Gansrigler is a 20-year old photographer and designer in Vienna, Austria. He works for WDM responsible for web and graphic design. You can reach him on twitter under @gansrigler.