## Wednesday, December 22, 2010

### Starfire!

I just played Paul Turbett's first PC game, via DOSBox. Pure Awesome. Paul is now Black Lab Games, and on the side we work together on other secret projects.

When I was much younger, I remember applying for a job at Silver Lightning Software (Paul's company at the time). Hah, I wonder if he still has my resume, or if it went straight into the bin! Funny how, almost two decades later, we end up working together.

## Tuesday, December 21, 2010

### More Ships.

These ships are all rendered within Unity3D using a toon style shader. No textures are used, just flat colours.

## Monday, December 20, 2010

### Awesome Cloud Game Library...

Built primarily for cloud games, PySoy offers an intuitive API for managing object behavior in 3D space.

<chortle> I'm pretty sure this sentence (from the main PySoy page) is a joke. Of course it is. Isn't it?

## Friday, December 17, 2010

### Unity3D Hex Grid.

How to snap world points to the closest hexagonal grid point, where a hexagonal grid point is the center of the hexagon. The Init(size) parameter is the length of one edge of the hexagon.

`using UnityEngine;using System.Collections;public class HexGridSnap : MonoBehaviour {   static float size,h,r,b,a;  static void Init (float size) {  HexGridSnap.size = size;  h = Mathf.Sin(30*Mathf.Deg2Rad) * size;  r = Mathf.Cos(30*Mathf.Deg2Rad) * size;  b = size + 2 * h;  a = 2 * r; }  static Vector3 Snap(Vector3 p) {  var u = p.x;  var v = p.z;  var x = u - u % a + r;  var y = v - v % b + ((x - r) / a % 1) * b / 2;  return new Vector3(x, p.y, y); }}`

### Unity3D - Configurable Vehicle Prefab.

Check it out here: The Vehicle Prefab, you will need the Unity3D web player installed as a browser plugin.

You can dynamically change transmission type, differential type, suspension parameters, and vehicle masses. Lot's of fun just in itself! :-)

## Tuesday, December 14, 2010

### Fraud.

I listed a car for sale on gumtree.com.au last night.

I've had 4 enquiries via SMS. 5 minutes of research later, I find they are all frauds. Hooray for google and it's knowledge of everything. It is a shame that one has to be a skeptic by default.

## Tuesday, December 07, 2010

### Unity3D WheelCollider and motorTorque.

So, you've created a car prefab using WheelCollider components, and now you can apply a motorTorque to make the whole thing move along.

But how do you calculate vehicles for the motorTorque which make the vehicle reflect reality?

Here are my current ideas on the best way to do this.

1. Create a "torque curve" for your engine. It should run from 0 - 7000 (which reflects your engine RPM) and the height should peak at the maximum power output (in Newton Metres) of the engine. . The below image shows a torque curve which peaks at around 450 newton metres and then sharply drops off near 6000 rpm, just like a real engine. Use an AnimationCurve for this.

2. Set up your masses. The car should weigh between 1000-3000 kg. Set this in the mass property of your rigidbody component. It is also very important to set the mass of your wheels (WheelCollider.mass) to something reasonable. Most car wheels weigh between 15-30 kilograms.

3. Create another AnimationCurve variable, which we will use for gear ratios. Gear 0 should be neutral, and gear -1 should be negative to enable a reverse gear. A typical(?) set of gear ratios are below. Add another float variable which is the "final drive ratio" and set it somewhere between 3 and 4.

4. Every frame, you need to calculate the RPM of the motor. To do this use this formula:
`motorRPM = minRPM + (wheelRPM * finalDriveRatio * gearRatios.Evaluate(gearIndex));`

minRPM is usually set to 700-1000, depending on the idle RPM of the engine. You can get wheelRPM from your WheelCollider components.

5. Finally, calculate the motorTorque.
`totalMotorTorque = torqueCurve.Evaluate(motorRPM) * gearRatios.Evaluate(gearIndex) * finalDriveRatio * accel;`

If you have four drive wheels, set each wheel's motorTorque to totalMotorTorque / 4. If you have only two drive wheels (front or rear wheel drive), set each wheels motorTorque to totalMotorTorque / 2. accel is a float variable which specifies how far the accelerator cable is depressed, and should be between 0 and 1.

6. Fill in the gaps. You need to add a mechanism to change the gearIndex value (which specifies which gear the car is in) and a mechanism to modify the accel value.

7. Tweak the curves. Just like a real car, minor adjustments to weight, torque curves or gear ratios can have a dramatic impact on the car's performance. Don't be surprised if you get crazy behavior from seemingly minor modifications!

### Strange Goings-On at Different Methods...

Master Chief rides to the rescue, solving all OSX Server problems in his path...

## Tuesday, November 30, 2010

### Personal Challenge: Game in a Week

In my spare time this week, instead of building spaceships, playing games or even drinking beer... I will make a game for the Apple App Store using Unity3D.

Next Wednesday I shall announce my failure, or success.

Who will join me? :-)

RAGE!: Unity3D Bug? kills all progress...

Verdict:

Failure. The above bug sucked my will to code for at least two days, though Unity does appear to be behaving now.

What have I got to show for the weeks effort?

1. I know that terrain meshes run acceptably fast on the iPad in the 1500-2000 vertex range. Meshlab does an excellent job of reducing Unity Terrain meshes to usable vertex counts.

2. A reasonable approximation of a car engine, transmission and differential.

3. An objective / waypoint system for running a race around a terrain.

I will revisit this again later. Sad Face.

## Monday, November 29, 2010

### Server Retirement.

`simon@metaplay:~\$ uptime 12:49:18 up 923 days, 4 min,  1 user,  load average: 0.00, 0.00, 0.00`

## Friday, November 19, 2010

### Carrier #2

Inspired by something I saw in a wing commander poster today. Using a different toon shader altogether. I might stick with this one, it has cleaner edges.

## Thursday, November 18, 2010

### Exploding Spacecraft...

What is the point of a nice spaceship model... If you can't blow it up? Not too much I hear you say. Well, now I can blow arbitrary spaceship models apart! w00T! :-)

### A Fleet is born...

I'm still working on the shaders. I added a toon lighting model which has definitely improved the lighting, but I'm not sure why my edges are so jaggy! Hmmm.

## Monday, November 15, 2010

### Spacecraft Development.

My spaceship is progressing. I've also tweaked the renderer to make it more cartoon like in appearance. What do you think?

## Wednesday, November 10, 2010

### Non Photo-realistic Rendering.

I'm experimenting with flat shading and full screen pixel shaders. What do you think? Would you buy this game? :-)

## Monday, November 08, 2010

### Font Rendering Problems in Unity3D

Does your text look like this in Unity3D 3.0?

To fix, simply change the Character option in the import settings for the font to "dynamic". Problem Solved.

### OSX Web/HTTP Sniffer Tool.

HTTP Scoop from Tuffcode. Great tool, invaluable if you have to work with HTTP.

## Tuesday, November 02, 2010

### Automagic GUI Scaling in Unity3D

Step 1. Tell you team that everything must fit within 1920x1080 or 1024x768 or whatever resolution you like!

Step 2. Surround all OnGUI method body code with methods BeginGUI and EndGUI from the below class.

Step 3. Scaling across all resolutions... problem solved!

`using UnityEngine;using System.Collections;using System.Collections.Generic;public class GUISizer {    static float  WIDTH = 1024;    static float HEIGHT = 768;    static List<Matrix4x4> stack = new List<Matrix4x4> ();    static public void BeginGUI() {        stack.Add (GUI.matrix);        Matrix4x4 m = new Matrix4x4 ();        var w = (float)Screen.width;        var h = (float)Screen.height;        var aspect = w / h;        var scale = 1f;        var offset = Vector3.zero;        if(aspect < (WIDTH/HEIGHT)) { //screen is taller            scale = (Screen.width/WIDTH);            offset.y += (Screen.height-(HEIGHT*scale))*0.5f;        } else { // screen is wider            scale = (Screen.height/HEIGHT);            offset.x += (Screen.width-(WIDTH*scale))*0.5f;        }        m.SetTRS(offset,Quaternion.identity,Vector3.one*scale);        GUI.matrix *= m;    }    static public void EndGUI() {        GUI.matrix = stack[stack.Count - 1];        stack.RemoveAt (stack.Count - 1);    }    }`

## Saturday, October 30, 2010

### A Unity Shader LOD Script.

`using UnityEngine;using System.Collections;public class LOD : MonoBehaviour{    //distances where LOD transitions occur.    public float[] lodLevels = new float[] { 1000f, 800f, 600f, 400f, 200f, 100f, 50f, 10f };    //These are the builtin LOD values for Unity shaders.    int[] shaderLOD = new int[] { 600, 500, 400, 300, 250, 200, 150, 100 };    void Start ()    {        StartCoroutine ("UpdateLOD");    }    void SetLOD (int LOD)    {        foreach (var i in renderer.sharedMaterials) {            i.shader.maximumLOD = shaderLOD[LOD];        }    }    IEnumerator UpdateLOD ()    {        var period = Random.value;        var cam = Camera.main.transform;        float[] levels = new float[lodLevels.Length];        int i = 0;        foreach (var level in lodLevels) {            levels[i++] = level * level;        }        while (true) {            var distance = (transform.position - cam.position).sqrMagnitude;            var LOD = levels.Length - 1;            foreach (var level in levels) {                if (distance > level) {                    SetLOD (LOD);                    break;                }                LOD--;            }            // make LOD checking non deterministic. avoids stampeding LOD calls?            yield return new WaitForSeconds (period);        }    }    }`

### Dubious Value of the Social Network.

I've been slowly extricating myself from various social networks for a while now. I've found I get a lot more things done.

I do like to stay on the bleeding edge of technology, in front of the game, so to speak. Being disconnected has not hurt this at all, in my opinion. I've not lost any business opportunities, friends or missed out on some new, important, game-changing tech...

I think the only things I'm missing out on are the latest LOL-cat or some other random funny waste of time. Or some random interesting but ultimately worthless blog post.

The above image is an advert targeting software developers, it is not a paid advert I have place on this site. It's message is clear.

What are social networks good for? Exploitation and making money. They're great for selling unmitigated garbage to the masses, where you watch them gulp it down in micro-payment sized portions and then beg for some more. If you have a product to sell, use the social networks. If you want to achieve things, leave them far behind, or exploit them for what they are.

## Friday, October 29, 2010

### Generic Manager Component

We've found ourselves using this pattern across a number of projects.
`using UnityEngine;using System.Collections; public class Manager : MonoBehaviour {  static public T Instance<T>() where T : Component {  T component;  var g = GameObject.Find("/" + typeof(T).ToString());  if(g == null) {   g = new GameObject(typeof(T).ToString());   component = g.AddComponent<T>();   DontDestroyOnLoad(g);  } else {   component = g.GetComponent<T>();  }  return component; } }`
It is used to create components which persist across level loads, without needing to create GameObjects to hold those components in the editor. It solves the problem where you may need to load levels in a specific order to make sure your persistent game objects are available in the level you wish to test.

Eg, you may have a MusicMixer component which will continue to play music across Application.LoadLevel calls. Instead of creating the MusicMixer in every scene, (or in one scene and marking it with DontDestryOnLoad) you can access it via:
`Manager.Instance<MusicMixer>();`
And if it does not exist in the level already, it will be created and returned, and also used across subsequent references to the MusicMixer.

### Unity3D Mesh Combining Tip

You don't need to use the CombineChildren component anymore. It appears that anything marked as static is now automatically batched.

Excellent.

## Monday, October 25, 2010

### Generic Thread Safe RingQueue in C#

`using System;using System.Threading;public class RingQueue{ private int size; private int read = 0; private int write = 0; private int count = 0; private T[] objects; private AutoResetEvent addEvent; private AutoResetEvent popEvent; public RingQueue (int size) {  addEvent = new AutoResetEvent (false);  popEvent = new AutoResetEvent (false);  this.size = size;  objects = new T[size + 1]; } public bool Empty {  get {   lock (this) {    return (read == write) && (count == 0);   }  } } public bool Full {  get {   lock (this) {    return (read == write) && (count > 0);   }  } } public void Add (T item) {  lock (popEvent) {   if (Full) {    popEvent.WaitOne ();   }   objects[write] = item;   count++;   write = (write + 1) % size;   addEvent.Set ();  }   } public T Pop () {  lock (addEvent) {   if (Empty) {    addEvent.WaitOne ();   }   T item = objects[read];   count--;   read = (read + 1) % size;   popEvent.Set ();   return item;  } }}`

## Saturday, October 23, 2010

I want to build an fairly high level shader. Here are initial thoughts on features or passes the shader should have.

0. Vertex Colours (RGB)
1. Color Map (RGB Color, A Illumination)
2. Normal Map
3. Specular Map (RGB Color, A Shininess)
5. Environment Cube Map

The specular map is used for environment mapping, in that the Alpha channel shows which parts of the model will be shiny, and therefore reflect the environment. The RGB channels in the specular map are used to tint the colour of the reflection. The reflected texture should follow the distortions created by the normal map.

Vertex colours are used to tint the model, and will be used for fake ambient lighting effects.

The shader should fallback to using passes 0,1,2 and 3, Then fallback to 0,1 and 2 and finally fallback to 0 and 1 as quality is reduced.

## Thursday, October 21, 2010

### RMS in Perth - A Summary.

I recently attended a talk by Richard Stallman, at the Hyatt Hotel in Perth.

A highlight of the night was when fellow Python Enthusiast Brad (from Rockethands) was stopped by Stallman as he arrived late to the talk.

You can read an excellent summary over here.

The best part of the talk was question time. Hearing Stallman adeptly defend his views was quite inspiring.

## Wednesday, October 20, 2010

### Be an Indie Game Developer in 9 Steps.

1. Make sure you have more ideas than talent.

2. Hate the big publishers and anything mainstream.

3. Join mailing lists with other Indie developers.

4. Blog and write about awesome games you will make one day.

5. Whine about scarcity of funding and lack of government handouts.

6. When you eventually make "something", whine about the lack of sales.

8. Watch other developers make money. Call them sell-outs. They don't deserve the "Indie" badge.

9. Rinse and Repeat.

## Tuesday, October 19, 2010

### RMS

Went and saw RMS speak tonight.

Does RMS ever get tired of playing Saint IGNUcius? Imagine telling the same joke for decades; surely it eventually gets a bit stale.

## Monday, October 18, 2010

### Custom Coroutines in Unity3D.

I had a whim today. In my Python green threading framework (Fibra), it is possible to run a section of code inside the green thread function in another OS level thread. This lets you do fun things like break out of the main thread when waiting for IO, or doing something that might block the rest of the green threads.

In Unity3D-speak, a green thread is called a Coroutine. After doing some rather ugly things with threads today, I figured things could be much cleaner if I could simply execute certain parts of a Coroutine outside the Unity3D main loop. It is possible, and I've done it. Here is the code! :-)

This is the test MonoBehaviour script. Notice that it inherits from Fibra, and uses StartGreenThread to execute methods that look like real Unity3D Coroutines. Inside the Coroutine, a FiBranch instance is yielded, which is the signal for the scheduler to run the next section of the Coroutine in the thread pool.

`using UnityEngine;using System.Collections;using System.Threading;public class FibraTest : Fibra {        public IEnumerator Busy() {        Debug.Log("Before Continue.");        yield return new FiContinue();            Debug.Log("After Continue.");        yield return new FiContinue();        Debug.Log("Finished.");        yield return new FiSleep(3);        Debug.Log("Ok really finished. Well with this CPU anyway:" + Thread.CurrentThread.ManagedThreadId.ToString());        yield return new FiBranch();        Debug.Log("I'm in another thread:" + Thread.CurrentThread.ManagedThreadId.ToString());        Thread.Sleep(1000);        yield return new FiContinue();            Debug.Log("Done:" + Thread.CurrentThread.ManagedThreadId.ToString());            }        // Use this for initialization    void Start () {        StartGreenThread("Busy");    }        // Update is called once per frame    public new void Update () {        base.Update();    }}`

This is the Fibra class, which implements the green threading magic.

`using System;using System.Collections;using System.Collections.Generic;using UnityEngine;using System.Threading;public abstract class FInstruction{    public abstract bool Execute (Fibra scheduler, IEnumerator task);}public class FiContinue : FInstruction{    public override bool Execute (Fibra scheduler, IEnumerator task)    {        return true;    }}public class FiBranch : FInstruction{    public override bool Execute (Fibra scheduler, IEnumerator task)    {        ThreadPool.QueueUserWorkItem(delegate(object state) {            bool removeTask = false;            try {                if (task.MoveNext ()) {                    var fi = task.Current as FInstruction;                    removeTask = !fi.Execute (scheduler, task);                } else                    removeTask = true;            } catch(Exception e) {            // Do something in here!                }            if(!removeTask) {                scheduler.StartGreenThread(task);                }        });        return false;    }}public class FiSleep : FInstruction{    float seconds;    public FiSleep (float seconds)    {        this.seconds = seconds;    }    IEnumerator Sleep (Fibra scheduler, IEnumerator task)    {        yield return new WaitForSeconds (seconds);        scheduler.StartGreenThread (task);    }    public override bool Execute (Fibra scheduler, IEnumerator task)    {        scheduler.StartCoroutine (Sleep (scheduler, task));        return false;    }}public class Fibra : MonoBehaviour{    static List<IEnumerator> tasks = new List<IEnumerator> ();    static Dictionary<string, IEnumerator> names = new Dictionary<string, IEnumerator> ();    public void StartGreenThread (string taskName, params object[] args)    {        var method = this.GetType ().GetMethod (taskName);        if (args.Length == 0)            args = null;        var task = method.Invoke (this, args) as IEnumerator;        names.Add (taskName, task);        StartGreenThread (task);    }    public void StopGreenThread (string taskName)    {        var task = names[taskName];        Fibra.tasks.Remove (task);        names.Remove (taskName);    }    public void StartGreenThread (IEnumerator task)    {        lock(Fibra.tasks) {            Fibra.tasks.Add (task);        }    }    public void Update ()    {        for (int i = 0; i < Fibra.tasks.Count; i++) {            bool removeTask = false;            var task = tasks[i];            if (task.MoveNext ()) {                var fi = task.Current as FInstruction;                removeTask = !fi.Execute (this, task);            } else                removeTask = true;            if (removeTask)                tasks.RemoveAt (i--);        }    }}`

The above class uses a double dispatch mechanism, which makes it a piece of cake to add your own custom schedule instructions. Simply inherit from FInstruction, and write your own Execute method. Return true if you want the green thread to be rescheduled, or false if you don't.

## Thursday, October 07, 2010

### ZeroConf Ubuntu Server Setup

Situation: You have a development server (Running the Ubuntu Server OS), an OSX work station, and one network cable.

Task: Enable networking between the two via a network cable so that development can commence!

Action:

1. Plug cable in, notice that network is non existent.
2. Install needed software on server.
`sudo apt-get install avahi-daemon avahi-autoipd`

3. Modify /etc/network/interface file. Change or add a section like this:
`auto eth0iface eth0 inet ipv4ll`
(The ipv4ll is the magic bit.)

4. Restart networking.
`sudo /etc/init.d/networking restart`

5. Ping yourserver.local from your workstation.

Response: Voila, networking is now working.

## Thursday, September 30, 2010

### An ERD for... Elite?

Or perhaps a Privateer style game... no attributes, just keys showing the relationships.

## Tuesday, September 28, 2010

### Small Mercies...

The words create, select, insert, update, delete are all six characters long.

If you work with databases and programming languages, you will understand why this is a small mercy for us poor developers. :-) Or perhaps I am just losing my mind to GDB induced psychosis...

## Monday, September 27, 2010

### I'm Knee Deep in GDB...

Learning things I never wanted to know...

Update:
I'm working with a Stackless framework which uses the asynchronous features of Psycopg2. On top of this, I've been using SQLAlchemy... unfortunately I have recently noticed that after a few hundred or so requests, the application simply hangs. After analyzing a core dump, it seems that something is attempting to acquire a lock... and deadlocks. It is very deterministic, as it always happens at the same point in my unit tests.

I've narrowed down the issue to something inside SQLAlchemy... I attempted to fix it but SQLAlchemy is so full of dark magic that I'm really quite lost. I guess I was expecting a bit too much to think that regular SQLAlchemy would would correctly with an asynchronous driven psycopg2...

## Thursday, September 23, 2010

### Postgresql Introspection.

Postgresql introspection is easy once you know where to look.

Despite working with Postgresql for the better part of a decade, I only recently discovered the Information Schema. It has all your database metadata laid out in nice, human readable views. No more wrestling with pg_catalog and other obscure system tables!

## Sunday, September 19, 2010

### Is the ERD useful for Game Dev?

I think ER diagrams are very handy tools for designing data requirements for a game. I don't see them given away or even talked about (in this context) on the web, and I'm not sure why.

Does anyone else use them? I think if they are stripped of attributes, and simply specify entities and relationships, they can be useful for general design, and perhaps are even re-usable? I have a theory that they form an excellent domain specific language useful for specifying game mechanics. Attributes can be added to a generic ERD, which add behaviour to the model, unique to the game being designed... hmmm.

This is a quick little design I put together to hold the required data for a Master of Orion (4x) style game.

## Saturday, September 11, 2010

### Interesting Postgresql Feature...

I found something new today, Postgres supports asynchronous notifications between different database sessions! What does this mean?

try this in a psql window;
`listen SomethingHappens;`

then in another window;
`notify SomethingHappens;`

Now go back to the first psql session... It's like a mini pub sub system built into your favourite database!

http://www.postgresql.org/docs/8.4/static/sql-notify.html

### Flashback - 1993

Flashback. A hard game, with awesome rotoscoped animation.

I played this on DOS. It is essentially a puzzle platformer, with relatively complex movement. Jumps, rolls, ducking, running and shooting could be all combined in a very fluid way, with flawless, seamless animation. Solutions to various puzzles sometimes required a running combination of several moves.

The graphics were outstanding. The cinematic cut scenes were very well done, and would draw a crowd if you played this in a class room. :-)

This is a great game, with a great story. It is easily equal or better than any platformer produced today. If you want to play it, it should be available on abandonware sites (it was developed by Delphine Software) and there are also version released for NES and Sega Master System... I think. :-)

### Indie Game Makes Huge.

Check out these two links then connect the dots...

First, check out Minecraft.

Two things can be noted here.

1. Minecraft is bringing in a truckload of euros, every week. Good games can make money on their own merit, with or without the Indie tag.

2. PayPal cannot be trusted with your money. Don't use them.

## Thursday, September 02, 2010

### Aircraft Simulation - Unity3D

Controlling an aircraft using physical forces is... hard. I've managed to implement something realistic using various Fin objects which apply forces on the aircraft. This video shows the autopilot system using these fins to keep the aircraft stable.

## Tuesday, August 31, 2010

### Robot Locomotion - Unity3D

This is from... an upcoming project.

## Sunday, August 29, 2010

### Game Creation Tools

At the last few GameJams, I've seen an increase in the use of RAD game tools, some of them even being developed by the participants themselves.

I thought I might collect a list of those tools here. The main criteria for being in this list, is that they don't require programming in a traditional computer language. Data Flow / Diagram languages are ok...

Shoot-em-up Construction Kit
Scirra Construct
Game Maker
Koonsolo RPG Editor
Reality Factory
Scratch
DS Game Maker
Game Builder Studio
Sploder
FIFE - wow, don't know how I missed this one for the last 5 years! Appears to be scripted using Python too!

### Learning the Ropes.

Back in 1994 I applied for a job at Epic MegaGames. I sent them a bunch of my digital art and a resume.

I was 15, and very naive. :-)

It seems the guy who read my application took some pity on me. He sent me back some constructive criticism and gave me a few pointers on how to produce things they could use. He also included a 3.5 inch floppy disk, with the "PCGPE" software on it. This was the PC Game Programmers Encyclopedia. I'm very grateful he did this. He saved me from a lifetime of producing second rate game art!

It a shame that kids are no longer taught this kind of stuff. I doubt many of the new generation of graduates can actually explain how a computer works. I owe a lot to Denthor of ASPHYXIA, his VGA tutorials really got the ball rolling. I had to convert all his code to C from Pascal, as I did not have a Pascal compiler. In the end I had quite a collection of my own demo/intro programs. Horizontal Parallax Starfields, Fire Effects, Sinus Plasma, Scrollers, Lightning, Fractals... I guess a lot of this knowledge is now used in shader programming, and isn't entirely obsolete.

None of this would have happened if someone at Epic hadn't sent me that 3.5 inch floppy disk. I think it was Tim Sweeney. Could it be? I'm going to hunt through my old boxes of junk and see if I can find the letter...

## Saturday, August 28, 2010

### Modem Wars - 1988

I remember playing this on my old XT machine, with a Hercules Graphics Card in 4 shades of amber. I had to run a program called "CGA.COM" which let my Hercules graphics card emulate a CGA adapter.

Modem Wars was interesting as a tactical game. I never had a modem on my XT, so I could only play against the computer AI.

IIRC the game was turn based, and you could move each unit on your team before the AI took control. The aim of the game was to take out the opposing side's command unit, so it was a bit like chess, with some added moves. For instance, you could ask your units to 'bunker down', which added a defensive bonus at the expense of movement.

The command unit had a special move. It could send an unmanned, player controlled aircraft around the battlefield. You used this to find out the location of the opposing command unit. I think you could also use it to crash into other ground units, but this was usually a waste unless you were targeting the command unit.

## Wednesday, August 25, 2010

### Windows and Me.

When someone sends me an exe file, or an ActiveX DLL, and asks me to help out with something software related...

I don't. I haven't run Windows for seven years, and hope I never have to again.

It's amusing when you detect incredulity on their end... they can't believe that someone just doesn't have Windows. Some people even get annoyed. I can tell.

It's not that I'm trying to be elitist, difficult or contrary, I just don't like Windows. I hate it. Windows abuses it's users. I get all tense and angry every time I have to use it (which is _only_ when helping out close friends). If I really had to solve a Windows problem, I'd simply pay someone else to do it.

Some people imagine that 'commercial reality' should dictate what I use, what services I provide. Well, your'e welcome to your own reality, I'll stay in mine thank you! That is why I use tools like Python, and Unity3D. Software isn't worth writing (or using!) unless it is cross platform. Of course, Unity3D is not _entirely_ cross platform, but that will change one day.

## Thursday, August 19, 2010

### HTC Legend - Giving it another go...

Due to my iPhone 3G + iOS4 running like treacle down a hill, I am giving the HTC legend another go. I'm optimistic, as a software update is available which may help improve on my last experience.

Apple have really done their users a disservice with iOS4 on older phones. Given that the older models cannot use any of the new features (apart from the useless and unattractive UI changes) there is no reason the older phone should have such an awful performance degradation.

It is almost as if this line of code is sitting inside the iOS4 source code...

`if deviceVersion != "iPhone4":    GoReallySlowMode(True)    SuckLotsOfBattery()    WaitSomeSeconds(Random() * 10)    ThinkAboutDoingSomething()    PretendToDoSomething()    FinallyDoSomething(reallyJerkyMode=True)`

In fact... I'm willing to bet it is. Apple is the new Microsoft, using shady business methods in an attempt to force users to upgrade.

Megh.

/rant

## Tuesday, August 17, 2010

### A Strange Story.

A long time ago in a place far, far away...

I used to clean windows, in a small regional city called Bunbury. Not the operating system type, but the kind you look through, made of glass. :-) The money was good, the work was fun, and it helped me through the last year of my Comp. Sci. degree. Well, I never actually finished that degree. Ah well. Even so, I always hoped one day to build computer games instead of washing windows!

One day, while cleaning windows and contemplating what I wanted to do in life (game development seemed like a distant dream), I struck up a conversation with an older gent. He told me about his son, who spent day and night in front of his computer, making 3D graphics with a computer language, and apparently he was really good at it! His son was now working in Scotland, and had worked on a game called "GTA". Of course, at that time I had played the demo of GTA and knew exactly what he was talking about.

Why do I remember this quaint little story, more than a decade later?

I think that this was a turning point, where I realised that it was possible for someone in a remote town in a remote country to get an awesome job, building computer games. I think this event is probably a major reason that I am building games today, instead of accounting systems, or worse... web pages!

Why am I telling you this story?

Today I received an email from an Australian who is working in the UK, and is keen to move home. He works with computer games, and is investigating the local scene to see what it has to offer. He also happens to have worked with Take Two... on the GTA graphics engine... 14 years ago, and is from Bunbury. Yep. He is that guy.

Amazing. What are the odds?

## Monday, August 16, 2010

### Game Dev Wages in Perth.

I noticed a local developer has started hiring. It appears they're working on a PS3 game...

They're advertising a bunch of jobs, including creative types, and technical types. The advertised rate for the creative jobs is "40k". That seemed pretty low to me, so I did some research.

They stated in their requirements: "Minimum of 3-year degree with an emphasis in character animation or equivalent work experience." What is the award rate for a person with that kind of education?

Fair Work Australia tells me that it is \$41579.20, assuming a 40 hour work week. If we assume the 40k figure includes Super, that means they're getting paid almost \$5000 below the award rate. Ouch.

The technical jobs have a "45k" salary attached, which, including Super, is still just below the Award rate. Ouch Again.

### App Store will Collapse in .AU.

If the legislation described in the linked article goes ahead, it is more likely that Apple will simply drop and block .au customers from it's App Store, rather than ask developers to pay the quoted \$470 - \$2040 dollars to get a game classified in Australia. At a minimum, It is likely that all free games would disappear.

Xbox Live Indie games already suffer because of Australian censorship laws. Local developer Black Lab Games cannot sell their StarHammer Tactics title on the Xbox in Australia because of this same legislation.

Working with multiple threads is often a necessary evil.

This is how I do it safely inside a Unity3D component. There are only certain times when it is safe to read or change variables in other components. For example, you will encounter problems if you try and modify or query Physics components while a FixedUpdate is occuring! This component uses a Mutex to let the thread know when it is safe to use other game objects.

`using System;using System.Threading;using UnityEngine;public class ThreadedComponent : MonoBehaviour{     Thread thread;  Mutex mainLoop;    void Awake() {    mainLoop = new Mutex(true);    thread = new Thread(ThreadWorker);      }    void Start() {    thread.Start();  }    void OnApplicationQuit() {    thread.Abort();   }    void ThreadWorker() {     //Catch and report any exceptions here,     //so that Unity doesn't crash!    try {      _ThreadWorker();    } catch(Exception e) {      if(!(e is ThreadAbortException))        Debug.LogError("Unexpected Death: " + e.ToString());     }  }    void Update() {    //Gives the thread a chance to work with gameobjects.    mainLoop.ReleaseMutex();    mainLoop.WaitOne();  }      void _ThreadWorker() {    while(true) {      //Play nice with other threads...      Thread.Sleep(0);             //Do random work here...            //Wait till it is safe to work with GameObjects.      mainLoop.WaitOne();      //Work with gameobject in here...      //But don't take too long!      mainLoop.ReleaseMutex();      //Signal Unity that we're done with GameObjects.    }  }}`

## Sunday, August 15, 2010

### Javascript in .NET

I've just found a project which provides the V8 Javascript Runtime, embedded in .NET!

Think of the possibilities when mixing this with the OpenTK project. Fast, cross platform graphics, audio and input with game scripting in Javascript.. Hmmm.

## Monday, August 09, 2010

### Game Pirates: You are Bottom Feeding Algae Eaters.

Machinarium suffers a 95% pirate rate.

As a game developer, it is hard not to be outraged by these figures. Pirating is just not cool. I would write more, but I know it won't make a difference, it falls on deaf, dead and scarred ears. It is of no use trying to preach ethical and moral behaviour to self centred, me-first-gimme-gimme bottom feeders.

/rant.

## Monday, August 02, 2010

### Unity3D 3.0 - First impressions.

I like the new, darker interface. Looks great, and is easy on my eyes.

First difference I noticed... the compiler is stricter.

Second thing I noticed... the physics engine behaves differently. My in-development-car-game behaves completely differently in Unity 3.0.

## Tuesday, July 27, 2010

### Live Performance on the iPad.

One app stands out, and it is called ThumbJam. I've been playing with this all night. It is very, very good. I own a Korg Kaossilator Pro and a Korg KP3 (touch music devices), and they could learn a whole lot from this \$9 app.

## Monday, July 26, 2010

I've been working on a high end shader over the last few days. this particular shader needed a diffuse map, a normal map, a specular map (color and alpha mask), a cube map, and a fallback texture. The cube map provided reflections which were mapped over the normals (from the normal map) of the model. Here are some random things I've learnt.

1. Add ambient light, don't multiply.

2. To mix colours, multiply them together, then multiply by 2 to retain the same brightness.

3. Use the Unity3D macros in UnityCG.cginc, they make life much easier.

## Wednesday, July 21, 2010

### Sabbatical

define: sabbatical

An extended period of leave, often one year long, taken by an employee in order to carry out projects not otherwise associated with the employee's job.

I think it is time for me to have one of those...

## Saturday, July 17, 2010

Every now and then, I see something so cool that my head explodes. It happened this morning while watching this video.

Beast Light mapping in Unity3D.

Woah.

I'd better start cleaning up now.

### Star Hammer Tactics

My friend Paul (from Black Lab Games) released Star Hammer Tactics on PSN this week.

I bought a second hand PSP just so I could play this game! :-)

It plays _very_ well on the small screen, it seems to fit the PSP controls perfectly. Awesome work Paul!

## Thursday, July 15, 2010

### Emergency Apple Press Conference

Apple are having an emergency press conference tommorow, and it is all about the iPhone.

Kevin Turner, from Microsoft, thinks that the "iPhone4 is Apple's Vista." Errr right... Except that the iPhone4 problem can be fixed with a case for the phone, and doesn't punish the user with bondage, discipline and an ugly abomination for an interface for half a decade.

## Wednesday, July 14, 2010

### ...

This is performed by my erstwhile colleague and fellow Indie Dev, Brad Power. Nice One Brad.

Update: The above video was taken down by the RocketHands guys, at the request of the double rainbow guy. They have no legal obligation to do so, they're just playing nice. Megh to the Rainbow Guy, your 15 minutes are all but over.

## Tuesday, July 13, 2010

### Neat .Net Stuff

This snippet shows two cool things. The Threadpool which can be used for arbitrary tasks, and an anonymous method, which allows the programmer to define throwaway, single use methods.

`using System.Threading;ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(Object state) {    //This block will run in a separate thread!    //And not block your main program. W00t!}));`

## Monday, July 12, 2010

### Generic Ring Buffer in C#

This data structure is helpful when creating lock-free algorithms. I'm not sure if the exceptions used are appropriate. Any suggestions?

`public class RingQueue<T>{    private int size;    private int read = 0;    private int write = 0;    private int count = 0;    private T[] objects;    public RingQueue (int size)    {        this.size = size;        objects = new T[size + 1];    }    public bool Empty {        get { return (read == write) && (count == 0); }    }    public bool Full {        get { return (read == write) && (count > 0); }    }    public void Write (T item)    {        if (Full)            throw new IndexOutOfRangeException ("Queue Full!");        objects[write] = item;        count++;        write = (write + 1) % size;    }    public T Read ()    {        if (Empty)            throw new IndexOutOfRangeException ("Queue Empty!");        T item = objects[read];        count--;        read = (read + 1) % size;        return item;    }}`

## Monday, July 05, 2010

### GameJam Perth 2010 - Part II

If you're interested in attending GameJam Perth 2010, Part II, or you want to keep in touch with GameJam events, please sign up here.

### HTC Legend - Review

The Good.
- Nice Body
- Nice Camera

- The Interface is bad. The keyboard is cluttered, with redundant glyphs cluttering each key.
- 6 hardware buttons which don't work as you expect.
- Multiple ways to scroll the screen, which work differently in each app. You can use the trackball, or the touch screen. Or accidentally both at once.