I want to take a moment and thank the thoughtful developers at Apple (technically NextStep probably, but whatever) for the wonderfully simple, and elegantly powerful NSNotificationCenter. I won’t bother going over the API, there’s already many great blog posts on that (my favorite is here), but I wanted to raise awareness of it, and talk about how I’m using it in Spellwars…as well as discuss the potential pitfalls of abusing an event-based architecture.
The basic premise of the Broadcaster/Observer pattern is to decouple components, so that events can be fired and handled without everyone having to know about everyone else. This allows, for example, pieces of the UI (in my case, information labels that display stats of the selected spell) to update when a Spell is selected by the user, but the Spell objects don’t have to have explicit links back to the UI components. They just fire off their event (SpellSelected) and the UI controllers can listen for that event, then update the labels. It makes for a very clean implementation when done correctly.
When I finally got around to refactoring my super-hacky direct method invokations for this particular use case, I was able to remove 80% of the related code, and remove 90% of the complexity. Requiring back-pointers all over the code was making me nauseous. I was just about to implement my own solution when I came across several blog posts referring to said NSNotificationCenter, and once I saw the super-simple 3 method API I knew it was exactly the way to go. Nuff said.
Now, I will warn against going too far down the Broadcaster/Observer path, commonly called an Event-driven architecture, because I’ve seen it abused to the point of making code completely incoherent and impossible to understand or debug. Events are a natural way to pass information between unrelated objects, but between related objects, just invoke the methods directly. It more precisely expresses your intention as a code designer, and it also more precisely executes your intention.
At a startup I worked with over a year ago that shall remained unnamed, they were using Flex to build several web applications. Flex has a very well developed Event architecture, made even better by the Cairngorm micro-architecture. The problem with the product that the company was developing, is that they used Events for everything, absolutely everything. There were basically no direct method invocations on any objects, even when you naturally had the target object already in scope, and it was a child or some other natural relationship. This meant that every time flow control has to pass from one object to another, it required a listener to be added, an event to be defined, said event to be fired, and said listener to then be removed after. If that flow didn’t look obviously wrong to anyone else in the company, there’s nothing I could say to help them. It was such an absurd abomination I just didn’t even know where to begin.
I pretty much decided to begin by finding a new job.
Anyway, there was this one bug where some previous employee of the company had left a big nasty ball of mud with some problem in it, and because of the number of events fired, and the ability for multiple objects to respond to any event, it was just impractical to figure out what was going on, much less track down the problem.
Lesson: Just because you can, it doesn’t mean you should. Like all engineering tools, apply with discretion.
That’s right, I’ve got some pretty pictures. They’re actually not all that pretty, graphic designer I am not, but they get the point across. I am hoping to generate some interest in the community out there (that means you), if the project looks interesting to you drop me a line: I’m looking for people to work with me.
So lets get to the game. A basic description of what I have right now, is a simple 2-player spell combat game. The game resolves on a board, not unlike battleship, on which players take turns playing spells from their hand, not unlike Magic: The Gathering. A battle starts off looking like this:
Seriously, do forgive the lack of design. Anyway, once you tap start, combat begins and you are presented with the spells in your hand, and you then choose one to play:
After you choose your spell, it is placed in the middle of the board. You can then drag your spells around anywhere on the board, before you decide to continue. Once you’ve placed your spells where you want them, tap Turn, and the combat engine will resolve the turn.
It should be noted, the goal of a battle is to reduced your opponent’s HP to 0, by dealing damage through your spells. Each player starts with a certain number of HP, based on other things in the game that have yet to be fully implemented, so for today we’ll say both players get, oh, 50 HP. Sounds good.
Spells interact based on their location on the board, and their area of effect, visualized by the colored circle around the icon. Some spells have a large area, some are smaller…the value of each is different, depending on what your are trying to accomplish with a given spell. Typically a spell will be either serving in attack, defense, or support…potentially all of the above.
Each turn, the spells on the board resolve on a stack, with individual spell speed determining the order of spell resolution. There is no “your turn” or “other person’s turn,” it all happens at once. If 2 spells overlap, the active spell does damage to the “defending” spell, if the spell’s defense is reduced to 0 it is destroyed.
Spells in your hand are pulled from your active set, currently called a Book. Think of the deck concept in any CCG, same thing. Each turn, you draw a single spell. Each turn, you can play a single spell. Combat continues until one person runs out of HP. I am tailoring the gameplay so a single game can be played in no more than a minute, probably something like 30 seconds for a single duel vs the CPU. I figure that is about the amount of attention span most iPhone users have, most of the time. The app starts up in about 2 seconds, so you can easily play a game or 3 while waiting in line at starbucks.
Where do the spells come from? Basically, the rest of the game. Which is really the bulk of the game. I’m working on that part next. I envision a multiplayer world, somewhat like lootwars, but with unique places to visit and custom challenges…my version of instanced dungeons vis-a-vis World of Warcraft or Diablo II. My vision is that a big part of the fun of the game is in hunting down and finding rare and unique spells to build up your collection, and to have fun and powerful spells to duel with. You can bet there will be hard to find spells, spell sets, spell combines, limited editions, etc. I know that balancing the supply of items in an economy like this becomes of paramount importance, it’s at the top of my list for things to design very, very carefully. Digital economy, here I come.
On Motivations and Background
I started this project because I found a real void in the iPhone game world of solid multi-player games with deep, compelling game mechanics. Lootwars is by far the most well-designed MMO-ish game I’ve played, but it leaves me feeling so un-fulfilled, wanting so much more. I’ve been gaming for 20 years, and what first pulled my interest was the Rolemaster/MERP games in the mid 80s. Those games had such deep game mechanics that I almost never was able to get past just working through all the tables and numbers…and I loved it! The few game sessions we had as kids were fun, and I knew that one day a computer game implementation of something like that could make for an incredibly compelling engagement. I’m starting to feel the tips of that now.
Later, in the mid 90s, I again got sucked into a simlar game with similarly deep mechanics, Magic: The Gathering. From playing in small towns, to bigger tournaments with large prizes, to the million dollar Pro Tour, I spent enough time playing Magic to gain a real deep respect for the engagement power of a delicately balanced game. The guys at WotC work very hard to make sure Magic stays fun and balanced, even with the influx of hundreds of cards and dozens of new game mechanics a year.
These are what inspire me, and what drive me to create this game. The iPhone deserves it’s own game for gamers, by gamers. I want to make something that is appealing to a broad base of people, there’s no sense in catering solely to hardcore players, but that also has a deep set of interactions and fun things to do, that you can spend as much or as little time as you want, and still find more of the game to explore. I know it’s not easy, but I’m up for the challenge. And I’m looking for others who are like-minded. I can’t do this alone, it’ll take both partners and a supportive community. If you want to play a part, you know where to find me.
So, having just poured all the juice from my claypot chicken dinner right into the keyboard of my macbook, I’m left with about a 50% functioning keyboard, and at least a good 12 hours, probably more like 6 days or so, where I’m not going to get much iPhone programming done. I thought I’d write about something more broad than iPhone SDK implementation details tonight. I’m going to talk about business, specifically my business.
My company, R.Cloud LLC, is just about 2 months old right now and business is good. I will take this opportunity to note that yes, I am available for new clients right now, if you are interested please get in touch with me. iPhone development hasn’t significantly changed since the iTunes store opened, it’s still a wild, wild world without much to grasp onto. You have to stay grounded in your own confidence, or else you will end up getting swept away in the maelstrom of data that spews out of the iTunes store. Top 10 lists. App review blogs. 4000 people a day on craigslist looking to “share the revenue” with you, if you will just choose them out of the infinite pool of ideas. (if you don’t understand why it doesn’t work, start with this article, and if that isn’t enough just keep randomly clicking on links off that page until you figure it out or get bored) There’s a shitstorm of directions to look, it’s worse than daytrading currency futures.
What keeps me grounded? My partner for one. I know without having a partner, I’d be screwed. Even if Steve, my business partner and artist, is at least as much of a lost-in-the-clouds kind of guy as I am, having another person to keep you focused and honest is priceless. I wish I had more partners, people who live locally, to work closely with on a daily basis. As much as I may work well with my existing partner, he lives in LA and I live in San Francisco…and that arrangement just doesn’t work out for me too well. Not enough throwing ideas around the room.
I can’t stress this enough, even just when talking to myself. Get a damn partner. A mentor is fine even. But at least one other human being (to whom you are not married) to work with. Please stop developing in a void, no matter how good you think your ideas are.
I know that as my apps progress, especially the game I’m working on, I’m going to want to bring in more resources. There’s only so much any one person can do, and I’m starting to reach that limit. I am familiar with the start-up world, but being on the other side of the fence really changes your perspective. This is the first time it’s my idea, my baby, don’t fuck it up you tools. Will I manage to find the right magical mix of people, personalities, skills, and money? Will I figure out how to really leverage my own abilities and channel what I want through the people I choose to work with? Or will I find myself burning through sweat and money, and end up having to do everything myself anyway?
Collision detection can be a little difficult with complex paths like arbitrary bezier objects. But when the two objects are circles? piece of cake! Find the center of each circle, then compare the distance between them. If that is less than the sum of the two radii, they collide.
The calculation is from high school geometry, and yes most of you have forgotten it. As apparently, did I. You probably recognize this:
x^2 + y^2 = z^2
and you might even remember what it applies to. When programming on the iPhone, we have x and y in coordinates from the UIView. When making the comparison between the above mentioned distance between points and radii, it’s easier to compare the squares of the respective z values, so we don’t have to compute 2 unnecessary and expensive square roots.
So anyway, I implement said solution, and go about my business. Over the next week or so, I notice that my collision detection is a little bit inaccurate. Not a lot, but a little. One night I decide I’m going to get it pixel perfect, since I should be able to pretty easily.
A few hours later, I give up and call in my wife. You see, she actually does this kind of math all day, every day. Well, not all day every day, but on a regular basis, every week. She’s a structural engineer, and they have to do calcs to make sure your house doesn’t fall over because of an over-imaginative and under-detail-oriented architect.
It turns out, I made a small…tiny mistake in how I formed the final equation. Rather than squaring the sum of the two radii, I squared each one separately, then added them together. That is:
rad_1^2 + rad_2^2
(rad_1 + rad_2)^2
Very easy to do in code, so watch out for it. It’s a nasty little bug to track down, because the inaccuracy changes based on the size of the circles…which varies in my app.
The final code I ended up with is below:
CGRect m_frame = [self frame];
CGRect o_frame = [otherView frame];
float m_rad = m_frame.size.width / 2;
float o_rad = o_frame.size.width / 2;
CGPoint m_center = m_frame.origin;
m_center.x += m_rad;
m_center.y += m_rad;
CGPoint o_center = o_frame.origin;
o_center.x += o_rad;
o_center.y += o_rad;
dt.x = m_center.x – o_center.x;
dt.y = m_center.y – o_center.y;
float x_sq = dt.x * dt.x;
float y_sq = dt.y * dt.y;
// this is wrong, I screwed up the original calculation
//float mrad_sq = m_rad * m_rad;
//float orad_sq = o_rad * o_rad;
float rad_sq = (o_rad + m_rad) * (o_rad + m_rad);
return (rad_sq) > (x_sq + y_sq);
While working on a few run-throughs of my currently in-development iPhone game, I came across a performance issue. When I started playing, the game was pretty zippy…but with each turn it would continue to get slower. And not just a little slower, a lot slower. At first a turn might take .2 seconds or so, but by turn 6 or 7 it was up to around 4 seconds to process a turn. What was going on? Why am I bothering to share this with the world?
It turns out that the logging was updating a UITextView for each NSLog call, so that a player could tap on a tab and see all the results of the computer resolving all the spells. Once there is more than one or two spells in play, a single turn could contain maybe 25-30 logging calls. Each call would copy the whole text out of the UITextView control, append a line to it, then set the text value. This became incredibly cpu intensive, and was slowing down the app way more than I would have ever imagined. The instrument panel showed me everything.
I was really horrified at how long a single UITextView.text = @”really long multiline multiparagraph log-like string” line can take. It seems to me that one of the most common use cases is to append text to a control, so being forced to copy the text out, append to it, then copy it back in is really slow and painful. Is there not a better way? really? It’s 2009, do I need to write this kind of control buffering myself? Apparently, yes.
And it’s worth noting, this only became apparent while running and debugging the app on a device. The performance issue never really showed up in the simulator, and even once I identified it, the simulator was useless even with the instrument panel. As much as I love the simulator, and I really do, for performance work don’t waste your time.
So, the solution? I went with the simple and obvious: create a buffered log. I only update the LogView when I commit the buffer, while the NSLog calls still go to the console immediately. Works like a champ!
I’ve been recently working on a new iPhone game, something to fill the void that is lacking in multi-player, collectible creature/card/spell/something, that semi-mmo feel you get from mixing Magic:The Gathering with Lootwars, Diablo II, World of Warcraft, an iPhone, and 20 years of gaming. It all starts to come out in a big heaping pile of…something, lots of great ideas and no focus. I’ve always felt my job as an engineer was to “fight entropy,” a phrase my old co-worker Matt came up with over a decade ago, and it sure fits…especially when working on a new project. I’ve got so much personal history in the gaming world, how could the ideas *not* come out all at once?
It’s coming along well, and a public beta will be available shortly I hope. I’ll be posting screenshots and game mechanics along the way.