Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Wednesday, July 3, 2013

Using Subversion With the Kobold2D Game Engine and Xcode

I've been messing about with some basic MacOS and iOS game development lately, and at the moment I'm working with the Kobold2D game engine, which is (mostly) a refinement of cocos2d.  I've found however that in Kobold's quest to make initial setup of a project easier, it sidesteps some of the normal setup that Xcode does when you add a project or file.  Some of this, such as Project Summary info like the Application Category and Bundle Identifier is easily fixed after the fact.  Version control setup, on the other hand, is marginally more complicated than normal (at least with Subversion).

With a bit of trial and error I think I've got a working procedure to get a new Kobold project to play nicely with Subversion.  Here are my assumptions for these instructions; the more you deviate from these the less this will be relevant, and I'll leave variations as an exercise for the reader:
  1. You're running Xcode 4.6 (I'm testing with 4.6.3)
  2. You've got Kobold2D 2.1.0
  3. You already have a repository set up and waiting at version 0 (zero)
  4. We're creating a pong clone called  -- oddly enough -- "pong"
Any text here in fixed width is intended to be cut and pasted directly into your Terminal if you desire.  However, I won't be held responsible if anything goes awry... I'm trusting that you're using your head and paying attention before you run any of these commands.

Create a Kobold2D Project

Run the Kobold2d Project Starter app.  Select the appropriate template (I'm going with Physics-Box2D) and set the project name to 'pong'.  You can also set your own Workspace name here if you want.  Make sure you uncheck "Auto-Open Workspace" because we don't want to have that open quite yet.  Click on the "Create Project from Template" button.

Import the Project into Subversion

In Terminal, set ~/Kobold2D/Kobold2D-2.1.0 as your current directory
cd ~/Kobold2D/Kobold2D-2.1.0
Make a new directory structure with the usual 'trunk', 'branches', 'tags' directory structure in it
mkdir -p pong-import/{trunk,branches,tags}
 Move your new 'pong' project into the new trunk directory
mv pong pong-import/trunk/
Change directory into pong-import and import the project and directory structure into your repository
cd pong-import; svn import . https://svn.mydomain.com/pong/ -m "Initial import"
Now delete this directory structure
cd ..; rm -Rf pong-import
That's it for the Terminal.

Add The Repository to Xcode

This is the only step that's exactly as it would usually be.  Go to the Xcode Organizer (menu Window -> Organizer) and select the Repositories tab.   Click on the + in the bottom left corner of the window and select Add Repository.   Follow the prompts to name the repository, give it the URI to the repository, add your authentication credentials, etc..  For the purposes of the example, let's say the URI for your repository is "https://svn.mydomain.com/pong/".

Check Out a Working Copy

While still in the Xcode Organizer Repositories tab, click on the expander arrow to the left of your 'pong' repository.  It should show four folders:  'Root' in purple, and your 'Trunk', 'Branches' and 'Tags' directories in yellow.  Select 'Root' and then click on "Checkout" in the button bar across the bottom of the Organizer.

This will open a standard Save dialogue.  Browse your way to ~/Kobold2D/Kobold2D-2.1.0/, type 'pong' into the Save As field, and click on Checkout.

Clean Up Your Workspace

Return to your Kobold-2.1.0 folder in the Finder.  Open the "Kobold2D.xcworkspace" workspace, or your custom workspace if you created one.

You'll see your pong project listed, but it'll be in red.  That's because the files aren't where the automatically-created workspace expects to find them.   Right click on that and select Delete.

Then, right-click again and select Add Files to "Kobold2D" (or whatever the name of your workspace is).  Browse to ~/Kobold2D/Kobold2D-2.1.0/pong/trunk/pong, select 'pong.xcodeproj' and click on Add.

You're Done!

You should now have a functioning Kobold2D project with all of the usual Xcode internal Subversion support available.  You should be able to pick a random file from your 'pong' project files, right click it and go to Source Control -> Update Selected Files and cause Xcode to check if there are updates available for that file.  

Good luck, and good gaming.

Friday, September 9, 2011

The One Where I Talk About A BBS Game


20 years ago I was, along with many of my friends, spending quite a lot of time on computer Bulletin Board Systems (BBSs). Most of us had already been doing this for many years, and there were people out there who'd been doing it even longer. The BBS scene at the time was pretty sophisticated we thought.. it was becoming possible to do some really great things!

One of the things that I thought was really great was playing computer games against other people in different places. This idea was still pretty novel, as computer networking, the way we think of it today, simply wasn't possible with most home computers – what few even existed. Most BBSes only had a single phone line for people to connect, and so out of necessity virtually every BBS game was turn-based, usually allowing a single turn per day. So, every day, I had time set aside to dial in, see what had transpired since the previous day, and take my turns.

One of my favourite games, and one of the few that I remember in any detail, was Esterian Conquest. It was a multi-player take on some of the early empire-building 4X games, set in a small two-dimensional galaxy, where each player had to build a fleet of ships, and go forth and conquer by force or diplomacy. Don't let the simple idea fool you though.. EC was a beast of a game, with simple rules that allowed for a plethora of complex results. Early on, my nightly turn would take but a few minutes to think about and execute, but later in the game I could literally spend hours pouring over reports from my fleets, hand-drawing maps on graph paper based on the information they contained, and then planning out and tediously punching in new orders for all of my fleets and planets.

About four years ago, while cleaning out boxes that had been in storage for ages, I came across a folder containing papers from the last game of EC I ever played. There were printouts of reports covered in pencil notes about possible actions to take, maps with quick calculations of how long it would take my fleets to reach some hot-spot in the game galaxy, and sheet after sheet of new orders.
Fleet 66 join fleet 47
Fleet 32 reduce speed to 5
Fleet 73 move to star at (12,41)
Everything about the game came back, and I started to wonder if it could somehow be resurrected. I had heard years before that the source code to EC had been lost in an all-too-unfortunate hard drive crash, but digging around in more boxes I did manage to find a floppy disk with the copy I had for the BBS I'd briefly run myself. Sadly, it proved to be more work than I had time for to get a computer running that could both run modern networking and connect that to an old DOS game. So I decided that instead, I'd just write my own.

I spent the next few months mapping out the game I'd like to create.. what I thought at the time was probably the first ever Turn-based Strategy MMO. I started writing documentation: how would I like the game to work? After chatting about the idea with a friend of mine, he gave me a photo-copy of an old table-top game he'd played called Stonova for ideas (it was based on Chris Wilkes' "Nova"). I worked out plans; I taught myself the math I'd need for three dimensional navigation (I wanted my game to take place in a realistic three-dimensional galaxy). But, when I really got down to it the game I had in mind would have required programming skills, particularly in the area of graphics, that I just didn't have the time to acquire. The idea was grand, but it was beyond me at the time. So I put the idea away for a while.

A couple of days ago, for no particular reason I can recall, I started thinking about this again. My original idea had been too grand for my meagre programming skills. But what if I scaled it down? In the last few years it's been proven that web-based games can work, and do attract players. So what if I ditched the desktop game idea, and went with the much easier to program web-based game? Games like Travian certainly seem to attract players, and as the basic concepts go it isn't all that different from what I had in mind.

My game will be simpler than EC in places, and more involved in others.

In EC it was possible to send your ships to any point in the galaxy, and along the way they would send back reports if they came within sensor range of any other passing ship. You could interrupt their orders mid-trip and have them pursue whom they spotted, or run away, or slow down and quietly follow at the edge of sensor range. I think I will simplify that a lot, and very likely only allow travel to other stars, not the spaces between them. Fleets will report on other fleets they find in their current star system, but I think I will drop the requirement to calculate intersecting flight paths, and handle changes in destination mid-flight.

EC had a small number of fixed ship types that you could build, and assemble into fleets. I think I'd like to have a bit more range in this area, so I'm going to design a technology research system that will allow players to concentrate on improving certain aspects of their ships. Are you a fan of big weapons? What happens when you go up against your opponent who has put all their research into heavily armoured ships? Or, maybe you just want to build really fast ships that can run away easily when threatened.

EC had no system of trade that I can recall. My game will allow players to trade resources, and might even have some sort of in-game cash economy. Perhaps you won't build warships at all, but will instead build big, fast transport ships and survive by supplying everyone with what they need... and paying tribute for "protection" where necessary.

So, I've started working on the idea again. I have no idea what will come of it, or whether I'll even finish. I haven't even got a name for it yet.. but I'm curious to see what I can come up with.

Thursday, November 11, 2010

Escaping Mac Mail RSS

Don't get me wrong, the Mac Mail RSS reader is pretty good. If you've just got the one computer, and don't have any desire to read your RSS feeds when you're away from home, then it's an excellent choice. It's shameful, however, that MobileMe – Apple's service for syncing your data between Mac computers – doesn't even try to sync your RSS feeds between Mail clients.

This lack of ability to keep the RSS feeds in my Mail client on my desktop and my laptop in sync (let alone on my iPad or iPhone) has led me to start looking for a replacement RSS reader. As disappointing as the lack of sync is, I quickly discovered the even more shocking reality that there's not even a way to export my RSS feeds from Mail. Go, look ... you won't find anything... I'll wait.

As it happens, there's this standard, which is useful for moving RSS feed information around, called OPML (Outline Processor Markup Language), which is a subset of XML (eXtensible Markup Language). I'm not a big fan of XML but there are times when it's useful, and in this case several major RSS readers have implemented an OPML import/export so that you can move your RSS feeds around. It would be really handy if Apple implemented this as well.

Unfortunately, Apple's oversights get worse. Not only can you not sync RSS feeds between computers, or export your RSS feeds, you can't even view the URL of your RSS feeds within Mail so that you could manually copy them to another device or program. Go Apple!

This only leaves one option: manually digging through the files that Mail saves out to keep track of your feeds. This is a task that is beyond the average home computer user, which effectively means that most Mac users who start using Mac Mail as their RSS reader are stuck.

Fortunately, I'm not the average home computer user, and I know where to find these files that Apple writes, and I know how to read them .. so I could go in and cut and paste all those URLs into another reader. But I'm too lazy for that, so I wrote a program to do it for me. This wasn't quite as easy as I expected, since reading in the XML plist files turned out to be a bit of a trick. As much as I don't like XML, trying to describe how I hate XML plist (the format Mail uses for these files) would completely derail this post – Apple really screwed the pooch on that one.

Eventually I gave up on the program being super-portable, and just used someone else's library to read in the plist files. I had been hoping that I could post a script here that anyone could save on their Mac and run to generate an OPML file, but the plist debacle meant that other stuff would need to be installed. Oh well.

In the end I got my OPML file, and I've imported it into Google Reader. Several of the iPad RSS readers will import their feeds from Google, which works well enough.

I'm posting my script below, free to anyone for personal use. In order to make it work you'll need to first install two libraries on your system.

Making it Go

In "Terminal" (which you can find in Applications -> Utilities), type the following two commands:
gem install builder
gem install plist

Once you've installed builder and plist, click on this link. It will download an archive file that contains the script.  When that's done, in your Downloads window double-click on the "MacRSStoOPML.tar.gz" entry; that will decompress the archive and show you a new Finder window with the archive you downloaded and the script that was in it.  Double-click on "MacRSStoOPML" (it'll have a grey box-like icon) to run it.  And you're done!  You should now have a file called "opml.xml" on your Desktop, which lists all of the RSS feeds you were reading in Mail.

Happy reading!

Monday, February 15, 2010

Losing My Memories

Back at the beginning of January a horrible thing happened. It was something that a lot of people fear in this day and age, but which few really believe will happen to them. It happened to me though, and I had to find a way to recover from it. Yes, I lost all of my digital photographs.

The the complete details of how it happened are not terribly germane to the post but the short story is that, while moving to a new computer, for that brief period where a lot of this data existed only on my backup disk, a Windows installer decided it would like to reformat that backup disk for me.

Recovering data from a reformatted drive can be tricky. Without the original filesystem information you need some special tools to even find old files, let alone reassemble them into something recognizable. But, with a bit of work I managed to get all of my images back, and this is the story of how I did that.

The whole recovery story started off with a stroke of luck. I happened to mention the demise of all of my photographs to a friend of mine, and he just happened to know of an incredibly useful tool for recovering my data. He pointed me toward TestDisk by Christophe Grenier. TestDisk is rather badly named I think, because testing is the least of what it can do. One of the key features that made my life far, far easier is its ability to do file type recognition when recovering files.

When the filesystem information from a disk is lost, even if you're able to recover files, you can't always recover the file names; often that information is lost forever. That means that recovered files will typically wind up with some sort of coded file name (usually just a number generated by the recovery program). If you're recovering a very large disk, you can wind up with literally millions of files with completely nondescript file names. It would be completely impractical to try and sort through an entire disk worth of files that way trying to find the pictures.

Fortunately, TestDisk's ability to recognize file types based on the data in the file, rather than the file name, meant that I could tell it to only recover the JPEG images from the disk. This way I wound up with a set of files where I definitely knew the type of each and every file. And it just so happens that all of the digital cameras I've owned work in JPEG.

I knew I was still going to have a problem though. Because this was my backup disk, which contained not only my Aperture database, but also all of my Time Machine data (a MacOS backup tool), what would be recovered in searching for all JPEG images would include all of the pictures in my Aperture database, but also my entire web browser cache, and any other little jpeg images stored on my disk as part of various applications, etc. When the recovery ran, I ended up with a bunch of folders with a little under 35,000 pictures in them. Now what?

Well, the first thing I did was to try to eliminate any duplicate images. Even though that would be a fairly simple script to write, I always google for these sorts of tools before I try to write them myself. Usually, someone else has already written and posted the thing I need, and often it's better than I would have written on the first try. This was just such a case, and I found a great little perl script that would search for and remove all the duplicate images.

That got me down to a little over 20,000 images. Still a lot, but far fewer than I had before.

The next step was to try and separate out the original files downloaded from my cameras from all of the other random images. For that, I did write my own script. I scanned through all of the images to extract the original image date/time from the Exif data, reorganizing the images into directories by the day the picture was taken. If an image had no original date in its Exif data, or no Exif data at all, then I assumed the file was not a photograph (or not one of my photographs) and put it off in a separate directory to be sorted through manually later.

Here's the script I used:

#!/usr/bin/perl

use strict;
use diagnostics;
use warnings;

use Date::Parse;
use File::Find;
use Image::ExifTool qw(:Public);
use POSIX qw(strftime);

my( $source_d      ) = '/Users/matt/Desktop/Recovery/jpg/';
my( $base_dest_d   ) = '/Users/matt/Desktop/Recovery/jpg-sorted/';

my( $dir_date_format  ) = '%F';
my( $file_date_format ) = '%Y%m%d-%H%M%S';

my( $nodate_i, $nodate_d ) = (0, 00);

if( ! -d $base_dest_d )           { mkdir $base_dest_d; }
if( ! -d $base_dest_d.'NoDate/' ) { mkdir $base_dest_d.'NoDate/'; }

sub wanted {
    my( $source_file ) = $File::Find::name;
    my( $source_date, $dest_d, $target_f );
    
    unless( -f $source_file ) { return; }
    unless( $source_file =~ /\.jpg$/ ) { return; }
    
    
    my( $info ) = ImageInfo($source_file);
    if( $info->{DateTimeOriginal} ) {
        $source_date = str2time($info->{DateTimeOriginal});

        $dest_d = $base_dest_d .
            strftime($dir_date_format, localtime($source_date));

        $target_f = strftime($file_date_format, localtime($source_date));

        # in addition to naming the file by date, give the image an index
        # number that advances if there is more than one image with the same 
        # date+time
        my( $target_i ) = 0;
        while( length($target_i)<2 ) { $target_i = '0'.$target_i; }
        while( -f $dest_d.'/'.$target_f.'-'.$target_i ) {
            $target_i++;
            while( length($target_i)<2 ) { $target_i = '0'.$target_i; }
        }

        $target_f = $target_f.'-'.$target_i;

    } else {
        # images with no date/time get put into subdirs, 100 images per
        # directory to keep the directory from getting too large
        $nodate_i++;
        if( $nodate_i > 100 ) { 
            $nodate_i = 1;
            $nodate_d++;
        }
        while( length($nodate_d)<3 ) { $nodate_d = '0'.$nodate_d; }
        $dest_d = $base_dest_d . 'NoDate/' . $nodate_d;

        $target_f = $_;

    }

    if( ! -d $dest_d ) {
        mkdir $dest_d or die "failed to create dest dir $dest_d: $!";
    }

    my( $final_file ) = sprintf( "%s/%s", $dest_d, $target_f );
    printf "%s: %s: %s\n",
        $_, $info->{DateTimeOriginal} || 'NoDate', $final_file;

    link( $_, $final_file ) or die "failed to link files $_:$final_file: $!";
}

find(\&wanted, $source_d );

This has left me with about 7,300 images sorted out into directories by the date the picture was taken, and about 13,600 in directories of images with no known shoot date.  This is far more manageable!  I'll probably still wind up doing a bunch of manual sorting of the images that are left, but now the task is much more approachable than it was in the beginning.   It's also possible I could find some other useful piece of Exif data to sort them by.