|
2010 archived here
2009 archived here
2008 archived here
2007 archived here
2006 archived here
The first and second weeks of October were pretty rough on nerds like me. On October 5th we lost Steve Jobs, and just seven days later we lost Dennis Ritchie. They were two very different guys, are responsible for very different aspects of computing, and their levels of fame couldn't be farther apart. Their only similarity was the significance of their contributions to the world, and that alone makes them both heroes in my book.
I learned BASIC on my TI-99 4/A back in grade school, but my first crack at programming something significant was using C, which Dennis Ritchie invented. As a video game programmer there is no language that lets me get closer to the metal while not having to memorize chip instructions. While C++ and Objective-C add the convenience of object orientation, the simplicity and elegance of plain old C has always appealed to me. As the famous quote from K&R goes, C is not a big language, and it is not served by a big book. I think when people say they like one language or another they really mean they like the libraries and pre-built UI elements that come with it. When people say they like C, I think they actually mean the language.
As if inventing a language weren't enough, Mr. Ritchie then went on to co-develop UNIX, the operating system that serves as the foundation for every computer on the planet that isn't running Windows. Mac OSX has a modified UNIX kernel, Linux is a modified UNIX kernel, to say nothing of all the other flavors of actual UNIX in the world. They all owe a debt of gratitude to Mr. Ritchie, who laid the groundwork.
The first computer I ever used was an Apple ][. Back in second grade I had seen a teletype, but I couldn't get my head around it. "So it's a big, loud typewriter?" I asked my technologically-advanced third grade friend. "No, no, see how the phone is plugged in over here?" and on it went. I eventually grasped the typing-over-a-phoneline concept, but seeing the green pixels of the Apple really brought it all home for me.
Steve Wozniak invented the circuits and programmed the operating system for the Apple ][, but even he admits it wouldn't have gone anywhere without Steve Jobs' sense of what consumers wanted and his will to get this machine to them. The guts of that computer are Wozniak's, but the polish (including the sleek plastic case) and ability to turn it into a lasting business was all Jobs.
Some would say, "Well, Wozniak did the hard part of inventing the computer, so why does everybody give Jobs so much credit?" and they'd be a little right, but only a little. Having just finished the Jobs biography and having read To Infinity And Beyond several years earlier, I think Jobs gets too little credit because he wasn't the creative force behind something, when several of the endeavors would have failed without his involvement.
Most people think the history of Pixar starts with the making of the movie Toy Story, but it starts about a decade earlier. The one-time Lucasfilm division was first and foremost a hardware company, producing software to run on that hardware, and Buzz Lightyear was nowhere in sight. Jobs not only purchased the company and provided the initial seed financing, but poured more of his own money into it as it neared failure. He did this not because it was practical, but because he believed in what they were doing, and had faith in the abilities of the brilliant artists and technicians they had. Pixar is certainly the master of the industry these days, but when John Lasseter says, "No Steve Jobs, no Pixar" he's not giving Jobs undue credit. Like Wozniak at Apple, Lasseter is the talent at Pixar, but talent alone wouldn't have gotten it done.
Certainly there will be others who will come along and invent the way Ritchie did, or market and innovate the way Jobs did. I can only hope they do it with the same passion and ability that made Jobs and Ritchie the giants they are, and that they acknowledge the shoulders on which they stand.
Happy coding,
Jon
I'm writing a cycling app right now for the iPhone, and one of its key features is a map that shows your progress along your chosen ride route. Thankfully most of the work has already been done for me in the wonderful MKMapView. Provided by Google, this component magically does everything you expect it to do (zoom, shift, update) with nary a line of code. With iOS 4.0 Apple has provided the notion of overlay views that can show images on top of the map that zoom / shift / update in sync with the underlying map. Imagine my delight.
The overlays are similar to annotations programmatically in that they have a data representation that is separate from the view that renders them. Since I was using NSManagedObjects for my locations as part of my Core Data queries, I decided to create an object that would store the relevant coordinate data and would conform to the <MKOverlay> protocol. In the hierarchy image you can see that I've created the PathOverlay class to serve this purpose.
For the map view controller's viewDidLoad routine, I create both the overlay data object and overlay view object like this:
- (void)viewDidLoad {
[super viewDidLoad];
pathOverlay = [[PathOverlay alloc] init];
pathView = [[MKOverlayPathView alloc] initWithOverlay:pathOverlay];
|
Unlike the default behavior of MKOverlayView's drawMapRect: zoomScale:inContext:, which does nothing, the drawMapRect routine's default behavior for the MKOverlayPathView is to draw a specified path using the view's stroke and fill colors and line widths. I also set these in my viewDidLoad:
[pathView setStrokeColor:[UIColor redColor]];
[pathView setLineWidth:3.0f]; |
Finally, I add the overlay itself (not its view) to the map view:
| [mapView addOverlay:pathOverlay]; |
When I was setting this up one of the first problems I had was timing, because the order of the method calls is a little funky. As an <MKMapViewDelegate> my view controller implements mapView:viewForOverlay, whose job it is to return the view object responsible for rendering the passed overlay object. The tricky part is that, as soon as you call [mapView addOverlay:pathOverlay], the system immediately calls mapView:ViewForOverlay. My problem was that I had some more path initialization code after my addOverlay call, so ViewForOverlay was returning a view that had a nil path, which doesn't draw anything. Be aware of the timing of this and you should be fine.
Next comes creating the path, which in the case of the MKOverlayPathView can be a CGPathRef or (more likely) CGMutablePathRef. For this app I'm storing locations in a Core Data repository, so I query that repository for a list of location NSManagedObjects, extract latitude and longitude, and convert that to an MKMapPoint. I also compute a view offset for the map points, which I will explain below:
- (void)updatePath
{
firstPathLocation = YES; //flag for things done only on the first location
for (locationLoop = 0; locationLoop < [queryResults count]; locationLoop++)
{
//get the current location record from Core Data
currentLocation = (NSManagedObject*)[queryResults objectAtIndex:locationLoop];
currentCoord.latitude = [[currentLocation valueForKey:@"latitude"] doubleValue];
currentCoord.longitude = [[currentLocation valueForKey:@"longitude"] doubleValue];
//convert the coordinate to an MKMapPoint so it can be used in the map view
currentMapPoint = MKMapPointForCoordinate(currentCoord);
if (firstPathLocation == YES)
{
viewOffsetX = locationNowMapPoint.x;
viewOffsetY = locationNowMapPoint.y;
//start a new line
CGPathMoveToPoint([pathOverlay path], NULL, currentMapPoint.x - viewOffsetX, currentMapPoint.y - viewOffsetY);
//set this overlay's coordinates to the first point's coordinates
[pathOverlay setCoordinate:currentCoord];
}
else //if this is not the first path location...
{
CGPathAddLineToPoint([pathOverlay path], NULL, currentMapPoint.x - viewOffsetX, currentMapPoint.y - viewOffsetY);
}
... (the rest of the for loop) |
At this point I've got a path (a variable of the PathOverlay class) to which I am adding points using the CGPathMoveToPoint and CGPathAddToPoint methods. When I'm done with the above for loop, I assign the completed path to the path property of the overlay view using setPath:. The default drawing behavior of the MKOverlayPathView is to draw the path assigned to that property.
It's also necessary to compute the bounding rectangle of the overlay, and though I've omitted the code, it's not that bad. You simply find the lowest and highest x and y values of each of the map points (converted from latitude and longitude using MKMapPointForCoordinate), and store those in your overlay object as the "boundingMapRect" property. Objects that conform to the <MKOverlay> must have both a coordinate and an boundingMapRect, which I've now computed.
What's with the view offsets? You might assume that, since you've provided the bounding rectangle, the MKOverlayPathView would compute the pixels of your path as an offset from your boundary values, but it doesn't. The reason I compute a view offset x,y for locationNowMapPoint (a variable in which I stored the device's current location) and subtract it is so that the CGPath points I'm plotting treat the the user's location point as (0,0), which is the center of the view, and all other points as offsets of that. When I first saw my Minnesota path data being plotted in the ocean off the coast of Brazil I was confused. When I computed these offsets it fixed the problem. Not really a "problem" I guess, but something I assumed was happening that was not.
While this explanation is by no means complete, and I'm not even sure I'm doing everything optimally, I hope this helps others who are struggling like I was. I spent several days with nothing showing up at all, then half a day with a path showing up on the wrong hemisphere, so I thought once I figured it out I'd try to spare others the pain of my mistakes. Let me know if you see any errors in either my code or descriptions of events so I can improve this entry.
Happy coding,
Jon
The movie King of Kong tells the story of two of the best Donkey Kong players in the world. With these two it was about high score, but the movie also talks about getting to the "kill screen", which on level 22 is where the game unceremoniously ends. Nowhere in the movie are any of the developers shown playing the game, and as I was finishing up Psychopomp I was wondering how good any of them were at it.
I spent the better part of four days gauging and tweaking the difficulty of Psychopomp's 30 levels. It was a tough balancing act, because all the beta testers' comments suggested that the first few levels were too hard. At the same time, I wanted to give players who got really good some very challenging levels later on in the game.
Ultimately what I was shooting for was what you get with Pac Man or Robotron. Both of these games serve up a couple of softball levels to make sure you know how to play the game. The first level of Pac Man has much slower ghosts, you move slower, and the ghosts stay blue for a comforting amount of time. The first level of Robotron features nothing but humanoids and slow-moving simpleton robots that die with one shot. Lulling you into a sense of security is what those boards are for.
By the fifth level of both of those games you're having your ass handed to you unless you've developed some talent. I can't even get to the tenth level of Pac Man, and I hit a wall in Robotron in the early twenties. I've never "finished" either of these games, so I know there are several levels that were developed for players who are skilled in a way that I will never be. Despite my years (decades?) of playing Nintendo, I have accepted that I am not a video game prodigy. This doesn't mean there won't be people who are video game prodigies trying out Psychopomp, and I want them to enjoy the game too.
I can get to level 22. There are 30 levels, but starting with the standard 3 boats I can only get to 22. In my attempt to make sure my difficulty settings were even physically possible I did play every single level, but I had to cheat in the debugger to even get there. Things like:
level = 25;
lives = 20;
Compile, run, cheat. Sure, I've seen level 30 and the "kill screen" banner that gives you your victory message, but only because I needed to make sure it worked. Level 30 and the four levels preceding it are damn near impossible, and three before that are no picnic, but I bet there are players better than me out there who could finish them.
Me? I'm content with 22. The escalating difficulty leading up to that level is pretty fun (if I do say so myself), and I enjoy the challenge. Plus, my desire to get to level 23 keeps me playing. Just one more game...
Happy coding,
Jon
I've never been a fan of publicly funded stadiums. I enjoy watching football and baseball as much as the next guy, but paying extra taxes to reduce their operating expenses is offensive to the capitalist in me. Those who know me are rolling their eyes right now, because they've heard my ranting over and over. They heard it when the Twins were trying to get funding for Target Field, and they've heard it throughout the Vikings' attempts at getting similar funding.
Rather than continue to bother my friends with my rants, I thought I'd bother my representatives. Now technically I think any city or county tax would be decided by other government officials, so this letter to my representatives is more of an insurance letter than anything else. They are critical because it was the state legislature that overrode our right to vote on whether a tax would be levied to pay for the Twins stadium, and I want to make sure that doesn't happen again.
So, without further ado, here is the text of the letter I will be mailing to senator Latz and representative Winkler:
I'm writing today because I'm concerned about the anti-competitive nature of the funding that is being proposed for a new Vikings stadium. While I understand how great it is to have entertainment options like the Vikings in town, giving them taxpayer funds to solve their revenue problems is not a good strategy for strengthening commerce within the metro area.
Since the Vikings are the only professional football team in town, the anti-competitive charge might sound absurd. However, fans use discretionary income to buy tickets to those games (and to visit bars and restaurants before and afterwards), so their competition is actually every business in the state at which people might spend that same discretionary income. Movie theaters, shopping malls, high school and college sporting events, bars and restaurants that aren't near the stadiums, and any other businesses you can think of at which people spend spare cash are competing with the Minnesota Vikings for those dollars.
In a normal business scenario this wouldn't be a problem. The bars, restaurants, and entertainment venues across the area would all have to produce a good product or service, spend money on advertising, and would be rewarded with profits if their efforts were successful. If they weren't successful, they would be forced to alter their business model, perhaps lowering costs by cutting salaries or leasing a smaller space, or increasing revenues by offering a more competitive price for the product they're offering. These are problems that businesses large and small solve every day, and they do it without any help from taxpayers.
Professional sports teams in the area distort the business climate by demanding public funding for the buildings in which they do business. They do it first by claiming to be state assets. The Vikings are a for-profit entertainment provider owned by the Wilf family. They are no more a state asset than the Dallas Stars or Los Angeles Lakers (both former Minnesota teams) were. To hear the Vikings claim to be in the same category as actual state assets like the Boundary Waters or the University of Minnesota is a bit much. I've never once heard the BWCA threaten to move to California if people stopped canoeing there.
They do it next by claiming that they create economic activity, but I'll reiterate that they shift it rather than create it. The activity creation theory assumes that Vikings fans have separate money sitting around that they would only spend on Vikings-related activities, but Vikings money comes from the same pile that any other leisure expense comes from: spare cash. There's a finite amount of spare cash out there, and if people are spending more of it on the Vikings, they're spending less of it on something else. Even if the creation theory does have some merit, movie theaters create the same type of activity (dinner or drinks before the movie), and on a much more consistent basis (every day and night of the year instead of the eight home games the Vikings play), but we don't use taxpayer funds to build more of them.
Finally, they do it by claiming that they create jobs and increase tax revenue for the state, as if they alone are capable of this. Every business in Minnesota can make this claim, and yet none of them is asking for the same subsidy. Car dealerships provide jobs and several types of tax revenue to the state, but if they came to the capitol asking for taxpayer funds to build showrooms I assume they would be laughed out of the room.
I hope you'll agree that while the Minnesota Vikings are certainly entertaining, and are a nice addition to the list of fun things to do in the Twin Cities, they are a business. As such, they should have to compete on the same level playing field on which every other Minnesota business already does. A shortfall in the operating budget of a private business is not a municipal problem, and should not be solved with taxpayer funds. I hope your vote on any upcoming financing legislation will deny public funding for a stadium or, if not deny, at least leave it open to a voter referendum. I was extremely disappointed that Minnesotans did not get our constitutionally-provided vote on funding for the Twins stadium (through a legislative loophole as I understand it), and I hope we will not be denied that right again.
Sincerely,
Jon Hellebuyck |
I'm always the last to know. When I first started telling people I was starting my own video game company, the universal response was, "Oh, will you be writing games for the iPhone?" I would explain that no, I was writing for the PC, to which the response was, "But you'll port the games to the iPhone, right?" Message received.
In a fairly dramatic and somewhat expensive move, Mode 13 game development will now include the iPhone. Dramatic because I hadn't planned on adding that platform this early in the schedule. Expensive because I had to buy new equipment and books to make it happen.
Why? I've discovered that the games I like to play are either turn-based strategy / resource management (like Fate Meridian), first-person shooters, or arcade-style action games. As a one-man team I will never produce a first-person shooter, I've written Fate Meridian, and I am four months into developing an arcade-style action game for the PC. Then I had an epiphany. An epiphany all of my friends and colleagues had 18 months ago.
One-man shops are ideal for mobile game development. Between the miniscule screens and limited texture RAM, the art requirements are far different from a PC. With Fate Meridian I could render huge 32-bit textures in Maya and not worry about whether or not I'd have problems with them. With the iPhone I'm studying the PNG16 image format and looking up how to get Maya to render an alpha channel using 16 bits.
The play experience is different from a PC as well, and this is where the advantage goes to the small shops. When I sit down at my computer to play a PC game I plan to be there a while, so it had better have some depth. When I'm waiting in line at the airport I just need something quick and fun to kill time until it's my turn, so I want a game that I can pick up, learn quickly, then put down again.
This shift to iPhones wasn't an easy decision for me. In order to move in this new direction I stopped development on a PC game that's only three months from being finished. It features numerous engine improvements, including better animations, interesting audio effects, and colored lighting (both diffuse and specular), and it's hard to leave them sitting in the compiler instead of finishing the game so others can enjoy them.
What's harder, although exciting, is shifting all the gears that I need to shift to work on iPhones and iPads. I haven't used OpenGL since college, and though it shares plenty of concepts with DirectX, getting used to it has taken time. I'm also still struggling with the shift from C++ to Objective-C. Thankfully they're both supersets of C, so I get some comfort and portability from that. Still, I figure learning a new programming language is like exercise for your brain, and my brain has been a C++ couch potato for 18 months now.
If there is a silver lining in all of this, it's that I get to explore a whole new game development business model. Gone are the year-plus development schedules for a single game. Gone also are the art asset lists that would choke a horse, since you only get 40MB on the app store per game. On top of all that I got a new Mac out of it and will be getting a new iPod Touch shortly. If ever there was an excuse to spend money on pretty things, this is it.
Happy coding,
Jon |