<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>Luke Hatcher</title>
	
	<link>http://www.lukehatcher.com</link>
	<description>That's my name. Don't wear it out.</description>
	<lastBuildDate>Tue, 05 May 2009 15:19:37 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/lukehatcher" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
		<title>Store Binary Data in Twitter With Tootfiles</title>
		<link>http://www.lukehatcher.com/2009/05/storing-binary-data-in-twitter/</link>
		<comments>http://www.lukehatcher.com/2009/05/storing-binary-data-in-twitter/#comments</comments>
		<pubDate>Sun, 03 May 2009 04:00:41 +0000</pubDate>
		<dc:creator>Luke</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://lukehatcher.com/?p=146</guid>
		<description><![CDATA[<a href="http://lukehatcher.com/wp-content/uploads/2009/05/birdus.png"><img src="http://lukehatcher.com/wp-content/uploads/2009/05/birdus.png" alt="Creative Commons photo courtesy of Flickr user mrclean: http://www.flickr.com/photos/mrclean/" title="Creative Commons photo courtesy of Flickr user mrclean: http://www.flickr.com/photos/mrclean/" width="540" height="240" class="aligncenter size-full wp-image-245" /></a> 

Sometimes a man's worst ideas lead to his finest moments: Ben Franklin decides to fly a kite in a storm and we get electricity (I'm paraphrasing that story), Alexander Graham Bell shacks up with his 15-year-old apprentice (who was deaf) and we get the telephone (paraphrasing again). 

Now, I don't fly kites and my wife is neither 15 years old nor deaf, but I feel you and I might be on the cusp of solving the world's data storage needs as I, too, have a terrible idea: **let's put _everything_ in Twitter.** _Everything._ Music, photos, tax forms--you name it, we should be able to store the data in a Twitter stream.]]></description>
			<content:encoded><![CDATA[<p><a href="http://lukehatcher.com/wp-content/uploads/2009/05/birdus.png"><img src="http://lukehatcher.com/wp-content/uploads/2009/05/birdus.png" alt="Creative Commons photo courtesy of Flickr user mrclean: http://www.flickr.com/photos/mrclean/" title="Creative Commons photo courtesy of Flickr user mrclean: http://www.flickr.com/photos/mrclean/" width="540" height="240" class="aligncenter size-full wp-image-245" /></a></p>

<p>Sometimes a man&#8217;s worst ideas lead to his finest moments: Ben Franklin decides to fly a kite in a storm and we get electricity (I&#8217;m paraphrasing that story), Alexander Graham Bell shacks up with his 15-year-old apprentice (who was deaf) and we get the telephone (paraphrasing again).</p>

<p>Now, I don&#8217;t fly kites and my wife is neither 15 years old nor deaf, but I feel you and I might be on the cusp of solving the world&#8217;s data storage needs as I, too, have a terrible idea: <strong>let&#8217;s put <em>everything</em> in Twitter.</strong> <em>Everything.</em> Music, photos, tax forms&#8212;you name it, we should be able to store the data in a Twitter stream.</p>

<h3>Brilliance begets &#8216;tootfiles&#8217;</h3>

<p>So yes, you probably have realized that storing all of your binary data in Twitter is one of the top five or six ideas of this decade, so you&#8217;re as eager as I am to begin implementation. Luckily, I&#8217;ve already gone to the trouble and written a Python script that does just this: I call it <a href="http://github.com/lukeman/tootfiles/">tootfiles</a>.</p>

<p><strong>Note: What follows is a detailed look at how this project was built and the various choices I made along the way. If the details of character encodings and data compression bore you and you&#8217;re only interested in seeing the final code or using the script yourself, you can check out the <a href="http://github.com/lukeman/tootfiles/">tootfiles project page over at my Github account</a>. I promise I won&#8217;t judge you.</strong></p>

<h3>A Quick (and faulty) Look at the Numbers</h3>

<p>Twitter allows us to post individual text messages to its service with up to 140 bytes per message. Assuming for a moment that each binary byte can be represented as one character byte in a toot, it is fairly simple to gauge how many toots it will take to represent a file given its size in bytes. For example, the <a href="http://www.google.com/intl/en_ALL/images/logo.gif">standard sized Google search logo</a> weighs in at 8,558 bytes. Divided up into 140 byte segments, you might determine that we could represent this file with 62 individual toots. That sounds like a lot of bit-sized messaging, but consider that internet celebrity <a href="http://twitter.com/scobleizer">Robert Scoble</a> has over 20,000 toots to his name and still has over 90,000 followers fawning over whatever it is that he actually does.</p>

<p>A more amusing case study might be trying to store a music file in your Twitter stream. Doing a quick search for some legal music to test with, I&#8217;ve found a punchy little number from the year 1909 called &#8220;<a href="http://www.archive.org/details/JohnGoAndPutYourTrousersOn1909">John, Go and Put Your Trousers On</a>.&#8221; With this short piece weighing in at 3,586,134 bytes, it would only take 25,615 individual toots to represent it as a tootfile. I&#8217;ll admit that this is a disturbingly high number of messages to store a small music file, but life is about trudging through dead end projects and never letting it break your spirit, so we&#8217;re just going to pretend it&#8217;s not a problem. Did you hear that? <em>It&#8217;s not a problem.</em></p>

<h3>Reality Bytes</h3>

<p>So the truth is we can&#8217;t just slice the files up and stick the pieces into a toot. Binary files are a different beast from the short, nearly plaintext messages of Twitter. To fit any possible binary byte into a string that we can store in Twitter, we&#8217;ll need to store these bytes using some type of standard encoding system.</p>

<h4>Choosing an encoding system</h4>

<p>The two candidate encoding systems I evaluated for this project were Base64 and Base85, with the trailing number indicating the size of the usable character set. To understand this a little better, remember that binary is base 2 (it can represent any number using only 1 or 0) and the standard numerical representation is base 10 (representing any number using 0-9). You could theoretically encode anything using any base, but the higher the base the tighter you can pack the data in.</p>

<h4>Size Matters&#8230;</h4>

<p>I said before that the higher the base, the more efficiently you can pack data into your string. To examine this a little closer, let us look at the real world difference between Base64 and Base85 encodings.</p>

<p>Base64 uses the character ranges <code>A–Z</code>, <code>a–z</code>, and <code>0–9</code> for its first 62 character slots. Depending on the implementation (and there are a few), the remaining two characters differ. In mapping binary to this encoding scheme, Base64 uses four characters to represent three bytes of data. This leads to a roughly 33% increase in size when representing a binary file in Base64.</p>

<p>Base85 (as defined in <a href="http://www.rfc-editor.org/rfc/rfc1924.txt">RFC1924</a>) uses the character ranges <code>0–9</code>, <code>A–Z</code>, <code>a–z</code>, and the 23 characters <code>!#$%&#038;()*+-;&lt;=>?@^_`{|}~</code> to represent data. By using five characters to represent four bytes of data, Base85 typically can represent a binary file with a 25% increase in size.</p>

<p>To compare these encodings using our two example files from above, I wrote a script that encodes the files with Base64 (as it&#8217;s included in the standard lib) and used <a href="http://paste.lisp.org/display/72815">this pure Python implementation</a> which does the same with Base85. You can compare the file sizes in the chart below.</p>

<p><img src="http://lukehatcher.com/wp-content/uploads/2009/05/filechart.png" alt="filechart" title="filechart" width="540" height="108" class="aligncenter size-full wp-image-165" style="border:none; padding:none;" /></p>

<p>There seem to be no surprises there, as the numbers back up our earlier claims with regard to encoding efficiency.</p>

<h4>&#8230; But Character Sets Matter More</h4>

<p>So yeah&#8212;Base85 is much more efficient; that&#8217;s the pick, right? I&#8217;ll now ask that you hold on for just one moment, as there is one more issue that we must consider: the characters used to represent our data in the encodings.</p>

<p>You see, Twitter has a little known &#8216;feature&#8217; that does a bit of post-processing to your messages to prevent bad guys from inserting scripts into a Twitter stream. This sanitization of Twitter messages takes certain special characters and converts them into HTML entities, meaning that characters like <code>&lt;</code>, <code>&gt;</code>, and <code>&#038;</code> get expanded into safer representations of themselves.</p>

<p>Sanitizing messages is great because it keeps you and I safe when we&#8217;re tooting away, but this has serious implications for our data storage scheme. You see, converting these single characters into HTML encodings means the characters now take up four bytes instead of one. Base85 includes a number of characters that Twitter translates into HTML entities, so our 140 byte messages might actually end up taking up much more than that and cause problems in the decode process.</p>

<p>For the above reason, its smarter for us to stick with good old Base64 encoding. Even without Base85&#8217;s character issues (get it?), there&#8217;s something to be said for having a standard Base64 implementation baked right in to most standard libraries as well.</p>

<h3>Implementation Details</h3>

<p>Instead of walking through every line of the code, I want to just highlight some of the other choices I made and what it means for the finished product. This is broken down into two sections&#8212;one for posting to and one for decoding files from Twitter&#8212;as the situations require different approaches. The code snippets are shown as Python functions for brevity, but you&#8217;ll notice that the <a href="http://github.com/lukeman/tootfiles/">final code</a> handles things with an object-oriented design.</p>

<h3>Posting Data to Twitter</h3>

<h4>Compression</h4>

<p>Before encoding our data to be posted to Twitter, we should really employ some type of simple data compression. Using the standard <code>zlib</code> package that ships with Python, I ran our two example files from before through a quick script to see how much compression really helps us. The snippet below (shortened at the expense of <a href="http://www.python.org/dev/peps/pep-0008/">PEP 8</a>) should give you an indication of how to do this on your own.</p>

<pre class="brush: python; gutter: false;">
import os, sys, zlib, base64

f = open('somefile', 'rb')
fcompressed = zlib.compress(f.read())
fencoded = base64.b64encode(fcompressed) 
</pre>

<p>The results from the run are shown in the following chart.</p>

<p><img src="http://lukehatcher.com/wp-content/uploads/2009/05/filecompresschart.png" alt="filecompresschart" title="filecompresschart" width="540" height="102" class="aligncenter size-full wp-image-203" /></p>

<p>This chart actually surprised me a bit, as I had only hoped to shrink the file down enough to save <em>some</em> of extra cruft we saw after encoding. While the compressed Google logo is only slightly smaller than the Base64 encoded file, our rousing hit song about trousers from 1909 has been reduced to a startling <em>82% of the original file&#8217;s size</em>. Your mileage will vary on this, as some file formats compress better than others while many formats are compressed by default, but it&#8217;s clearly a huge win to include a bit of fast compression to our code.</p>

<h4>Get Your toot in the Door</h4>

<p>So now that we have a decent handle on our compressed and encoded data, it&#8217;s time to think about getting it tooted. Before posting the messages to Twitter, we&#8217;ll first need to split the large string of data into 140 byte chunks. The below function does just this, given a <code>data</code> string and defaulting the slice size to 140.</p>

<pre class="brush: python; gutter: false;">
def segment(data, n=140):
  ''' Given the encoded string, slice it into twitter ready array elements '''
  tootcount = int(math.ceil(len(data)/float(n)))

  slices = range(tootcount)
  slices.reverse()
  
  return [data[i*n:(i+1)*n] for i in slices]
</pre>

<p>You&#8217;ll notice that we reverse the range in the <code>segment()</code> function, as we want to build the list from tail to head. This reverse order makes reading the individual toots easy later on in the decode section, as we can simply iterate through the stream grabbing the toots in order.</p>

<p>Including some type of header helps signify the start of a file, along with a bit of metadata. Header information is appended to the list (to be posted last) using the following format:</p>

<pre class="brush: python; gutter: false;">
tootlist = segment(data)

# Header Information
header = "|Tootfile:'%s' MD5:'%s' Count:'%s'|" 
         % (filename, md5hash, tootcount)

tootlist.append(header) # Insert the header
</pre>

<p>With this header, we&#8217;re helping future decode runs by including three important pieces of information: the name of the file, the MD5 hash of the file data (for integrity checking), and the number of data segments that will follow the header.</p>

<h4>Publishing the Segments</h4>

<p>Publishing the toots to Twitter is accomplished using the Twitter-python library. It&#8217;s a fairly simple library to use (<a href="http://twitter.com/montylounge/status/1682434987">despite the uppercase method names</a>), so I won&#8217;t get into the details of this other than to provide a quick look at the <code>publish()</code> method:</p>

<pre class="brush: python; gutter: false;">
def publish(data, username, password):
    api = twitter.Api(username, password)
    for toot in data:
        for retries in range(5):
            try:
                status = api.PostUpdate(toot)
                break
            except:
                if retries == 4:
                    raise Exception('Unable to post a segment. Quitting.')
                else:
                    time.sleep(1)
    print "Finished."
</pre>

<p>There&#8217;s some rudimentary fault tolerance built in, as I encountered some timeout issues when tooting a larger file. The run will fail if it cannot post a single toot with five attempts.</p>

<h3>Retrieving Data from Twitter</h3>

<p>This part of the project was a bit tricky, as the Twitter API does not seem to provide a good way to access a single user&#8217;s stream of toots for more than a single page. My preferred method was for a user to only need to know the ID of a tootfile header when retrieving files.</p>

<p>The first issue I ran into was not knowing the username to grab all of the toots from. I ended up using <a href="http://www.undefined.org/python/"><code>simplejson</code></a> and using a call to <code>http://twitter.com/statuses/show/&lt;TOOTID&gt;.json</code> to grab enough info given a single Twitter message ID to do the rest of our business. The key piece of info I needed was the Twitter username that owns the toot. I could have settled and required a full URL path to the header (which includes username), but this was a choice I made&#8212;right or wrong&#8212;as to how I wanted this implemented.</p>

<p>After reading a <a href="http://www.movingtofreedom.org/2009/03/18/python-script-for-backing-up-twitter-statuses/">blog post from Scott Carpenter</a>, I decided to just use the fantastic Python HTML scraping library <a href="http://www.crummy.com/software/BeautifulSoup/"><code>BeautifulSoup</code></a> to grab the tweets out of the given users stream. While Scott&#8217;s goal was to archive all of his Twitter messages, I was able to simplify the script to grab just the info we needed. The modified section is below.</p>

<pre class="brush: python; gutter: false;">
def walk(username, headerid, tootcount):
    tootlist = []
    grabbedtoots = 0
    
    url = 'http://twitter.com/%s?page=%s'
    re_status_id = re.compile(r'.*/status/([0-9]*).*')
    
    # find the max number of pages, based on 20 per page
    maxpages = int(math.ceil(int(tootcount)/20.0))

    for page in range(1, maxpages+1):
        f = urllib.urlopen(url % (username, page))
        soup = BeautifulSoup(f.read())
        f.close()

        toots = soup.findAll('li', {'class': re.compile(r'.*\bstatus\b.*')})
        if len(toots) == 0:
            break

        for toot in toots:
            # Do we need more toots? If so, keep going
            if grabbedtoots < int(tootcount):
                m = re_status_id.search(toot.find('a', 'entry-date')['href'])
                status_id = m.groups()[0]

                # Look for the message directly after our header
                if(int(status_id) < int(headerid)):
                    data = str(toot.find('span', 'entry-content').renderContents())
                    tootlist.append(data)
                    grabbedtoots += 1
            else:
                break

        # one second delay between pages 
        time.sleep(1)
</pre>

<p>There&#8217;s nothing too fancy going on here&#8212;just some pulling down of the Twitter pages and scraping out the messages. This implementation of <code>walk()</code> is naive and assumes that you only have one tootfile in your stream and that it is located at the front of your stream. I consider this a bug, so it will be fixed eventually in the actual project.</p>

<p>Reassembling the data is fairly trivial once you have the data in a list. The following snippet works backwardly compared to the encryption, peeling back the layers of compression and encoding before leaving you with a string representing the file data.</p>

<pre class="brush: python; gutter: false;">
def decode(tootlist):
    """Decodes the raw data given a list of toots"""
    data = "".join(tootlist)
    compressed_data = base64.b64decode(data)
    rawdata = zlib.decompress(compressed_data)
    md5hash = md5.new(self.rawdata).hexdigest()
</pre>

<p>With that, we&#8217;re done. The decode process can now check the md5 hash of the assembled data against what&#8217;s in the header and write out the <code>rawdata</code> to either a file or standard out.</p>

<h3>Grab the source and fork it for your own needs</h3>

<p>If you&#8217;re interested in the full (and slightly more proper) Python implementation of tootfiles, you can grab the source code and documentation over <a href="http://github.com/lukeman/tootfiles/">at its Github project</a>. The script can either be used as a standalone command line encoder, or you can use it as a Python library.</p>

<p>I&#8217;m releasing the script with an MIT license, which basically means you can do whatever you want with it.</p>

<p>This is mostly a proof of concept release, as the whole idea of storing meaningful amounts of data in 140 byte segments is absolutely silly. Even as I write this, I&#8217;m aware of a few bugs that would occur if someone were to try and use it heavily. With that said, I&#8217;ll continue to iron things out and I will gladly accept any patches as well.</p>

<p>If you&#8217;re interested in seeing some actual postings from the script, check out <a href="http://twitter.com/tootfiles">tootfiles</a> on Twitter. Have fun, and <em>please</em> don&#8217;t spam your followers with a tootfile&#8212;especially if you&#8217;re someone that I&#8217;m following. ;)</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lukehatcher?a=5Jev4vN2X9Q:j460mQ9G0AE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/lukehatcher?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=5Jev4vN2X9Q:j460mQ9G0AE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/lukehatcher?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=5Jev4vN2X9Q:j460mQ9G0AE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/lukehatcher?i=5Jev4vN2X9Q:j460mQ9G0AE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=5Jev4vN2X9Q:j460mQ9G0AE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/lukehatcher?i=5Jev4vN2X9Q:j460mQ9G0AE:F7zBnMyn0Lo" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.lukehatcher.com/2009/05/storing-binary-data-in-twitter/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Coloring Sprites With Cocos2d-iPhone</title>
		<link>http://www.lukehatcher.com/2009/04/coloring-sprites-with-cocos2d-iphone/</link>
		<comments>http://www.lukehatcher.com/2009/04/coloring-sprites-with-cocos2d-iphone/#comments</comments>
		<pubDate>Mon, 06 Apr 2009 12:00:33 +0000</pubDate>
		<dc:creator>Luke</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[cocos2d]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[iphone]]></category>

		<guid isPermaLink="false">http://lukehatcher.com/?p=41</guid>
		<description><![CDATA[!["Mario or Luigi? It's all in the pants"](http://lukehatcher.com/wp-content/uploads/2009/04/mario.png)

As someone who enjoys finding better ways to do things, I wanted to share a new tip I learned this weekend. Do you find yourself wrangling a handful of all too similar sprites, only varying by color? A useful pattern in game development is to keep the number of sprites in your project to a minimum by performing what's called a [palette swap][palette] of the colors in the images. Fortunately for us, Ricardo Quesada's [cocos2d iPhone game engine][cocos2d] makes it a piece of cake to color your textures on the fly.

[palette]:http://www.giantbomb.com/palette-swap/92-1434/
[cocos2d]:http://code.google.com/p/cocos2d-iphone/]]></description>
			<content:encoded><![CDATA[<p><img src="http://lukehatcher.com/wp-content/uploads/2009/04/mario.png" alt="&quot;Mario or Luigi? It's all in the pants&quot;" /></p>

<p>As someone who enjoys finding better ways to do things, I wanted to share a new tip I learned this weekend. Do you find yourself wrangling a handful of all too similar sprites, only varying by color? A useful pattern in game development is to keep the number of sprites in your project to a minimum by performing what&#8217;s called a <a href="http://www.giantbomb.com/palette-swap/92-1434/">palette swap</a> of the colors in the images. Fortunately for us, Ricardo Quesada&#8217;s <a href="http://code.google.com/p/cocos2d-iphone/">cocos2d iPhone game engine</a> makes it a piece of cake to color your textures on the fly.</p>

<p>Credit for this idea goes to <a href="http://groups.google.com/group/cocos2d-iphone-discuss/browse_frm/thread/ca9ea0a9d02e95da?tvc=1&#038;q=setRGB">Codemattic</a> from the <a href="http://groups.google.com/group/cocos2d-iphone-discuss/">cocos2d-iphone discussion group</a>, but I thought it was worth expanding upon to spread the knowledge and throw some code around while I&#8217;m at it.</p>

<h3>Let&#8217;s gather our tools</h3>

<p><em>Note: Code snippets in this article assume that you&#8217;re using version 0.7.1 or later of cocos2d. If you&#8217;re interested in grabbing the final product, you can <a href="http://cloud.github.com/downloads/lukeman/cocos2d-sprite-color-demo/cocos2d-sprite-color-demo.zip">download the finished project</a> from GitHub. You can also browse the source tree or fork it for yourself at the <a href="http://github.com/lukeman/cocos2d-sprite-color-demo/">GitHub project page</a>.</em></p>

<p>To implement this demo, <strong>you will need to have a working cocos2d project to hack with</strong>. My code snippets will live in the SimpleGame project that I co-maintain over at GitHub. If you&#8217;d like to play along, <a href="http://cloud.github.com/downloads/monoclestudios/simplegame/simplegame.zip">grab a copy of SimpleGame</a> and have it handy.</p>

<p><a href="http://lukehatcher.com/wp-content/uploads/2009/04/colorsprite.png"><img src="http://lukehatcher.com/wp-content/uploads/2009/04/colorsprite.png" alt="Plain sprite" title="ColorSprite" width="45" height="100" style="background:transparent;border:none;" align="right" /></a>Also, grab a copy of the simple humanoid sprite to the right&#8212;we&#8217;ll be adding it to our project to demonstrate the effect. You can either <a href="http://lukehatcher.com/wp-content/uploads/2009/04/colorsprite.png">right-click on this link</a> or save the image using your browser.</p>

<h3>Implementation</h3>

<h4>Import your sprite and draw it</h4>

<p>The first thing you&#8217;ll want to do is open up the XCode project you&#8217;ll be working with. Feel free to use your own cocos2d 0.7.1+ project, or use the <a href="http://cloud.github.com/downloads/monoclestudios/simplegame/simplegame.zip">provided one from above</a>. From this point on, I&#8217;m going to assume you&#8217;re using the provided project. If you have your own, I expect you&#8217;ll know more about where the code should go than I do.</p>

<p>Once you&#8217;re in XCode, right click on <code>Resources</code> in the project pane to the left and choose <code>Add -&gt; Existing Files...</code> from the context menu. Browse to find your copy of the humanoid sprite from above and click <code>Add</code>. On the next dialog, 
click the checkbox next to <code>Copy items into destination group's folder (if needed)</code> and then choose <code>Add</code> again.</p>

<p>Now that the sprite image is added to your project, let&#8217;s write some code to display it on the screen. We&#8217;ll be working in the <code>GameLayer</code> portion of the <code>GameScene</code>, so open up <code>GameScene.m</code> and find the <code>init</code> method on or around line 27.</p>

<p>Modify <code>init</code> to look like this, changing &#8220;ColorSprite.png&#8221; to whatever name you might have saved the image as:</p>

<pre class="brush: c++; gutter: false">
- (id) init {
    self = [super init];
    if (self != nil) {
        isTouchEnabled = YES;
        
        // Add our original sprite to the layer
        Sprite *plainSprite = [Sprite spriteWithFile:@"ColorSprite.png"];
        [plainSprite setPosition:cpv(150, 160)];
        [self addChild:plainSprite z:0];
    }
    return self;
}
</pre>

<p>Assuming no typos, and that you&#8217;ve referenced the sprite filename correctly, hit <code>Build and Go</code> in the XCode toolbar to run the project. Once the app is running, choose the <code>Start Game</code> option on the menu and you&#8217;ll something like what I have below. (I took the liberty of changing the background of the layer to make the screenshots clearer)</p>

<p><img src="http://lukehatcher.com/wp-content/uploads/2009/04/plainsprite.png" alt="A Simple sprite on the canvas" /></p>

<h4>Color away</h4>

<p>We&#8217;re in a good spot now to see the power of coloring our sprite. To accomplish this, we&#8217;ll add another copy of our sprite to the layer and employ the <code>setRGB:::</code> method to it.</p>

<p>Add the following block right below the three lines you added previously to the <code>init</code> method.</p>

<pre class="brush: c++; gutter: false">
        // Add a red sprite onto the layer
        Sprite *redSprite = [Sprite spriteWithFile:@"ColorSprite.png"];
        [redSprite setPosition:cpv(200, 160)];
        [redSprite setRGB:255 :0 :0];
        [self addChild:redSprite z:0];
</pre>

<p>Notice the only difference in the above code is our use of the setRGB method on the sprite. Using standard RGB color values, you can theoretically tint your sprite into 16,581,375 colors. For this demo, we&#8217;re sticking to the primary colors.</p>

<p>Also, <em>and this is important</em>, the math behind this method is ruthless&#8212;it works nicely with a white (RGB 0,0,0) pixel, but might do scary things to your orange boot sprite. I trust that you will use this tastefully.</p>

<p>Before you run the above code, let&#8217;s add two more sprites right below it to really spruce things up.</p>

<pre class="brush: c++; gutter: false">
        // Add a green sprite onto the layer
        Sprite *greenSprite = [Sprite spriteWithFile:@"ColorSprite.png"];
        [greenSprite setPosition:cpv(250, 160)];
        [greenSprite setRGB:0 :255 :0];
        [self addChild:greenSprite z:0];
        
        // Add a blue sprite onto the layer
        Sprite *blueSprite = [Sprite spriteWithFile:@"ColorSprite.png"];
        [blueSprite setPosition:cpv(300, 160)];
        [blueSprite setRGB:0 :0 :255];
        [self addChild:blueSprite z:0];
</pre>

<p>These two blocks will draw a green and blue copy of our sprite. If you&#8217;ve typed everything correctly, you can run the project now and see the brightly colored fruits of our labor.</p>

<p><img src="http://lukehatcher.com/wp-content/uploads/2009/04/finished.png" alt="Finished product" /></p>

<h3>Conclusion</h3>

<p>I hope you find this trick as useful as I have. While we&#8217;ve covered a simple example where the entire sprite is tinted to one color, one could (and should) use this approach to create complex, layered sprites with interchangeable parts.</p>

<p>Trouble? Let me know in the comments, but feel free to <a href="http://cloud.github.com/downloads/lukeman/cocos2d-sprite-color-demo/cocos2d-sprite-color-demo.zip">grab a copy of the finished project</a> if you&#8217;re interested.</p>

<p><strong>Update 4/29/2009:</strong> <a href="http://code.google.com/p/cocos2d-iphone">Cocos2d-iphone v0.7.2</a> has been released which includes two new actions, TintBy and TintTo, which might be of interest to readers of this post.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lukehatcher?a=6UXuZXYdQmU:u-FAKpPClCE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/lukehatcher?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=6UXuZXYdQmU:u-FAKpPClCE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/lukehatcher?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=6UXuZXYdQmU:u-FAKpPClCE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/lukehatcher?i=6UXuZXYdQmU:u-FAKpPClCE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=6UXuZXYdQmU:u-FAKpPClCE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/lukehatcher?i=6UXuZXYdQmU:u-FAKpPClCE:F7zBnMyn0Lo" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.lukehatcher.com/2009/04/coloring-sprites-with-cocos2d-iphone/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>touchDefense – Tower Defense for the iPhone</title>
		<link>http://www.lukehatcher.com/2008/11/announcing-touchdefense-tower-defense-for-the-iphone/</link>
		<comments>http://www.lukehatcher.com/2008/11/announcing-touchdefense-tower-defense-for-the-iphone/#comments</comments>
		<pubDate>Mon, 10 Nov 2008 13:44:04 +0000</pubDate>
		<dc:creator>Luke</dc:creator>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[cocos2d]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[monocle]]></category>

		<guid isPermaLink="false">http://lukeman.webfactional.com/?p=9</guid>
		<description><![CDATA[After three months of development, I'm proud to announce the release of [touchDefense][td] for the iPhone and iPod Touch.

[td]: http://touchdefense.com]]></description>
			<content:encoded><![CDATA[<p>After three months of development, I&#8217;m proud to announce the release of <a href="http://touchdefense.com">touchDefense</a> for the iPhone and iPod Touch.</p>

<p>This release is a joint venture between <a href="http://lethain.com">Will Larson</a> and myself. If you&#8217;re not familiar with Will&#8217;s work, just know that he&#8217;s an ace coder with a reputation for quality.</p>

<p>The touchDefense website is located at <a href="http://touchdefense.com">http://touchdefense.com</a>. The game is available for purchase at the introductory price of $3.99 on the <a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=295579967&#038;mt=8">App Store</a>.</p>

<h3>So what&#8217;s it all about?</h3>

<p><img src="http://touchdefense.com/static/full/IMG_0013.PNG" alt="Screenshot of touchDefense" /></p>

<p>touchDefense is a tower defense game for the iPhone OS. If you&#8217;re not familiar with the genre, <a href="http://en.wikipedia.org/wiki/Tower_defense">this Wikipedia entry</a> should give you the rundown. The game features touch controls, allowing you to simply drag towers onto the playing grid. There are five levels included in 1.0, but we expect to add more in an upcoming free update.</p>

<h3>Monocle Studios LLC</h3>

<p>Preceding the release of touchDefense, Will and I formed a software development company, <a href="http://monoclestudios.com">Monocle Studios LLC</a>. We&#8217;re still working up plans for the future of Monocle Studios, but rest assured that includes both exciting new releases as well as free content updates to touchDefense.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lukehatcher?a=sif_WalAxEs:4iIozDpgM34:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/lukehatcher?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=sif_WalAxEs:4iIozDpgM34:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/lukehatcher?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=sif_WalAxEs:4iIozDpgM34:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/lukehatcher?i=sif_WalAxEs:4iIozDpgM34:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=sif_WalAxEs:4iIozDpgM34:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/lukehatcher?i=sif_WalAxEs:4iIozDpgM34:F7zBnMyn0Lo" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.lukehatcher.com/2008/11/announcing-touchdefense-tower-defense-for-the-iphone/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Thoughts on Version Control</title>
		<link>http://www.lukehatcher.com/2008/09/thoughts-on-version-control/</link>
		<comments>http://www.lukehatcher.com/2008/09/thoughts-on-version-control/#comments</comments>
		<pubDate>Thu, 04 Sep 2008 01:15:11 +0000</pubDate>
		<dc:creator>Luke</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[dvcs]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://lukeman.webfactional.com/?p=11</guid>
		<description><![CDATA[A while back, Django core developer James Bennett set off a bit of a nerd explosion when he publicly questioned whether distributed version control systems like git or Mercurial offer enough advantages over centralized version control systems like Subversion to justify using them in its place. While I&#8217;m only experienced with Subversion and git (and [...]]]></description>
			<content:encoded><![CDATA[<p>A while back, Django core developer James Bennett set off a bit of a nerd explosion when he <a href="http://www.b-list.org/weblog/2008/jul/28/lets-talk-about-dvcs/">publicly questioned</a> whether distributed version control systems like <a href="http://git.or.cz/">git</a> or <a href="http://www.selenic.com/mercurial/wiki/">Mercurial</a> offer enough advantages over centralized version control systems like <a href="http://subversion.tigris.org/">Subversion</a> to justify using them in its place. While I&#8217;m only experienced with Subversion and git (and my thoughts will be limited to those two systems) this post should serve as my take on version control at large.</p>

<h3>My history with version control</h3>

<p>I have used Subversion for nearly all programming projects at <a href="http://www.centre.edu">my day job</a> for the past few years. I manage all of my repositories on an offsite server (my <a href="http://www.dreamhost.com">Dreamhost</a> server, actually) and it serves me well as both a version control system and a great offsite backup solution. Working on a development team of one, all of my changesets are simple (no merging necessary).</p>

<p>As for git, I first began working with it a few months back after a some friends set up a Github repository for an excellent <a href="http://ptdef.com/">javascript tower defense implementation</a>. After coming up with a few small patches, I setup my first Github account and struggled through the process of learning an entirely new set of commands to merge what amounted to a few lines of code. A few projects and many more commits later and I&#8217;m much more comfortable with the various git commands.</p>

<h3>Why distributed matters</h3>

<p>My needs are vanilla enough that Subversion should work well for anything I have going on, yet I now prefer working with git. Instead of giving you a huge narrative, I deem it proper to list off the reasons why a DVCS works best for me:</p>

<ul>
<li><strong>No need to setup a server</strong> - While the initial setup of git might be complicated, I no longer have to login to my remote server to initialize repositories. This low barrier to entry is a <em>huge</em> win for me.</li>
<li><strong>You always have the whole tree at your disposal</strong> - No need to go back to the server for diffs and the like&#8212;each team member (or at least each of your development machines) has the entire repository sitting on the file system. This is also useful in that a server can fail, temporarily or permanently, and you&#8217;ll still have a complete copy of your repository. It also matters <em>because&#8230;</em></li>
<li><strong>Local commits (aka offline commits)</strong> - You might not realize you need these, but you do. Why should it matter whether you&#8217;ve paid TMobile $10 when you want to add a changeset? Just add and commit whenever and push the stuff up when you get back to a wired location. I find myself breaking commits up into smaller and more specific changesets.</li>
<li><strong>Branching works</strong> - The last thing I would want to suggest is that branching in Subversion does not work, but it always felt like too much work for me. In git, the concept of branching is key, with every copy of the repository basically representing a branch. Having multiple branches in the repository is also a snap, and since you have the whole repository at hand, it is easy to switch between branches as well.</li>
</ul>

<p>So while I&#8217;m a bit late to this conversation, that&#8217;s my take on the matter.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/lukehatcher?a=SVvCkhhhzVA:6UUEq2kzGvE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/lukehatcher?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=SVvCkhhhzVA:6UUEq2kzGvE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/lukehatcher?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=SVvCkhhhzVA:6UUEq2kzGvE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/lukehatcher?i=SVvCkhhhzVA:6UUEq2kzGvE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/lukehatcher?a=SVvCkhhhzVA:6UUEq2kzGvE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/lukehatcher?i=SVvCkhhhzVA:6UUEq2kzGvE:F7zBnMyn0Lo" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.lukehatcher.com/2008/09/thoughts-on-version-control/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic page generated in 0.265 seconds. --><!-- Cached page generated by WP-Super-Cache on 2009-11-06 15:32:19 -->
