View the individual posts for a better framerate on the Unity player...
Train Defense 2
Having some problems with the server - my last train defense update has disappeared.
Here is the link to a new archive build. The files are no longer exposed for tinkering, but its still free to play.
I've decided to put the Train Defense PC development version online if anyone wants to download it and play with it.
Also, the art and game configuration files are all PSDs, PNGs and XMLs so feel free to play with anything you want.
It's only a development version - there is no PC support for achievements or leaderboards, since gamecenter handles this.
I've nothing good to say about unity's particle systems.
Wasted many nights trying to wrangle Unity's particle system. It has a new Shuriken particle system which is broken when it comes to spawning a single particle at an arbitrary location, velocity and colour, and an old particle system that can't seem to fade out alpha without changing the colour.
So I've got some placeholder particles working but its in a pretty bad state. I could write my own particle system but they have no support for point sprites and trying to do an optimised particle system using the dynamic mesh interface is going to be fairly inefficient. I'll just have to leave it for now and try again later.
On a different note, I've added carriages. At first I thought they'd be too special purpose to use my existing turret attachment system so I tried implementing a separate system for them... but failed miserable in a pile of code poo. So I regrouped and decided to see just how well the attachment system could handle carriages. Turns out, with some simplifications, the attachment system handles them fine. There was a few script dependency issues but these eventually worked themselves out. The train engine is now the only script that gets an Update() called by Unity. It calls a RepositionAndUpdate method on the attachlist script which calls the same method on all its attachable objects. The attachments themselves call their attachments and so forth.
The attachList script also has a spawn function which can, very carefully, spawn an initialise a gameObject. There's some tricks to that also in Unity as instantiating a gameObject gets its Awake() called but not its Start(), so you need to avoid using Start() for items you will spawn. I may end up using object pools for speed and avoiding garbage collection, but they are quite wasteful of memory when you have a large variety of prefabs. I don't seem to need them for now, but the option is there for later if I hit any performance issues.
Just miscellaneous ports this time. Train Defense has 15 enemies and about 20 turrets, each unique in some way, so lots of bits and pieces to port.
Do today I've added an Air propulsion script for the air units, as well as a simple spinning attachment for their blades. I ported the hammer for the small and large ground enemy. The hammer does damage but I've made the train invincible for now.
I've done the twinshooter turret and the laser - the laser is what your seeing below. There's no way to switch turrets in the current build. They are a bit lackluster still without particles, red flashes and camera shake, but functionally its working.
I've started working on the Artillery turret, but its 3am and its not going to happen tonight. Each turret projectile is fairly unique. I shared a lot of code in a messy uber projectile system in Train Defense 1, but it was often painful to do anything unique since they always had to fit in with assumptions made in the hierachy. With Unity components, I've avoided doing any hierarchical reuse. A projectile script handles the bullets, and a turret script handles the turret. The turret script only works with a particular projectile type, since the targetting and firing procedure can be quite unique from one turret to another. This means some cut & paste and duplicating code, but its only a few lines and stops anything from getting messy or making any assumptions about how a bullet should work.
Fair bit of progress to report..
Firstly, I implemented the projectile system so my guns can fire. Nice and extensible scripts, as one would expect from Unity. A projectile script manages a list of bullets and builds them into a dynamic mesh each frame. Everything dynamic has to be indexed triangle lists, instead of strips as I had in the old code. Not much I can do about this in Unity so I just have to pay the cost. A series of bitflags determine what enemies a turret targets, and what collision objects a bullet can hit.
A Health script is added to all destructable objects. I've added armour to objects in Train Defense 2. Not sure how I overlooked that in the original Train Defense - I had just made enemies with bigger hitpoints. Now I have a choice of more hitpoints, or more armour, which opens a lot of strategic elements. So whenever a bullet hits a 'PushOutObject' or 'poo', it calls an appropriate TakePhysicalDamage or TakeEnergyDamage, etc, method on the script (which I keep a handy reference to in the poo).
I'm trying to avoid doing GetComponent<> calls during Update() for performance, so currently the PushOutObject is serving as a bit of a cache for common script types, like Health and DynamicModel. Not sure if it will stay this way. I think the 'cached references' could probably be its own object to keep the collision object simple and clean... something I'll play with later anyway.
The fragment system is now in place - identical to the old Train Defense fragments. Since each model is made of primitives (spheres, boxes, cones), I create meshes for each of these individual elements as well as the single mesh. When something dies it spawns a bunch of fragments from a pool and positions and assigns the appropriate mesh to each meshFilter. They bounce around for a bit and shrink out of existance.
Finally I've added a SoundManager. Seems that you can't avoid adding your own soundmanager to unity if you want any decent control over sounds. I've added a simple SoundManager script that lets me play from a pool of channels, and control how many sounds of a particular group can play at once. So, for instance, I can set that only 4 bullet type sounds will play at once. This is important when you have 40+ enemies all machine gunning at once. You can't just let every bullet fired play a sound. I've chucked in bullets and explosion sounds for now. I don't want to put too many in till the last moment since it will make the Unity web download a lot larger.
So far its all running at 60fps solid on my iPad3 at Retina resolution, so I'm pretty confident this should all work out. Apart from particles and passengers, theres no majorly expensive systems left to add.
So 2 major additions.
Probably hard to see in a window this size, but the train happily bobs around as it moves now. This was trickier than expected since it requires a simple shearing of the transform matrix, but Unity's transform system does not support this. The only transforms you can do are scaling, rotation and translating. To achieve it I've had to modify the vertex shader to accept a custom transform that is applied in local space before passing the vertice on to the rest of the pipeline.
The more significant addition is adding attachments system. I couldn't just add child objects because of the skewing animation I mentioned above - Unity doesn't support skewing of the hierachy. So I've had to add my own custom attachment components. Its actually a fairly simple system and gives me more control over special cases and update ordering, so I think its for the best.
The attachment system is done by having an AttachList component which you add to the parent object. It lists what prefabs to instantiate and what attach point to attach them to. Each model can have any number of named attach points.
The child object is given a script derived off an Attachable component. The Attachlist component calls an update method in the attachable component each frame during the parents LateUpdate. Thus all attachables update after all parent objects. There's not much more too it. The Attachable update knows the attach points and parents objectToWorld transform, so can position itself how it wants.
Currently I just have a 'peashooter' attachable, which is a basic single turret gun that aims at any nearby enemies. I don't have a projectile system yet, so I can't actually shoot anything, so that's what I'll be implementing next.
Finally, I thought I'd have fun with some timelapse desktop capture software I downloaded - chronolapse -which makes it so easy to record a PIP timelapse of code & webcam. So tonights blog includes a small timelapse of me implementing the attachment system.
Tonight I ported the train path code. It went over surprisingly smoothly. I was expecting some issues since all my maths are in radians, but many of Unity's maths use degrees interfaces, and since they are both floats, its easy to mix them up.
While the code ported easily, it actually took me an hour to get the path onscreen. Using Debug.LineRender I could see the path was being created correctly, but nothing would render. Turned out that I forgot to give the path mesh triangle indices. The original code was a long triangle strip, which is more optimal and doesn't need indices, but I need Pro version of unity to access strip rendering functions in there Open GL module. I haven't ran this latest build on iOS yet to see how the performance is hit by Unities dynamic mesh system. Fingers crossed it is fast, or else I'll need Unity Pro to fix it.
Once the path was in I ported the train movement code across. I hit a brick wall trying to get the train wobble to work. Unity transform doesn't allow any direct control over the transformation matrix, so its not possible to do the skewing I was using. Shaders to the rescue here - I made a quick outline shader that takes a pre-transform matrix. Its a bit of a painful solution, since its added expense to the shader, plus I'll have to make sure to apply that matrix to any attach points for attaching turrets to the train, but overall its not a big issue and some of the maths are simpler this way.
I added in a few enemy templates and made them home in on the player. you can use the mouse to drag out a path. its not final UI code since you can currently just click anywhere to make a path, which is wrong.
Tonight I ported the push out manager from Train Defense to Unity. Most of the port just involves syntactic changes from C++ to C#. Pretty much everything that moves to C# just ends up looking cleaner and simpler. All the fancy systems I had in place to handle AI talking to the propulsion system of objects has been replaced by simple Unity component scripts. The data file that used to describe all the enemies is now replaced by variables on the enemy prefabs, making it much more flexible and faster to develop.
Suffice to say the conversion to Unity has been a win on every front so far. The only think Unity can do to hurt me will be performance and so far that has been quite acceptable. Even the debug code for the Push Out Manager is simpler and cleaner now. What was a page long iteration of structures and calls to debug renderers, is now a simple foreach() with a call to gizmo drawSphere.
Each enemy now has a PushOutObject component which caches all the information the pushout system needs to keep objects outside of each other. A LateUpdate on the PushOutManager resolves all collisions and pushes the objects outside of each other.
There is still no AI, other than a desire to go to 0,0,0. AI is trivial to write, so I'll leave that a bit longer. I still have a lot of systems to port, and it will probably take a night to port each one, though I know a lot more Unity now so I'm spending a lot less time searching through Unity Forums.
I've finished porting over all the primitives needed for the Train Defense assets. I've spent a fair bit of time learning unity shader pipeline and trying to work out how to get my dynamically generated entities to appear in the Unity scene view. I'd like to use Unity to set up levels as level editting is one of its strengths. The method I finally settled on was to add a script that chooses which mesh to use from the library of dynamically generated meshes. There is an [ExecuteInEditor] attribute that you put on classes which means the Awake() and Start() functions for your scripts will run while entering editor mode.
I've also started working on the AI framework. Unity has much more mature components than the systems I was using for Train Defense #1, so I'm trying to clean up the code instead of just porting it over. Train Defense #1 uses a very simple physics system for movement and pushout. I'll be porting that also since its a lot cheaper and more controlled than using full physics.
So... its been a while but I've finally found some time to start work on Train Defense 2. I've learnt a lot from the Train Defense project and have some great ideas and improvements planed for a sequel. I won't divulge too much in the first post, but probably drop details along the way.
The first newsworthy item is that I will be doing Train Defense 2 in Unity3D. While I'm happy with the performance of my own engine, being able to push around 200+ enemies with shadows and toon rendering on a iPad#1, its been a pain trying to support Mac and PC releases and I'm not in any position to support Android or Web releases. Unity will let me publish on all platforms instantly.
Also, I am really digging working with C#. Its such a cleaner language than C++. I was worried about performance and garbage collection but some initial tests have had great responses. There's also been a number of hit iOS games released through Unity (Shadowgun, Ski Safari, Heroes Call) so I'm fairly confident I won't hit any roadblocks in development.
First thing is first, I needed to test if Unity could actually handle the large number of enemies that Train defense needs, and with 3 passes per enemy, thats a fair few draw calls for iOS to handle. I'm happy to announce that my first tests have shown unity handling nearly 200 units at 60fps using my shaders. It also seems to drop frames gracefully after exceeding the limit.
Next I needed to port all my models to Unity. I've switched file formats from XML to SHAD, which is a more human readable format as it has no brackets and just uses indents for scope. I wrote a quick converter to write the XML file out as SHAD and here is the results. I've still got a couple of rotations to fix but its nearly there.
1-10 of 10