<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog Pav Blog &#187; iPhone</title>
	<atom:link href="http://www.pavley.com/tag/iphone/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.pavley.com</link>
	<description>“A great leap in the dark” – Thomas Hobbes</description>
	<lastBuildDate>Thu, 05 Jan 2012 05:02:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Dungeonators Battle UI Redesign</title>
		<link>http://www.pavley.com/2011/12/21/dungeonators-battle-ui-redesign/</link>
		<comments>http://www.pavley.com/2011/12/21/dungeonators-battle-ui-redesign/#comments</comments>
		<pubDate>Thu, 22 Dec 2011 01:59:44 +0000</pubDate>
		<dc:creator>pav</dc:creator>
				<category><![CDATA[Cocos2d-iPhone]]></category>
		<category><![CDATA[Product Design]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[UI Design]]></category>
		<category><![CDATA[User Interface]]></category>

		<guid isPermaLink="false">http://www.pavley.com/?p=501</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><a href="http://www.pavley.com/wp-content/uploads/2011/12/photo-1.png"><img class="aligncenter size-full wp-image-507" title="Current Dungeonators Battle UI" src="http://www.pavley.com/wp-content/uploads/2011/12/photo-1.png" alt="" width="461" height="307" /></a><a href="http://www.pavley.com/wp-content/uploads/2011/12/Dungeonators_new_battle_ui.png"><br />
</a></p>
<p>There is nothing quite like real user feedback. The <a href="http://itunes.apple.com/us/app/dungeonators/id463233923?mt=8">Dungeonators</a> 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 (<a href="http://www.alistapart.com/articles/paperprototyping/">paper prototype</a>, 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!)</p>
<p>When I uploaded Dungeonators to the App Store on 14 October 2011 I was pretty confident about the game play and the user interface. <a href="http://en.wikiquote.org/wiki/Last_words">Famous last</a> words as they say <img src='http://www.pavley.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>After an initial healthily growth curve Dungeonators installs tanked:</p>
<p style="text-align: center;"><a href="http://www.pavley.com/wp-content/uploads/2011/12/Dungeonators_new_battle_ui.png"><br />
</a><a href="http://www.pavley.com/wp-content/uploads/2011/12/photo.png"><img class="aligncenter size-full wp-image-502" title="iTunes Connect Screen for Dungeonators 1.0" src="http://www.pavley.com/wp-content/uploads/2011/12/photo.png" alt="" width="384" height="576" /></a></p>
<p>The message I get from this user adoption curve was simple: Dunegonators stinks!</p>
<p>So I went back to the drawing board to search for the stinky bits. After much reflection I realized three things:</p>
<ol>
<li>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&#8217;t know what you&#8217;re doing.)</li>
<li>People don&#8217;t know what to touch. They want to touch the avatars and not the raid and spell frames. If you don&#8217;t know what raid frames and spell frames are then you are not going to <em>get</em> my game.</li>
<li>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!</li>
</ol>
<div>So here is the new battle UI that tries to clean this mess up:</div>
<div><a href="http://www.pavley.com/wp-content/uploads/2011/12/Dungeonators_new_battle_ui.png"><img class="aligncenter" title="Dungeonators_new_battle_ui" src="http://www.pavley.com/wp-content/uploads/2011/12/Dungeonators_new_battle_ui.png" alt="" width="480" height="320" /></a></div>
<ul>
<li>The good guy raid frames (on the left) are no longer touchable: They just display status. I couldn&#8217;t find a casual user who knew what a raid frame was so I got rid of raid frames.</li>
<li>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&#8217;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.</li>
<li>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&#8217;s a gross simplification that is all for the best.</li>
<li>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.</li>
</ul>
<div>In general I learned what I thought I always knew: iPhone games have to be simple and causal gamers don&#8217;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!</div>
]]></content:encoded>
			<wfw:commentRss>http://www.pavley.com/2011/12/21/dungeonators-battle-ui-redesign/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sprite Playground</title>
		<link>http://www.pavley.com/2011/12/02/sprite-playground/</link>
		<comments>http://www.pavley.com/2011/12/02/sprite-playground/#comments</comments>
		<pubDate>Sat, 03 Dec 2011 04:37:29 +0000</pubDate>
		<dc:creator>pav</dc:creator>
				<category><![CDATA[Cocos2d-iPhone]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Sprite]]></category>

		<guid isPermaLink="false">http://www.pavley.com/?p=483</guid>
		<description><![CDATA[I wrote a little Cocos2d-iPhone test app and committed the project to GitHub. (Like every dutiful hacker should.) You&#8217;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 [...]]]></description>
			<content:encoded><![CDATA[<p><iframe width="560" height="315" src="http://www.youtube.com/embed/DfsTaC5dkJc" frameborder="0" allowfullscreen></iframe></p>
<p>I wrote a little Cocos2d-iPhone test app and committed the <a href="https://github.com/jpavley/SpritePlayground">project</a> to GitHub. (Like every dutiful hacker should.) You&#8217;re welcome to download the project and fool around with the code.</p>
<p>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&#8217;s how I did the hard parts:</p>
<p>I created a sprite from an PNG file and got it&#8217;s dimensions:</p>
<pre class="brush: c++">CCSprite * cocos2dGuy = [CCSprite spriteWithFile:@"avatar_n1_tang.png"];
CGSize spriteSize = cocos2dGuy.textureRect.size;</pre>
<p>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&#8217;re touching the image. Then I add the CCNode to the layer. It&#8217;s also important to set the CCNode&#8217;s anchorPoint to the center (0.5, 0.5) as it&#8217;s default is bottom-left. CCSprite default to center anchorPoints and I want my CCNode to act like a proper sprite.</p>
<pre class="brush: c++">CCNode * composite = [CCNode node];
composite.anchorPoint = ccp(0.5,0.5);
composite.contentSize = spriteSize;
composite.position = centerPt;
[self addChild:composite z:0 tag:kCompositeTag];</pre>
<p>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&#8217;s probably not necessary for me to set the cocos2dGuy&#8217;s anchorPoint and so I&#8217;ll remove that line of code down the road.)</p>
<pre class="brush: c++">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];</pre>
<p>Finally I created the custom CCParticleSystem from a <a href="http://particledesigner.71squared.com/">Particle Designer</a> 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.</p>
<pre class="brush: c++">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];</pre>
<p>Movement and animation are easy in the world of Cocos2d. I really like the visual effect of  CCEaseExponentialInOut. It has a nice punch.</p>
<p>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:</p>
<pre class="brush: c++">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];
         }
    }
}</pre>
<p>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!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pavley.com/2011/12/02/sprite-playground/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Cocos2d-iPhone Sprite Rotation to an Arbitrary Point</title>
		<link>http://www.pavley.com/2011/11/28/cocos2d-iphone-sprite-rotation-to-an-arbitrary-point/</link>
		<comments>http://www.pavley.com/2011/11/28/cocos2d-iphone-sprite-rotation-to-an-arbitrary-point/#comments</comments>
		<pubDate>Tue, 29 Nov 2011 04:15:05 +0000</pubDate>
		<dc:creator>pav</dc:creator>
				<category><![CDATA[Cocos2d-iPhone]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Sprite]]></category>

		<guid isPermaLink="false">http://www.pavley.com/?p=474</guid>
		<description><![CDATA[I had some time during the Thanksgiving weekend to work on Dungeonators. I&#8217;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 [...]]]></description>
			<content:encoded><![CDATA[<p>I had some time during the Thanksgiving weekend to work on <a href="http://itunes.apple.com/us/app/dungeonators/id463233923?mt=8">Dungeonators</a>. I&#8217;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.</p>
<p>(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 <em>cleanly</em> 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.)</p>
<p>I won&#8217;t show you my original sprite rotation implementation. Some things are too gross even for the Internet. Let&#8217;s just say it was written as if I was trying to remember high school trigonometry by trial and error.</p>
<p>Instead below is the final implementation, useful to any <a href="http://www.cocos2d-iphone.org/">Cocos2d-iPhone</a> programmer who wants a sprite to rotate to face an opponent at any point on the screen:</p>
<pre class="brush: c++">- (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];
}</pre>
<p class="brush: c++">And here&#8217;s how it works, just incase you&#8217;re curious&#8230;</p>
<ul>
<li>The method takes a source sprite and as target sprite as parameters. After it runs it will rotate the source to face the target.</li>
<li>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.</li>
<li>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).</li>
<li>The animation, which could easily be factored out into a method of its own, uses Cocos2d&#8217;s CCRotateBy and CCEaseIn to turn the source sprite to face the target in half a second. This part didn&#8217;t change from the original code. I didn&#8217;t factor it out because in my game I always use these two pieces together. I don&#8217;t like to do too much work in the abstract because I usually end up making my code too complex.</li>
</ul>
<p>* The need to negate the value produced by CC_RADIANS_DEGREES is a bit of a mystery to me. If I don&#8217;t do it my sprite ends up facing in the opposite direction.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pavley.com/2011/11/28/cocos2d-iphone-sprite-rotation-to-an-arbitrary-point/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Invalid Code Signing Entitlements</title>
		<link>http://www.pavley.com/2011/10/10/invalid-code-signing-entitlements/</link>
		<comments>http://www.pavley.com/2011/10/10/invalid-code-signing-entitlements/#comments</comments>
		<pubDate>Mon, 10 Oct 2011 22:42:24 +0000</pubDate>
		<dc:creator>pav</dc:creator>
				<category><![CDATA[Cocos2d-iPhone]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Xcode 4]]></category>

		<guid isPermaLink="false">http://www.pavley.com/?p=445</guid>
		<description><![CDATA[Finally after 11 months I submitted my iPhone game, Dungeonators, to iTunes Connect for inclusion in the Apple App Store. I&#8217;m planning on giving it away so the &#8220;warcraft meets angry birds&#8221; funs is accessible to everyone! I hope it passes Apple&#8217;s review process It took several attempts for me to get to &#8220;waiting for [...]]]></description>
			<content:encoded><![CDATA[<p>Finally after 11 months I submitted my iPhone game, Dungeonators, to iTunes Connect for inclusion in the Apple App Store. I&#8217;m planning on giving it away so the &#8220;warcraft meets angry birds&#8221; funs is accessible to everyone! I hope it passes Apple&#8217;s review process <img src='http://www.pavley.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>It took several attempts for me to get to &#8220;waiting for review status&#8221;. Here are the step I went through in hope that if you, in the near future, need to submit an app for the first time, you can succeed on your first attempt.</p>
<p>At this point set a cold beer within easy reach&#8230;</p>
<ol>
<li>Most of the info from Apple and the books on iPhone development is based on the old Xcode 3-based application submission process. Google Xcode 4 iTunes connect for the most recent tips. I&#8217;m not even going to include a link because the info goes stale fast. Just google it.</li>
<li>Set your app&#8217;s pricing and metadata in iTunes connect. You&#8217;ll need a 512 x 512 icon too.</li>
<li>Follow all the directions about distribution certificates and distribution provisioning profiles. Like a double-linked list your distro cert should point to your provisioning prof and vice versa.</li>
<li>First create the distro cert via keychain access app on your map. Make sure there is key associated with your distro cert after you install it in your key chain.</li>
<li>Second create your distro provisioning prof and install it in Xcode 4. Make sure your target&#8217;s code signing entitlements point to your distro provisioning profile for the release build.</li>
<li>Clean and Archive your app with the Product menu in Xcode 4. The Archive scheme should be set to your release configuration.</li>
<li>In the Organizer window validate and submit your app. You&#8217;ll need your iTunes Connect password.</li>
<li>If you get the dreaded &#8220;invalid coding signing entitlements&#8221; don&#8217;t panic. It could mean a lot of different things. But if your iOS app is simple then it&#8217;s most likely  the iCloud entitlement. (Google it for more info.)</li>
<li>Go to App IDs in the provisioning portal. Scroll to the bottom. Click configure on the row that represents your app&#8217;s ID. Uncheck Enable for iCloud. Click Done. Create a new distro provisioning prof and reinstall it into Xcode 4. Go to iTunes Connect and reject your binary. Go back to Xcode&#8217;s Organizer window and do Validate and Submit again.</li>
<li>If you get an invalid binary. Drink a beer and try again! (do while beer != empty)</li>
</ol>
<div>See, that was easy!</div>
]]></content:encoded>
			<wfw:commentRss>http://www.pavley.com/2011/10/10/invalid-code-signing-entitlements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cocos2d Tip#3: Making Your iPhone Game Fast</title>
		<link>http://www.pavley.com/2011/04/09/cocos2d-tip3-making-your-iphone-game-fast/</link>
		<comments>http://www.pavley.com/2011/04/09/cocos2d-tip3-making-your-iphone-game-fast/#comments</comments>
		<pubDate>Sat, 09 Apr 2011 18:00:50 +0000</pubDate>
		<dc:creator>pav</dc:creator>
				<category><![CDATA[Cocos2d-iPhone]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.pavley.com/?p=349</guid>
		<description><![CDATA[My first iPhone game, that might actually make it to the App Store, is just about done. (Not done done but almost ready for testing and tweaking.) With the idea that other people beside me might actually play my game I&#8217;ve started to do a very dangerous and high risk activity: Optimization! The all the [...]]]></description>
			<content:encoded><![CDATA[<p>My first iPhone game, that might actually make it to the App Store, is just about done. (Not <a href="http://blog.phpdeveloper.org/?p=148">done done</a> but almost ready for testing and tweaking.)</p>
<p>With the idea that other people beside me might actually play my game I&#8217;ve started to do a very dangerous and high risk activity: <a href="http://en.wikipedia.org/wiki/Program_optimization#Quotes">Optimization</a>!</p>
<p>The all the famous Computer Scientists and Software Architects agree: Optimizing your program is a necessary evil, like the death penalty or bug tracking systems, and to be avoided at all costs.</p>
<p>Well, that&#8217;s not quite true. It&#8217;s premature optimization that is the bad guy here. Don&#8217;t start out programming with performance or scalability in mind, least you optimize code that doesn&#8217;t need it and miss optimizing code that really needs it. (It&#8217;s the same for bug tracking systems&#8211;don&#8217;t put all your junk in Jira or Bugzilla&#8211;just the verifiable, repeatable bugs that you might actually fix one day.)</p>
<p>When I started my game I knew my ideas were going to evolve and I didn&#8217;t want to hard code myself into a corner. I consciously wrote code that I knew would be slow but flexible.</p>
<p>For example I used expensive string comparisons instead of testing for cheap numeric constants. During the initial development phases of my game the strings were self-documenting (I could read them like little notes to myself) and easy to change. Later, when my game solidified and the string comparison were easy to find using Xcode&#8217;s Find in Project command (which is now Xcode 4&#8242;s Find in Workspace command)&#8230;</p>
<pre class="brush: c++">// before optimization
if ([goodGuy.role isEqualToString(@"tank") {
   // aggro something
} else if ([goodGuy.role isEqualToString(@"healer") {
   // fix something
}</pre>
<pre class="brush: c++">// after optimization
switch (goodGuy.role) {
   case CharacterRole_tank:
      // aggro something
      break;
   case CharacterRole_healer:
      // fix something
      break;
   default:
      // oops! This should not happen
      CCLOG(@"unknown character role in %@",NSStringFromSelector(_cmd));
      break;
}</pre>
<p>Changing the type of Character's role property from NSString* to CharacterRole (a typedef'ed int) sped up my game in update methods which were called with every frame change. It was a pain to add all the constants but at least I only had to do it once--even though my conception of a Character and a role changed quite a bit.</p>
<pre class="brush: c++">// Character.h
typedef enum {
    CharacterRole_tank = 0,
    CharacterRole_healer = 1,
    CharacterRole_melee = 2,
    CharacterRole_ranged = 3,
    CharacterRole_boss = 4,
    CharacterRole_add1 = 5,
    CharacterRole_add2 = 6,
} CharacterRole;

// Character.m
@interface Character : NSObject  {
   NSString* _name;
   CharacterRole _role;
   // ...
}
@property (readwrite, copy, nonatomic) NSString* name;
@property (readwrite, assign, nonatomic) CharacterRole role;</pre>
<p>Another big optimization I did was to replace for-loops and with Cocos2d's fast enumeration macros...</p>
<pre class="brush: c++">// before optimization
Character* goodGuy = nil;
for (int i = 0; i &lt; self.goodGuys.count; i++) {
   goodGuy = [self.goodGuys objectAtIndex:i];
   // do something with good guy
}

// after optimization
Character* goodGuy = nil;
CCARRAY_FOREACH(self.goodGuys, goodGuy) {
   // do something with good guy
}</pre>
<p>My list of good guys changes during the game so I stored them in a CCArray&#8211;Cocos2d&#8217;s version of a NSMutuableArray. CCARRAY_FOREACH is a Cocos2d macro supercharged for fast array access. I could have used the Objective-C version of a fast numerator but I like to use as much of Cocos2d as I can. That way when I port my game to <a href="http://www.cocos2d-x.org/">Cocos2d-x</a> (C++ cross-platform version) it will be less work <img src='http://www.pavley.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>One of the biggest optimizations I did was to upgrade from Cocos2d 0.99.5-rc1 to 1.0.0-rc. You have to be smart about when you upgrade to a new version of a framework. I don&#8217;t agree with the idea of living on the bleeding edge&#8211;stability of the platform allows me to focus on my own bugs!</p>
<p>Upgrading from Xcode 3 to Xcode 4 also seemed to help, or at least not hurt, performance. The new version of Cocos2d seems to work better with Xcode 4. I&#8217;m still getting used to the shiny new Xcode&#8211;it acts weird and slow on my Mac Mini.</p>
<p>To make framework and Xcode upgrades easy I put very little code into my app delegate class. All I have to do is to comment out&#8230;</p>
<pre class="brush: c++">//[[CCDirector sharedDirector] runWithScene: [HelloWorldLayer scene]];</pre>
<p>and replace it with&#8230;</p>
<pre class="brush: c++">[[CCDirector sharedDirector] runWithScene: [HomeScreen scene]];</pre>
<p>There are lots more optimization I can do if my performance isn&#8217;t where I want it to be: Unroll my loops and get rid of Character lists altogether. But I&#8217;ll lose a lot of abstraction and flexibility so I&#8217;m not going to optimize anything more unless my beta testers complain!</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pavley.com/2011/04/09/cocos2d-tip3-making-your-iphone-game-fast/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cocos2d Tip #2: Using CCTimer in Your iPhone Game</title>
		<link>http://www.pavley.com/2011/03/25/using-cocos2ds-cctimer-in-your-iphone-game/</link>
		<comments>http://www.pavley.com/2011/03/25/using-cocos2ds-cctimer-in-your-iphone-game/#comments</comments>
		<pubDate>Fri, 25 Mar 2011 10:02:18 +0000</pubDate>
		<dc:creator>pav</dc:creator>
				<category><![CDATA[Cocos2d-iPhone]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Sprite]]></category>

		<guid isPermaLink="false">http://www.pavley.com/?p=291</guid>
		<description><![CDATA[If you&#8217;re writing almost any type of game, from a puzzler to a FPS to an RTS, tracking time is critical element of the game play. (Except for Angry Birds. You can ponder an Angry Birds level until your iPhone battery runs dry without penalty.) Cocos2d-iPhone provides several means for tracking time in your game [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re writing almost any type of game, from a puzzler to a FPS to an RTS, tracking time is critical element of the game play. (Except for Angry Birds. You can ponder an Angry Birds level until your iPhone battery runs dry without penalty.)</p>
<p>Cocos2d-iPhone provides several means for tracking time in your game and scheduling methods to be called at both regular heartbeats and at arbitrary points in the future. The easiest way to manage time in a Cocos2d-based game is to use a CCLayer&#8217;s <em>scheduleUpdate</em> or <em>schedule</em> methods. Both methods are explained nicely in the <a href="http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:best_practices#timers">timers</a> section of the <em>Cococ2d Best Practices </em>guide. The guide also explains why you should try to avoid using iOS&#8217;s NSTimer class. (Your game will miss out on automatic pause and resume if do use NSTimer.)</p>
<p>But what if you can&#8217;t use scheduleUpdate or schedule in your game because you&#8217;re putting your game logic into a custom class instead of a CCLayer or CCSprite?</p>
<p>For the sake of simplicity and portability I don&#8217;t subclass CCSprite in my games. Instead, I create custom classes to represent my game objects and call update:(ccTime)delta on them from CCLayer objects to make stuff happen. I needed a nice timer class and started to write my own. About halfway though this project I ran into Cocos2d&#8217;s CCTimer. Since I&#8217;m trying to write as little code as possible I abandoned my timer. CCTimer is a nicely written, lightweight timer class that uses NSInvoker to create callbacks and still integrates will with the rest of the Cocos2d-iPhone framework.</p>
<p>Here&#8217;s how it use it&#8230;</p>
<p>First, I store a reference to a timer in my non-Cocos2d class:</p>
<pre class="brush: c++">
// Zombie.h
#import "cocos2d.h"
@interface Zombie : NSObject {
    BOOL _resurrectable;
    ccTime _resurrectionCountdown;
    CCTimer* _resurrectionTimer; // own
    float _rebirthPenalityPercent;
}
@property (readwrite, nonatomic, assign) BOOL resurrectable;
@property (readwrite, nonatomic, assign) ccTime resurrectionCountdown;
@property (readwrite, nonatomic, retain) CCTimer* resurrectionTimer; // own
@property (readwrite, nonatomic, assign) float rebirthPenalityPercent;
- (void) startResurrectionTimer;
- (void) stopResurrectionTimer;
@end
</pre>
<pre class="brush: c++">
// Zombie.m
#import Zombie.h
@implementation Zombie
@synthesize resurrectable = _resurrectable;
@synthesize resurrectionCountdown = _resurrectionCountdown;
@synthesize resurrectionTimer = _resurrectionTimer;
@synthesize rebirthPenalityPercent = _rebirthPenalityPercent;
+ (id) getInstance {
    CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
    return [[[self alloc] init] autorelease];
}

- (id) init: {
    CCLOG(@"** %@: %@", NSStringFromSelector(_cmd), self);
    if ((self = [super init])) {
        self.resurrectable = YES;
        self.resurrectionCountdown = 30.0f; // half a second
        self.resurrectionTimer = nil;
        self.rebirthPenalityPercent = 0.10f; // 10% less health
    }
}
@end
</pre>
<p>Second, I define a call back method to stop the timer:</p>
<pre class="brush: c++">
// later on in Zombie.m
- (void) stopResurrectionTimer {
    CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
    if (self.resurrectionTimer != nil) {
    // the only way stop a timer is to deallocate it
        [_resurrectionTimer release];
        _resurrectionTimer = nil;
    }
    // do stuff when the zombie dies...
}
</pre>
<p>Third, I define a method to start the timer:</p>
<pre class="brush: c++">
- (void) startResurrectionTimer {
    CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
    if (self.resurrectionTimer != nil) {
         // if there is an old resurrectionTimer then deallocate it
         // (this is the only way to stop a timer)
        [_resurrectionTimer release];
        _resurrectionTimer = nil;
    }
    //  allocate a new timer with a built-in factory method
    // the stopResurrectionTimer method is called when
    // the time is up!
    self.resurrectionTimer = [CCTimer timerWithTarget:self
                                             selector:@selector(stopResurrectionTimer)
                                             interval:self.resurrectionCountdown];
}
</pre>
<p>Fourth, I add a call to update the timer in my CCLayer&#8217;s update method:</p>
<pre class="brush: c++">
// ZombieGameLayer.m
- (void) update:(ccTime)delta {
    [self.zombie.ressurrectionTimer update:delta];
}
</pre>
<p>Finally, Somewhere deep in my game logic I start the timer at the right dramatic moment.</p>
<pre class="brush: c++">
// somewhere else in Zombie.m
- (void) die {
    // call when killed
     CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);

    // if resurrectable start resurrectionTimer
    if (self.resurrectable) {
        [self startResurrectionTimer];
    }
}
</pre>
<p>It&#8217;s important to note that at the time of this blogging, the CCTimer documentation claims the interval value used to determine the length is in seconds, but really it&#8217;s in milliseconds (that is 1/60 of a second). If want your timer&#8217;s call back to run in 2 minutes set the CCTimer interval to 160.0f.</p>
<p>It&#8217;s also important to note that CCTimer is independent of frame rate: This might be obvious but sometime you want to execute an action every frame an sometime you want to execute it every few milliseconds.</p>
<p>If things aren&#8217;t working make sure you&#8217;ve told your layer to schedule updates in it&#8217;s init method and make sure you are updating your timers from your layer <img src='http://www.pavley.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.pavley.com/2011/03/25/using-cocos2ds-cctimer-in-your-iphone-game/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objective-C Memory Management For Newbies</title>
		<link>http://www.pavley.com/2011/02/12/objective-c-memory-management-for-newbies/</link>
		<comments>http://www.pavley.com/2011/02/12/objective-c-memory-management-for-newbies/#comments</comments>
		<pubDate>Sat, 12 Feb 2011 21:32:51 +0000</pubDate>
		<dc:creator>pav</dc:creator>
				<category><![CDATA[Cocos2d-iPhone]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Game Development]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://www.pavley.com/?p=305</guid>
		<description><![CDATA[Below you will find a list of memory management rules that will make your Coco2d game coding experience easier and your games less buggy. But before you dive in please read the caveats below: These rules are based on several sources written by engineers with much more experienced than me in Objective-C and Cocos2D development. [...]]]></description>
			<content:encoded><![CDATA[<p>Below you will find a list of memory management rules that will make your Coco2d game coding experience easier and your games less buggy. But before you dive in <em>please</em> <em>read</em> the caveats below:</p>
<ul>
<li>These rules are based on several sources written by engineers with much more experienced than me in Objective-C and Cocos2D development. Any mistakes are my own, any good idea belong to them.</li>
<li>My sources include this <a href="http://www.raywenderlich.com/2657/memory-management-in-objective-c-tutorial">tutorial</a> by Ray Wenderlich and the <a href="http://www.raywenderlich.com/forums//viewtopic.php?f=2&amp;t=154#p543">comments</a> by fufie. Ray&#8217;s tutorials should be read by every aspiring Coco2d-iPhone developer!</li>
<li>I also found this Stack Overflow <a href="http://stackoverflow.com/questions/588866/atomic-vs-nonatomic-properties">question and answer</a> on property declarations and this <a href="http://cocoacast.com/?q=node/103">blog post</a> on properties by CocoaCast really helpful as well.</li>
<li>Of course all this info is contained in Apple&#8217;s <a href="http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/MemoryMgmt/MemoryMgmt.html">Memory Management Programming Guide</a> in greater detail. RTFM, as they cheerfully remind us in IRC, is a great way to learn.</li>
<li>In many ways this blog post is just a briefing on all of the above material and my motivation for posting this info is just to have it all in once place and neatly summarized.</li>
<li>Finally, these rules are guidelines for inexperienced developers, not laws. Engineers who are experienced with Objective-C memory management and Cocos2d don&#8217;t need these rules and shouldn&#8217;t even bother to waste their time and read my post. Following these rules will keep newbies out of trouble with their first game or two.</li>
</ul>
<p><strong>10 rules that make memory management a breeze&#8230;</strong></p>
<p><strong>Rule #1</strong>: Always create properties for your <em>ivars</em> in your .h and <em>synthesize</em> them in your .m.</p>
<pre class="brush: c++">// in MyClass.h
@interface MyClass : NSObject {
@public NSString* _moniker;
}
@property (nonatomic, copy, readwrite) NSString* moniker;
@end

// in MyClass.m
@implementation MyClass
@synthesize moniker = _moniker;
@end</pre>
<p><strong>Rule #2</strong>: Use an <em>underscore</em> so the compiler can distinguish an ivar from a property with a common root name. When synthesizing remember to associate the ivar with the property. This way the compiler will yell at you if you try to set an ivar as if it were a property.</p>
<pre class="brush: c++">@synthesize moniker = _moniker; // ivar = property</pre>
<p><strong>Rule #3</strong>: Always access your internal properties through <em>self</em> using <em>dot syntax</em> to ensure proper memory management through property declarations.</p>
<pre class="brush: c++">self.moniker = @"Betty"; // the ivar _moniker now refers to a new copy of the string "Betty"</pre>
<p style="padding-left: 30px;"><strong>Note:</strong> In C, C++, and Objective-C the operand on the left must be an <a href="http://stackoverflow.com/questions/579421/often-used-seldom-defined-terms-lvalue">lvalue</a> so you can&#8217;t chain assignments. Code like</p>
<pre class="brush: c++" style="padding-left: 30px;">self.rectangle.top = 10;</pre>
<p style="padding-left: 30px;">generates a compiler error.<br />
Instead you have to unpack the object and assign it back to the property:</p>
<pre class="brush: c++" style="padding-left: 30px;">Rectangle* rect = self.rectangle;
rect.top = 10;
self.rectangle = rect;</pre>
<p><strong>Rule #4</strong>: Always provide an <em>object factory class method</em> to create an instance of your custom objects using autorelease for simple memory management.</p>
<pre class="brush: c++">+(id) getInstance {
	return [[[self alloc] init] autorelease];
}</pre>
<p><strong>Rule #5</strong>. When declaring a property for a basic type or for objects you don&#8217;t own use the <em>assign</em> attribute.</p>
<pre class="brush: c++">@interface MyClass : NSObject {
@public int  _counter;
@public NotYourObject* _notMyObject;
}
@property (nonatomic, assign, readwrite) int counter;
@property (nonatomic, assign, readwrite) notMyObject;
@end</pre>
<p><strong>Rule #6</strong>: When declaring a property for a subclass of NSObject use the <em>retain</em> attribute to retain the object on assignment and release the original object (if any) associated with the property.</p>
<pre class="brush: c++">@interface MyClass : NSObject {
@public Something*  _thing;
}
@property (nonatomic, retain, readwrite) Something*  thing;
@end</pre>
<p><strong>Rule #7</strong>: When declaring a property for an NSString use the <em>copy</em> attribute to create a copy on assignment and release the original string (if any) associated with the property. You probably want the assigned string and the original string to be two independent objects.</p>
<pre class="brush: c++">@interface MyClass : NSObject {
@public NSString*  _moniker;
}
@property (nonatomic, copy, readwrite) NSString* moniker;
@end</pre>
<p><strong>Rule #8</strong>: Use the <em>autorelease</em> to automatically release objects when you are done with them.</p>
<pre class="brush: c++">self.thing =  [[[SomeThing alloc] init] autorelease];</pre>
<p><strong>Rule #9</strong>: Apple API calls that begin with &#8220;init&#8221; or &#8220;copy&#8221; need to be managed by you and released when you&#8217;re done with them. You can use rule #8 to make releasing objects at the end of a method painless.</p>
<pre class="brush: c++">self.moniker = [NSString stringWithFormat:@"%@ number %i", @"Betty, 2]; // already autoreleased
self.moniker = [[NSString initWithFormat:@"%@ number %i", @"Betty, 3] autorelease]; // needs autorelease</pre>
<p><strong>Rule #10</strong>: Always use the <em>nonatomic</em> attribute when declaring properties unless you are working with multiple threads&#8211;and if you are working with multiple threads you are way above the level of these rules.</p>
<pre class="brush: c++">@property (nonatomic, assign, readwrite) int counter;</pre>
<p><strong>Rule #11: </strong>Always use the ivar in your delloc method to release objects you own and set them to nil (to ensure safe subclassing).</p>
<pre class="brush: c++">[_moniker release];
_moniker = nil;</pre>
<p><strong>A thought on static analysis&#8230;</strong></p>
<p>Xcode&#8217;s <em>Build and Analyze</em> (Shift-Cmd-A) always drives me crazy with false positives. First, it finds potential issues with the Cocos2D framework source files and I&#8217;m not about to worry about or fix any of those. Second, all the issues it finds in my source files are either trivial non-issues (an assignment hidden inside an if-then-else block) or not problems at all (releasing object that it thinks I don&#8217;t own). But perhaps it&#8217;s my coding style that needs to improve. I hate letting warnings go by unresolved and as soon as figure out a way to write code the makes static analysis happy I&#8217;ll let you know.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pavley.com/2011/02/12/objective-c-memory-management-for-newbies/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Nope: I Haven&#8217;t Stopped Reading</title>
		<link>http://www.pavley.com/2009/07/29/nope-i-havent-stopped-reading/</link>
		<comments>http://www.pavley.com/2009/07/29/nope-i-havent-stopped-reading/#comments</comments>
		<pubDate>Thu, 30 Jul 2009 03:45:44 +0000</pubDate>
		<dc:creator>pav</dc:creator>
				<category><![CDATA[Tech Trends]]></category>
		<category><![CDATA[e-book]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Kindle]]></category>

		<guid isPermaLink="false">http://www.pavley.com/?p=29</guid>
		<description><![CDATA[Steve Jobs is a man we all admire and respect. Even when he says something, well, dumb. Back in January of 2008 Steve told a NY Times reporter that &#8220;&#8230; American&#8217;s have stopped reading.&#8221; Steve cited this as the reason the Amazon Kindle would fail. In the past year and half the Kindle has been [...]]]></description>
			<content:encoded><![CDATA[<p>Steve Jobs is a man we all admire and respect. Even when he says something, well, dumb. Back in January of 2008 Steve told a NY Times reporter that &#8220;&#8230; American&#8217;s have <a href="http://bits.blogs.nytimes.com/2008/01/15/the-passion-of-steve-jobs/?ex=1358226000&amp;en=dc35254b0fcd5490&amp;ei=5090&amp;partner=rssuserland&amp;emc=rss">stopped reading</a>.&#8221; Steve cited this as the reason the Amazon Kindle would fail. In the past year and half the Kindle has been selling pretty well. But it gets even better: E-book readers from Amazon and Barns &amp; Noble are popular applications for the iPhone. There are over 40o book-related applications available for download on Apple&#8217;s App Store. One of my favorites is the <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&amp;docId=1000301301">Kindle for iPhone</a>.</p>
<p>I don&#8217;t own a physical Kindle. I don&#8217;t need a another electronic device. All the sockets on my power strip are filled! The iPhone is my phone, emailer, broswer, PIM, GPS, notebook, music player, camera, and now e-book reader. While I don&#8217;t agree with Steve that Americans have stopped reading I do agree that that specialized single function harward like the Kindle has a dim future. Kindle software, and book readers in general, on small multifunctional devices like the iPhone have a bright future.</p>
<p>Since I downloaded the Kindle software I&#8217;ve bought and read 6 digital books in 60 days. But here&#8217;s the important point&#8211;I would not have read these books otherwise. I don&#8217;t get a lot of traditional time to read between a busy <a href="www.conductor.com">startup</a> and a house full of kids. With the iPhone I can read while waiting on a line at the pharmacy, or while sitting on a stalled train somewhere between Newark and New York, or while waiting for soccer practice to fishing up.</p>
<p>When I was younger (by several decades) I used to carry around a paperback book on the off chance that I&#8217;d get a moment to read it. These days I don&#8217;t have the time to think that far ahead. Downloading and reading books on the iPhone is just so damn convenient it has replaced <a href="http://www.tiptopworkshop.com/blocked/">Blocked</a> as my favorite time biding activity.</p>
<p>The only real issue is Amazon&#8217;s digital supply of <a href="http://en.wikipedia.org/wiki/Nebula_Award_for_Best_Novel">Nebula Award</a> winners is running dry. Some important books from the list, The Quantum Rose, Parable of the Talents, Forever Peace, and Moon and Sun, are tragically missing. I&#8217;m anxious to download Barns &amp; Noble&#8217;s Bookstore reader and see if they can pick up the digital slack.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.pavley.com/2009/07/29/nope-i-havent-stopped-reading/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

