Categories
Nerd Fun Programming

Emoji Tac Toe Opened Sourced

Happy Father’s Day!

 

To celebrate my 28th Father’s Day I’ve opened sourced Emoji Tac Toe. It’s actually not a big deal to anyone but me. It’s kinda of scary open sourcing code that you wrote alone and without first cleaning it up. But what the heck. If someone can learn something from this code, why keep it locked away. It’s already been on GitHub for a year. It’s not getting any prettier under lock and key.

You can find the source code at github.com/jpavley/Emoji-Tac-Toe2. And you can download the iOS app on the App Store at John Pavley > Emoji Tac Toe.

You can play Emoji Tac Toe on your iPhone, your iPad, and your Apple Watch. (As long as you are running iOS 9.3 or later.)

I guess I should chat a little bit about the code just in case you want to take a peek.

First

I plan on refactoring the code quite a bit. I want to basically refactor it so that the core is separate from the iOS implementation and I can port it easily to the web and to Android. Maybe Windows too. Who knowns! I’m going to start this process by adding unit tests and then by tearing it apart.

Second

I plan on updating the code for iOS 11, including Swift 4 and ARKit. I’ve been meaning to add multiplayer over BlueTooth and MessageKit capabilities. I also want to complete the tvOS and macOS implementations.

Third

The core code lives in the EmojiTicTacToe.swift file. Since there are more emoji than I can count I have cherry picked the 1100 that I wanted to include. This is still too many and I should cut it down further. It’s too many emoji because choosing which emoji to play with is difficult. I can’t use Apple’s keyboard user interface because I can’t restrict it to just showing emoji. And I don’t want to waste my time recreating Apple’s design. Also, this game is not about typing anything so a keyboard doesn’t make sense.

Instead I create an array of emoji and it works very well. iOS is great at dealing with Unicode.

Tic Tac Toe is an ancient game and simple. There only eight winning vectors. So, it’s easy to brute force and just check any board for the eight vectors.

As emoji are text it’s simple to translate a game board into a string and back. Interoperability with messaging and tweeting is free. This is why I love emoji! Rich graphics without the cost of image file management. Once day when operating systems allow custom emoji we’ll stop using PNGs and JPEGs altogether. On that day the web will be more fast and safe than ever!

Given the simplicity of the game, my AI is equally simple. When it’s the AI’s turn, I look for an open cell, look for a blocking move or look for a winning move using the eight winning vectors as my guide. Because tic tac toe is too easy to prevent absolute boredom I add a bit of random error into the AI’s thinking so that if the player is paying attention she can beat the machine.

Four

ViewController.swift contains iPhone/iPad specific code.

I found I needed some iPad specific code to avoid a crash when presenting Apple’s standard share UIActivityViewController. I did not open a radar.

I handle several gestures that I’m sure my players never discover but they are there none the less:

  • A long press on an emoji can trigger an attack if battle mode is enabled. A few emoji will do cool tricks in battle mode. There are several battle mode strategy functions that implement these tricks. My favorite is youWin which lets the other player win.
  • Panning up and down turns sounds on and off. That should be a standard gesture for all games!
  • A shake starts are new game with a random pair of emoji. This is the best way to start a new game as choosing particular emoji is a pain.

Five

NewGameViewController.swift contains the code for the game settings on the iPhone/iPad.

Originally, I had the iPhone and Watch Extension collaborate so that one could control the other. But the effort was not worth the reward. Now the two version are completely independent.

I use a UIPickerView with two components to enable the player to choose two emoji. It’s not bad at all if there were only 20 or 30 emoji. But it’s just too much spinning to find a particular emoji out of 1100!

If the user tries to choose the same emoji for player 1 and player 2 (or the AI) I detect that and have the UIPickerView jump to the next emoji. See ensureRowsAreUnique(component: row:).

To make finding a particular emoji a bit easier I allow the player to jump over groups of emoji in the UIPickerView by tapping on the labels for each player. I’m guessing nobody would ever find this feature but the labels are colored blue to indicate they buttons.

Six

InterfaceController.swift contains the code for a very simple version of Emoji Tac Toe that runs on watchOS. I actually like this version if the game best. No battle mode, no sound, no popovers, no choice of emoji. Just a single player game you tap out on your watch while waiting for the train.

Programming the UI for watchOS reminded me of my VisualBasic days! Each button view has it own handler function. No way to aggregate the touches and dispatch them with a switch statement!

Final Notes

All-in-all this code is pretty rough and need a lot of work. But it does work and hardly ever crashes. So that’s something. There is a half-finished tvOS implementation but I’m going to rethink it so don’t look at it!

I had to delete the sound effect that I didn’t create myself. Your build of Emoji Tac Toe will not sound like mine. But otherwise you are free, within the MIT License constraints, to do what you like with the code.

Categories
Nerd Fun Programming Self Improvement

Binge Watching Handmade Hero

For the last several weeks I’ve been obsessed with one TV show. It’s changed my viewing habits, my buying habits, and my computing habits. Technically it’s not even a “TV show” (if your definition of that term doesn’t include content created by non-professionals that is only available for free over the Internet).

But for me, a more or less typical Gen-Xer, Handmade Hero by game tool developer Casey Muratori has me totally enthralled as only must see TV can enthrall. I’m hooked and I simply must watch all 256+ episodes of Handmade Hero before I die (in about 1,406 Saturdays according to the How Many Saturdays app).

So first off let me explain a few things. Unless you are an aspiring retro game programmer or aging C/C++ programmer Handmade Hero will seem tedious at best and irrelevant at worst. There are much better and more modern ways to make a video game (like SpriteKit on iOS or Unity on any OS) but Casey promises to demonstrate live on Twitch.TV how to write a complete video game from scratch, without modern frameworks, that will run on almost anything with a CPU. He’s starting with Windows but promises Mac OS X, Linux, and Raspberry Pi.

This is a bold promise! When I first heard of Handmade hero, almost 2 years ago I ignored it. I didn’t know who Casey Muratori was and the Internet is littered with hundreds of these solo projects that tend to fissile out like ignobly failed Kickstarter projects.

But a comment in Hacker News caught my eye about a month ago. Casey had delivered hundreds of hours of live coding with explanations of arcane C, Windows, and video programming techniques! It’s all archived on YouTube and he’s still steaming almost every night! Awesomesause!

So I had to check it out. I started with Casey’s first video, Intro to C on Windows, and ate it up. I had to pound through the rest of that week’s archive. Because I have a family and a very demand job and kids and cats I had to purchase a subscription to YouTube Red so that I could watch Casey’s videos on or offline. Google is getting $10 bucks a month off me of because of Casey!

My keyboarding fingers ached to follow along coding as Casey coded. I used to be a C/C++ programmer. I used to do pointer arithmetic and #DEFINEs and even Win32 development! Could I too write a video game from scratch with no frameworks? I had to buy a Windows laptop and find out! Thus Dell got me to buy a refurbished XPS 13 because of Casey!

Even Microsoft benefited. I subscribed to Office 365 for OneDrive so I could easily backup my files and use the Office apps since I’m keeping my MacBook Pro at the office these days. I have discovered that a Windows PC does almost everything a MacBook does because of Casey!

I usually have less than an hour a day to watch TV so I’ve had to optimize my entertainment and computing environment around Handmade hero because at this rate I will never catch up to the live stream! But I’m having a blast and learning deep insights from a journeyman coder.

What could an old school game coder teach an old battle-scared industry vet like me? More than I could have imagined.

First of call Casey is an opinionated software developer with a narrow focus and an idiosyncratic coding style. He is not wasting his time following the endless trends of modern coding. He is not worried about which new JavaScript dialect he is going master this month or which new isometric web framework he is going wrestle with. He codes in C with some C++ extensions, he uses Emacs as his editor, he builds with batch files, and debugs with VisualStudio. While these tools have changed over the years Casey has not. He is nothing if not focused.

Thus Casey is a master of extemporaneous coding while explaining–the kind that every software engineer fears during Google and Facebook interviews. This means Casey has his coding skills down cold. He is unflappable.

Casey doesn’t know everything and his technique for searching MSDN while writing code shows how fancy IDEs with auto-completion are actually bad for us developers. He uses the Internet (and Google search) not as a crutch to copy and paste code but as a tool to dig deep into how APIs and compilers actually work. There seems to be nothing Casey can’t code himself.

Casey makes mistakes and correct himself. He writes // Notes and // TODOs in his code to follow up with as if he is working with team. Casey interacts with his audience at the end of every stream and is not shy about either dismissing their questions or embracing them. Casey is becoming a better, more knowledgeable programming before our eyes and we’re helping him while he is helping us.

Casey is not cool or suave on camera. He swigs almond milk and walks away off screen to get stuff during the stream. But nothing about Handmade Hero would be substantially improved if Casey hired a professional video production team. In point of fact, any move away from his amateur production values would be met with suspicion from his audience. Any inorganic product placement would fail. Dell, Microsoft, and Google should support him but stay the heck away least they burst the bubble of pure peer-to-peer show-and-tell that surrounds Casey.

I have 249 videos go to (and Casey has not stopped making videos)! I still don’t know if he delivers on his promise and creates an actual video game from scratch. (Please! No spoilers!) But I already know far more than I did about real-world game development where the gritty reality of incompatible file systems and operating platform nuances make Object Oriented Programming and interpreted bytecode luxuries a working developer can’t afford.

 

Categories
Programming

Identity used to sign executable no longer valid

The last thing I wanted to do on a Sunday morning is write a blog post about an an Xcode executable problem. What I had planned to do is test my most recent Swift 2.0 SpriteKit game on my iPad and iPhone. Last night I got a “Identity used to sign the executable is no longer valid” error when attempting to run my code on a real device. Since it was around midnight I took the message a notification that bedtime had arrived. Besides, a quick search on StackOverflow would surely solve the problem and if I got on SO now I would be up all night nosing around.

This morning I got the same message and found a post on SO that started  four years ago with two pages of answers: The identity used to sign the executable is no longer valid. It’s been viewed 66K times and covers many ancient versions of Xcode. The top answer simply said to restart Xcode. Indeed, restarting, rebooting, or re-installing is always a great answer! So I tried the first two (restarting Xcode and rebooting all my devices) but no joy. And it’s a cheap answer. 99% of computer problems are temporarily solved by powering down and up the server or device but the root cause sits like a malignant elf in the machine, biding it’s time, ready to strike again.

So I figured it out. My problem, in any case.

Last week I was giving a talk at SUNY Buffalo (shout out to Prof. Hartloff). It’s just far enough away from NYC that I had to stay overnight. I took a MacBook Pro that I don’t ordinarily use for development. When I was working on my new game and testing it my iPad and iPhone (to get actual frame rates and the feel of touching the screen) Xcode discovered that I didn’t have an iOS development certificate on that MacBook and asked me if I wanted to revoke my current cert or copy it over from another machine. Since I didn’t have it I said revoke. Xcode did what ever it does and created me a new iOS dev cert associated with that particular MacBook Pro.

Note to Apple: There has to be a better way for Apple certified developers to manage their certificates in this age of clouds and connectivity. Can’t these certs reside on Infinite Loop server?

Enough backstory!

If you get the dreaded “Identity used to sign executable no longer valid” error and restarting your Xcode doesn’t work here are the steps that should fix it for good.

Go to your Apple developer account certificate overview and read carefully and completely about how to manually manage certs and provision devices. Once you understand what you need to do it’s relatively simple.

  1. Revoke and delete all the could certs and profiles of devices you no longer own that have build up over the years. Clean it all up.
  2. Then, following the instructions from Apple recreate your iOS development and distribution certificates.
  3. Re-provision your iOS devices.
  4. Download your certs and provisioning files and reinstall them into your Mac’s keychain.
  5. Clean and build your app.
  6. Now it should run on the iOS devices you’ve provisioned nicely.

Note to You: Xcode is no longer managing your certs and profiles. But that’s OK. It was doing a bad job anyway.

Post Script

Why didn’t I post this info to Stack Overflow? Because this is a pretty radical solution, not without risk. SO, for better or worse, has been come the place for copy and paste solutions that have not aged gracefully over time. Don’t get me wrong–I love Stack Overflow, recommend it, and use it all the time. But sometimes it’s not safe to post an answer to a problem that requires reading comprehension.

Lucky for you and me, my unpopular blog post will probably be the last item in your search for solutions to apple certification problems.

Categories
Cocos2d-iPhone Programming

Cocos2D-Swift 3.0: A great way to get started developing iOS games!

If you’re new to iOS game development now is a great time to get started. In 2008 a brilliant engineer named Ricardo Quesada rewrote his 2D game engine for Apple’s iOS and released it as open source. It’s no exaggeration to say that hundreds of games, like my own, were developed using Cocos2D—including dozens of hits. Now it’s 2014 and the newbie game developer has several versions of Quesada’s Cocos2D framework to choose from. But for me the branch of Cocos2D devoted to the iPhone and iPad will always have a special place in my heart. Clearly Cocos2D-iPhone (now called Cocos2D-Swift) was the inspiration for Apple’s SpriteKit framework. And once you learn the fundamentals of Cocos2D on iOS you can easily transfer these skills to Android, Windows, and HTML5 versions of the Cocos2d family. Working with Cocos2d-Swift is like “reading Shakespeare in the original Klingon.”

Learning iPhone Game Development with Cocos2d 3.0 by Kirill Muzykov is a book I wish I had when I was learning to develop my first iPhone game. Muzykov patiently covers all the basics (nodes, sprites, actions, text, sound, buttons, menus) and jumps into advanced topics (particles, physics, tile maps, iTunesConnect, Game Center, and in-app purchases) while guiding the reader though creating a game called CocosHunt and using important tools (Particle Designer, Texture Packer, Tiled) and websites (freesound.org, media.io).

Along the way the reader also learns about Objective-C, Xcode, and iOS APIs. You’re still a beginner by the time you finish Muzykov’s book but you’re a well informed beginner and ready to tackle larger and more complex projects—like the next Candy Crush.

One of the best things I like about Muzykov’s book is it’s structure. A typical chapter starts with setting up a project and cycles through segments entitled “time for action” and “what just happened?”. This alternating rhythm becomes a reliable way to digest the material and ensure the author doesn’t wave his hands over new concepts. Almost every chapter includes a pop-quiz. I’m not a big fan of quizzes but if that’s what you need to re-enforce the material Muzykov provides them.

The source code is clean and clearly written with good comments. Muzykov keeps the syntax simple, using “typedef enum” instead of “typedef NS_ENUM” and “#define” instead of “FOUNDATION_EXPORT NSString *const” which is probably for portability. Much of a game is managing state and game developer who follow Muzykov examples in his classes won’t get into trouble.

If you’re new to mobile game development and you want to focus on iOS then Learning iPhone Game Development with Cocos2d 3.0 is a good book for you.

Categories
Programming Sprite Kit

Sprite Kit, Retina, iOS7 and Getting It Right

I spent more time that I care to admit figuring out how to reconcile my old Dungeonators code with Apple’s Sprite Kit, Retina displays, and iOS 7. Along the way I searched the web for help and ran into tons of tutorials and advice for indy game developers (I highly recommend  www.raywenderlich.com for a great set of systematic and well written tutorials). But I learned to be wary of advice on some sites that is confused or actually wrong. For example I came across this macro in one of Ray’s tutorials that originated from a Stack Overflow conversation:

#define IS_WIDESCREEN ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )

This macro was written by a floating point math C macro professional. It’s used to determine if the resolution of an iPhone screen is 4 inches. iOS 7 only runs on iPhone’s with Retina displays but there are still  millions of iPhone 4 and 4s models in use with 3.5 inch screens. The iPhone 5, 5c, and 5s has a widescreen of 4 inches.

But why do I need a fancy macro for that? It’s code that I’m only going to run once. And it’s not a particularly CPU intensive calculation. And really, I want to understand what every line of code in my game does. Copy and paste code is always a bad idea.

It’s not hard to figure out what this macro does: It gets the height of the screen, subtracts the resolution of the 4 inch iPhone from it and makes sure the result is less than a number that is as close to zero as the phone’s floating point system can represent. However, there is no reason that we have to go to this level of complexity!

My feeling about macros is that you almost never need to use them. And if you do, call in a pro C programmer. Macros can optimize your code but if you don’t use the right number of parens you could end up with subtle side effects and bugs that are hard to track down.

As an added bonus this macro is only useful if you have determined that the iOS device your game is running on is an iPhone. Taken out of context this speedy line of code could give your game the wrong idea.

To do it right, as in doing it with code that is safe, maintainable, and as efficient as it needs to be, you have to understand how Apple internally represents the resolution of an iOS device. (I’m assuming you want your game to be universal across the Apple universe.)

So let’s say you want to write a universal iOS game in Objective-C using Sprite Kit. Here are the consequences of your decision:

  • Your game can only run on iOS devices running iOS7. This fact eliminates the original non-Retina iPhones but not non-Retina iPads
  • Your game must support both 3.5 and 4 inch iPhones.
  • Your game must support iPad and iPad Retina devices.
  • Don’t worry about model names! The name of the device (iPad, iPad Air, iPhone 5, iPhone 4s, iPadophone 7xyz) doesn’t tell you anything reliable about the number of pixels you have to play with.

Here’s the non-obvious part: You’re going to create your game with pixels in mind but Apple is going to give coordinates in points. I wish Apple had not done it this way. I guess they were trying to be helpful. At lest let developers turn of the points paradigm if like me, they find it unhelpful. But we can’t turn it off so we have to live with it!

Apple says there are 2 pixels in a point. This table should help:

Device Type    Pixels        Points      Models
iPhone 3.5"    960 x 640     480 x 320   iPhone 4, 4s
iPhone 4"      1136 x 640    568 x 320   iPhone 5, 5c, 5s
iPad           1024 x 768    1024 x 768  iPad, iPad Mini
iPad Retina    2048 x 1536   1024 x 768  iPad with Retina

Apple gives us a macro of it’s own to figure out if we’re running on an iPhone or iPad, UI_USER_INTERFACE_IDIOM() and a way to discover the screen’s dimensions in points,
[UIScreen mainScreen].bounds.size.height

Thus, here is a simple method that you can add to your game projects to figure out what sort of iOS device you’re running on based on it’s screen real estate.

- (NSString *)figureOutScreen {
    // Call once during initialization!
    NSString *result;
    
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        
        // iPhone
        
        if ([UIScreen mainScreen].bounds.size.height==568.0f) {
            
            // iPhone Retina 4-inch
            result = @"iPhone Retina 4-inch";
        } else {
            
            // iPhone filename 3.5-inch            
            result = @"iPhone Retina 3.5-inch";
        }
    } else {
        
        // iPad (Can't tell if it is mini, standard, or Retina 'cause all the dimensions in points are the same
        result = @"iPad";
    }
    return result;
}
Categories
Cocos2d-iPhone Programming Sprite Kit

Re-doing Dungeonators

One thing I think all software developers love to do is to make software for “the heck of it.” Hacking something together without having to worry about users, open source community members, and code reviews, is something devs don’t get to do often in these days of test-driven, agile, minimum viable products. Back in 2011 I created an iPhone game just for the heck of it. I wanted to learn about the indy game development process and there isn’t a better way of learning than by doing. I accomplished my mission and uploaded the first version of Dungeonators to Apple’s iTunes App Store in October of 2011. While the game is not very playable, I learned a lot:

  • How to design and implement a realtime game with Objective-C and the Cocos2d-iPhone framework
  • How to create all the art, fonts, sprites, and a spite atlas
  • How to record (or buy) all the sounds and music and use open source tools to transcode audio for a game
  • How to create the mechanics of a game with objects and callbacks while ref counting to manage memory
  • How to test and deploy an iOS game and get something approved in the App Store

Now it’s 2014 and much has changed in the world of indy game development for iOS. Apple’s iOS 7 introduced Sprite Kit which reduces the need for a framework like Cocos2d. Apple also introduced the iPhone 5 and the iPad with Retina, which mean there are four iOS screen resolutions/aspect ratios in common use. Oh, and let’s not forget Flappy Bird and 2048. While writing a hit indy game is still harder than winning the lottery it looks like a couple of people have done it!

Since I’m taking a break between adventures, I thought it would be fun to update Dungeonators for iOS 7 and Sprite Kit. Plus it would be good to make the game universal (available on all iOS devices) and global (available in more than just the United States edition of the App Store). And I should probably make it playable!

The technical part of this plan is relatively easy. iOS 7 is easier to develop with than previous versions of iOS. I can use ARC (automatic reference counting)in addition to manual ref counting. All the music and sound effects should just work fine. My custom Objective-C classes just need some simplifying (I wrote too much code–that’s my bad coding habit). The original Dungeonator’s artwork is all vector-based so rendering it in different resolutions for each iOS device shouldn’t be too hard. Finally, Sprite Kit is remarkably similar to Cocos2d. Porting the scenes, sprites, transitions, and actions will also be easy.

High resolution Dungeonators under development (1136 x 640 pixel rendering)

The hard part is creating a playable game. If you download original version of Dungeonators from the App Store you’ll find it really confusing. How do you play? Where to you touch? What is the goal? I don’t know what I was thinking!

Actually I do know what I was thinking. I was thinking about the inside not the outside. Inside there are classes for characters, strategies, spells, payloads, and matches. Way too much to fit in a casual game. So while I’m porting everything over I’m going to tear out hundreds of lines of code. I’m going to simplify Dungeonators to the point where it doesn’t require a personal demo from me to learn how to play!

I still might not have a playable game but at least it won’t crash anymore!

Categories
Cocos2d-iPhone Programming

ARC Memory Management in iOS 5 and Cocos2d-iPhone 2.0

My rewrite of Dungeonators is crawling along at a glacial pace. Mostly because I can only work a couple of hours a week on the project. But the iOS 5 way to manage memory with ARC (automated reference counting) is making the process far less painful than it was the first time I wrote my game. ARC uses annotations and some new key words to manage memory on your behalf. It works very well if you’re doing simple client-side game development and don’t have to worry about backward compatibility with iOS 4.

Here is an example of how ARC changes your life for the better…

In the old days you would declare out your ivars, declare your properties, then synthesize and map them together, and release them in a dealloc method. This little design pattern required 4 repetitive lines of code for every ivar (instance variable) and engendered flamewars about  coding style and where underscore should go (if you thought it was necessary to distinguish an ivar name from a property name).

Pre-ARC Entity.h

#import "cocos2d.h"
@interface Entity : CCSprite {
BOOL isActive_;
NSString * name_;
}
@property (nonatomic) BOOL isActive;
@property (nonatomic, copy) NSString * name;
@end

Pre-ARC Entity.m

#import "Entity.h"
@implementation Entity
@synthesize isActive = isActive_;
@synthesize name = name_;
- (id) init {
  self = [super init];
  if (self) {
    isActive_ = YES;
    name_ = @"Fang";
  }
  return self;
}
- (void) dealloc {
  [name_ release];
  name_ = nil;
  [super dealloc];
}

In this new modern era of automated reference counting I just declare properties, I don’t worry about accessing the ivars directly, and I don’t write my own dealloc. It’s a lot less code in a complex game where characters and objects have dozens of properties.

Post-ARC Entity.h

#import "cocos2d.h"
@interface Entity : CCSprite
@property (nonatomic) BOOL isActive;
@property (nonatomic, strong) NSString * name;
@end

Post-ARC Entity.m

#import "Entity.h"
@implementation Entity
@synthesize isActive;
@synthesize name;
- (id) init {
  self = [super init];
  if (self) {
    isActive = YES;
    name = @"Fang";
  }
  return self;
}

To get Cocos2d-iPhone to work with ARC was really easy: I just replace the NSAutoreleasePool object in main.m with the new ARC friendly @autoreleasepool annotation. (I might not have had to do this but it’s supposedly more efficient.)

int main(int argc, char *argv[]) {
//    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//    int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate");
//    [pool release];
//    return retVal;
  int retVal;
  @autoreleasepool {
    retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate");
  }
  return retVal;
}

The downside, as I stated above, is that your app will only run on iPhones, iPads, and iPods running iOS 5 and you need to use Cocos2d-iPhone 2.0. But I think that’s a fair tradeoff. Backward compatibility is a killer of the artistic soul and should be avoided where possible. To Err is human, but to upgrade is divine 🙂

Check out Ray Wenderlich’s excellent ARC tutorial for all the gritty details!

Categories
Cocos2d-iPhone Product Design

Dungeonators Battle UI Redesign


There is nothing quite like real user feedback. The Dungeonators game that I started coding about a year ago has been through several design iterations. Before I wrote a line of code I mocked up the whole UI and tested that on my friends and kids (paper prototype, an honorable UI design tradition). And with each development build I tested everything again and even enlisted strangers. I must have played though the final release candidate a 100 times. (It was then that I realized that game programmers must get sick of their games if they properly test them!)

When I uploaded Dungeonators to the App Store on 14 October 2011 I was pretty confident about the game play and the user interface. Famous last words as they say 🙂

After an initial healthily growth curve Dungeonators installs tanked:


The message I get from this user adoption curve was simple: Dunegonators stinks!

So I went back to the drawing board to search for the stinky bits. After much reflection I realized three things:

  1. Dungeonators is too hard for casual users and too easy/dumb for hardcore gamers. People who play MMORPGs like World of Warcraft punch through my game. People who play Angry Birds get stuck around level 1.6. (Which is as far as you can go if you don’t know what you’re doing.)
  2. People don’t know what to touch. They want to touch the avatars and not the raid and spell frames. If you don’t know what raid frames and spell frames are then you are not going to get my game.
  3. I was going to have to fix this. I could fix this problem with a lengthy tutorial or FAQs. But Dungeonators is causal game not productivity software. I never read manuals and skip tutorials. I expect my audience to have the same level of self respect!
So here is the new battle UI that tries to clean this mess up:
  • The good guy raid frames (on the left) are no longer touchable: They just display status. I couldn’t find a casual user who knew what a raid frame was so I got rid of raid frames.
  • Good guy spell frames are no longer associated with good guy raid frames: Spell frames are now modeless and never hidden. Each good guy has two spells available 24/7. As the game progress the spell are automatically upgraded. I’ll have to rewrite the game mechanics to handle the fact that the total number of available spells has gone from 4 x 6 (which I understand is 24) to a mere 8. But that actually makes Dungeonators a heck of lot simpler to program and to play.
  • The bad guy raid frames are still touchable and still enable the player to switch targets. But in the original UI you could have separate bad guy targets for every good guy. In the revised UI all the Dungeonators are synchronized. It’s a gross simplification that is all for the best.
  • Touching the center of the screen, where the avatars live, is still not part of the game play but if you do, the game will pause and bring up the main menu. I was able to kill two birds with one stone: No main menu button and a valid response to a user touch. Feedback is everything thing: In the original design touching the center of the screen was ignored and could have been interpreted as the game freezing up.
In general I learned what I thought I always knew: iPhone games have to be simple and causal gamers don’t have the time or energy for complex mechanics. But in practice I learned a lesson that every battled hardened game developer must know after their first game is released: There is no better test case than the real world!
Categories
Cocos2d-iPhone Programming

Sprite Playground

I wrote a little Cocos2d-iPhone test app and committed the project to GitHub. (Like every dutiful hacker should.) You’re welcome to download the project and fool around with the code.

My goal was to figure out how to create a composite sprite, make sure it could respond to touches, and rotate and move it round the screen. With a little trial and error I got it working. Here’s how I did the hard parts:

I created a sprite from an PNG file and got it’s dimensions:

CCSprite * cocos2dGuy = [CCSprite spriteWithFile:@"avatar_n1_tang.png"];
CGSize spriteSize = cocos2dGuy.textureRect.size;

Then I created a CCNode to be the parent of my sprite sandwich. (I originally tried to use my cocos2dGuy CCSprite as the parent but Cocos2d stacks added on top of partent nodes and I wanted the particle effect under the cocos2dGuy not on top of him.) I set the size of the CCNode to the dimensions of the cocos2dGuy so that when you touch the CCNode it responds as if you’re touching the image. Then I add the CCNode to the layer. It’s also important to set the CCNode’s anchorPoint to the center (0.5, 0.5) as it’s default is bottom-left. CCSprite default to center anchorPoints and I want my CCNode to act like a proper sprite.

CCNode * composite = [CCNode node];
composite.anchorPoint = ccp(0.5,0.5);
composite.contentSize = spriteSize;
composite.position = centerPt;
[self addChild:composite z:0 tag:kCompositeTag];

Next I added the cocos2dGuy sprite to the center of the composite CCNode. These two entities are now both the same size and stacked on top of each other. (It’s probably not necessary for me to set the cocos2dGuy’s anchorPoint and so I’ll remove that line of code down the road.)

cocos2dGuy.anchorPoint = ccp(0.5, 0.5);
CGSize compositeSize = composite.contentSize;
CGPoint compositeCenterPt = ccp(compositeSize.width/2,compositeSize.height/2);
cocos2dGuy.position = compositeCenterPt;
[composite addChild:cocos2dGuy z:1 tag:1];

Finally I created the custom CCParticleSystem from a Particle Designer file and added it to the composite CCNode but at a lower Z value show it shows up under the cocos2dGuy sprite. See how I had to set the position and the anchorPoint to ensure everything lined up.

CCParticleSystem * fx = [ARCH_OPTIMAL_PARTICLE_SYSTEM particleWithFile:@"fireball_small_fast_green.plist"];
fx.anchorPoint = ccp(0.5, 0.5);
fx.position = compositeCenterPt;
fx.duration = kCCParticleDurationInfinity;
fx.scale = 2.0f;
fx.autoRemoveOnFinish = YES;
[composite addChild:fx z:0 tag:1];

Movement and animation are easy in the world of Cocos2d. I really like the visual effect of CCEaseExponentialInOut. It has a nice punch.

Handling touches are bit harder. I had to remember to set self.isTouchEnabled = YES in my init method and override both registerWithTouchDispatcher and ccTouchBegan. The key bit of code for responding to a touch is isTouchForMe:

bool hit = false;
for(CCNode * node in [self children]) {
    if(node.tag == kCompositeTag) {
         hit = CGRectContainsPoint([node boundingBox], touchLocation);
         if (hit) {
             [self hiliteSprite:(CCSprite *)node];
         } else {
             [self turnSprite:(CCSprite *)node andAttackPoint:touchLocation];
         }
    }
}

The main thing here is to give each touchable node a unique tag and test each node in the layer for that tag. If you touch the sprite he inflates for a moment. If you touch an empty part of the screen the sprite turns and launches himself at your finger. Ouch!

Categories
Cocos2d-iPhone Programming

Cocos2d-iPhone Sprite Rotation to an Arbitrary Point

I had some time during the Thanksgiving weekend to work on Dungeonators. I’m hoping to get an upgrade out to the App Store soon. One thing I needed //TODO: is refactor my rather poor implementation of rotating a sprite to face another sprite. My original code worked ok, in a roundabout way, but was ugly and mysterious.

(My iPhone game is full of ugly mysterious code: As I implement my ideas in code I first focus on getting it to work. Then, if I have time I go back and fix it to work cleanly. Generally cleanly means boiling the code down to the fewest number of lines possible, making it as functional as possible, and using functions from the operating system or open source code libraries as much as possible.)

I won’t show you my original sprite rotation implementation. Some things are too gross even for the Internet. Let’s just say it was written as if I was trying to remember high school trigonometry by trial and error.

Instead below is the final implementation, useful to any Cocos2d-iPhone programmer who wants a sprite to rotate to face an opponent at any point on the screen:

- (void) rotateSourceSprite:(CCSprite *)sourceSprite toFaceTargetSprite:(CCSprite *)targetSprite {

    // Calculation
    CGPoint difference = ccpSub(sourceSprite.position, targetSprite.position);
    CGFloat rotationRadians = ccpToAngle(difference);
    CGFloat rotationDegrees = -CC_RADIANS_TO_DEGREES(rotationRadians);
    rotationDegrees += 90.0f;
    CGFloat rotateByDegrees = rotationDegrees - sourceSprite.rotation;

    // animation
    CCRotateBy * turnBy = [CCRotateBy actionWithDuration:0.5f angle:rotateByDegrees];
    CCEaseIn * ease = [CCEaseIn actionWithAction:turnBy rate:4];
    [sourceSprite runAction:ease];
}

And here’s how it works, just incase you’re curious…

  • The method takes a source sprite and as target sprite as parameters. After it runs it will rotate the source to face the target.
  • The calculation part uses Cocos2d helper functions and macros (ccpSub, ccpToAngle, and CC_RADIANS_DEGREES) to figure the maths. In my original implementation I had written my own versions. Using the Cocos2d API makes my code easier to read and perhaps faster.
  • The maths work like this: Create a vector out of the distance between to points. Convert the vector to an angle. Convert the angle from radians to degrees and negate it*. Add 90 degrees to the angle to get the proper orientation. (The +=90.0f value is game specific: My sprites are rotated 90 degrees to start with.) Subtract the penultimate result of the calculation from the current rotation property (angle) of the source sprite to get the final result (the amount to rotate by).
  • The animation, which could easily be factored out into a method of its own, uses Cocos2d’s CCRotateBy and CCEaseIn to turn the source sprite to face the target in half a second. This part didn’t change from the original code. I didn’t factor it out because in my game I always use these two pieces together. I don’t like to do too much work in the abstract because I usually end up making my code too complex.

* The need to negate the value produced by CC_RADIANS_DEGREES is a bit of a mystery to me. If I don’t do it my sprite ends up facing in the opposite direction.