I opted for the XNA platform since I'm well versed in C#, and I found it to be a very mature wrapping of the DirectX interfaces. As I found out during development though, that decision came with a few compromises as to available functionality, and ultimately the demise of the project as a whole.
Today, this project is simply a bunch of screen shots and a single YouTube video. The source code is intact, but because "Games for Windows Live" is now dead, GameStudio (as XNA is known to the layman) is no longer supported and cannot compile or run on versions of Windows later than 7.
The only feasible way to revive this project is to port everything over to Visual C++. I have neither the time nor the inclination for such a herculean effort; my last C++ coding was done sometime around 2001.
The development diary of this project is still a very interesting read, and everything I learnt doing this made it well worth the effort. Stingray will defintely not be my last project containing realtime 3D visuals.
The above is a screen dump of my actual back buffer from the level editor. And, as highlighted, there seems to be some problem with the clipping or something. Areas which are supposed to be hidden behind other areas are drawn and seen. Sort of like a Z order problem when working with sprites.
I've searched high and low for solutions to this, but Google has not been forthcoming. And the App hub registration is so spastic that I cannot sign up (South Africa is not supported). My options are now either to
Of course, I'll still continue to look for a solution. The members over at Stackoverflow might hit on something...
The upshot of it all is that I'm finally in a position to actually start building my game. To date it's just been infrastructure mostly, and there are still a bit left of course. But as you can see, the level editor is now gaining momentum.
Those are the 8 basic tiles I've modeled so far. There's plenty more to come, and they've been manually placed in XML because the editor is still lacking vital functions. Something else I've managed to accomplish is a solar model, or sunlight & moonlight model if you want. It manages itself through calls from the Update() method. The main game code does not have to do anything special to change the direction or the light color. It all happens within the instance itself. You simply instantiate it at a certain time of day and it starts ticking over. The effect as it goes from dawn to dusk through the color and direction changes is quite amazing to see. Of course, in the finished game, a complete cycle of 24 game time hours will probably take around 3 hours real time. It should be subtle, otherwise it will distract the player. However, if someone does play for 1.5 hours straight, the changes will be noticed. That's the sort of scenario I'm looking for.
And as you can see, I managed to solve the problem with the incorrect rendering of hidden faces. Some settings in the shaders solved it. Not sure what device state in XNA 4.0 is appropriate to fix it yet though.
Once you've defined the scope, the types and the number units you will be putting into the game, there's really no getting around the fact that making all of the content, be it 3D models or sprites for the UI, takes a very long time.
Much more so than the actual coding of the game. Needless to say, as an indie I don't have a team of artists at my disposal. So between myself and Ramon, we're filling up our free time (an increasingly scarce commodity!!) quite comprehensively.
Currently I'm concentrating on level objects, like the palm tree above. There's some problems with the alpha map as you can see. Depending on the lighting it's either white, or it's the fill color. Not yet sure what the reason is, but I'll muck around with the shader and the device state to try and solve it. Ramon is currently concentrating on the actual player helicopter model. We've dicussed various "modes" for the chopper, and there will be an upgrade system. Mostly though, we want a visual aspect to each of the upgrades and special abilities. This might complicate matters dramatically with the animation loops etc, but we'll get to that when we get to that :)
I say sort-of, because if you read the articles that was linked by Andrew, it's quite obvious that I didn't understand some pretty basic concepts very well. For instance, the depth buffer. That forced me to rethink my design a bit, and how I process the content for drawing. It also forced me to do some math, and I realised that for items like the palm tree, it might just be possible to model it completely instead of using very few faces with alpha blending. And as a result it actually looks better.
Apart from the above, I've managed to get somewhere with one of the enemy units as well. A simple recon vehicle. Here is a render of it. There's still a bit to do before I can use it as a game model, one of which is the texture coordinate unwrapping, which will probably prove to be a pain.
You might have noticed that there is a rather complete lack of concept art so far. The fact of the matter is, I just don't have the time to sit and churn out pencil sketches or otherwise to design the game elements. However, as things start ramping up, I'm pretty sure I will have to take a step back and spend some time on this.
Also, I intended to make the map only 512x512, but that proved to be a bit too small in getting the colors on the right places. Anyway, here's another render of it with a small thumbnail of the map. With these units there is a difficult decision as to what level of detail is required, and I suppose it will take a few iterations to get it right. For the most part I envisage that the player won't be too near them at any time. But, if there are any animated cut scenes later on starring these models, they should at least look the part. So, this model clocks in at just under 7000 triangles. If that's too much or too little, I don't know. From these pre-renders, the quality looks ok-ish to me. And I still got to do all the normal maps as well.
Ramon also sent me a render of the chopper. This is already a week out of date, and he has already started unwrapping it I believe. As you can see, he put a lot of effort into the rotor mechanism. It's something that will be on the screen almost all the time, and I think it's stellar. There's also a lot of animation loops he's got to do still. The wheels, bay doors and the various guns and their different animations. Hopefully I'll be able to figure out how to get it all into the game itself.
There's so much more content to make still, but slow and steady wins the race :)
The screens of the level editor I've posted have hacked code to get it working correctly. I basically passed the original normals straight on to the pixel shader code instead of transforming them.
This means that all the tiles get the same amount of sunlight. It's obviously a problem when you start to rotate stuff, since the shadow areas will change depending on the orientation. Thus I need to transform the normals. However, doing so resulted in very strange results. Tiles to the left were lit differently from tiles to right. It's actually an age-old problem, and perfectly obvious when you visualise the process of the vertex and pixel shaders.
The problem comes in with using the same matrix as the one for the vertex transformations (which, incidentily, all tutorials do). But, this article explains quite clearly that using the main transform matrix as is, is not correct. Also see my news post about the MATHS :)
As the article explains, if you use the correct distinction between points and vectors, the same transform matrix could apply if you don't do any scaling. Which means you modelled everything correctly at the start. But I did a test, and even though you can declare the input to the vertex shader as float4 for the normal, XNA does NOT pass in a normal with the w component. In the .X files, the normals only have three components, and XNA's vertex structures are based around the Vector3 struct. This means the w component does not exist within the C# space. So it's up to you to set w to zero in the shader code for normals (it seems it's set to 1 by default based on my test results).
The conclusion then, is that XNA does not employ "homogenoeus vectors and matrices" at all. So you have to make it do so, otherwise you won't be able to move your models around your world. Well, you will, but it will all be dark.
Ramon has almost completed mapping the chopper. I know he's having difficulties and headaches since it's a rather complex model, but if anyone can get it done, he can. This is what he's come up with so far...
In other news, I've finished a prototype 'skybox'. I say prototype, because at this point it's not really all that good looking, but the idea is proven and all that remains is some tweaking. The textures are transitioned based on the sunlight system. Actually, the sunlight system drives the whole skybox by itself, including the rendering of it. All nicely packed into a single box of pleasure :) The screenshots were taken at dawn, noon and during late evening respectively.
The principle behind this is quite simple. There are no shortage of tutorials out there on this topic, and plenty of discussions about the best method to use. The one I have opted for is the custom shadow mapping option. I suppose at some point I will try and figure out proper hardware supported stencil buferring etc, but there are well documented pros and cons attached to each method. See here for details. It is a very, very old post, but serves to illustrate my point.
So anyway, moving on to what I'm trying to accomplish... Here's the depth buffer I'm generating from the viewpoint of the sun. This bit is pretty straight forward, using its own (but small) shader and a render target. One note on this - most native DirectX implementations opt to use the R32 surface format for this to retain accuracy. For XNA, I initialize the render target to the R1010102 format. This is memory overkill at the moment, since I'm only using the red channel for depth information. The problem with this is that other formats like Single does not support blending (or requires Point filtering instead of linear), so passing it to the real scene render shader is not supported when the BlendState is set for alpha. So, to make the best of it, I'll probably change it to a normal RGBA32 format and pack the float depth value into the various components instead. Should make for some pretty psychedelic depth buffers :)
Currently the actual generated shadows are all over the place. I'm thinking an error in the projection from the camera viewpoint to the light viewpoint for depth comparison. No luck so far, but I'll keep at it. After that, there's blurring to be done as an additional step. The only problem with all this is that the frame rate is cut in half... At this point I'm not discriminating as to what I'm rendering for the depth buffer, but that said there isn't a lot on the test level to exclude either.
I've managed to solve the problems with the projection from the camera view to the depth buffer. The HLSL function tex2Dproj doesn't actually do what it says on the tin. Basically, once you've transformed the pixel to the depth buffer space using the appropriate projection, simply calling tex2Dproj directly using your resulting projected vector isn't actually going to work. Even though the function does the projection divide, it doesn't restrict it into the 0.0 to 1.0 space that is used for UV lookup. A simple matrix calculation can do that for you though, and then use the function to get the appropriate texel.
This is what I ended up with. Very blocky and very low fidility, but at least it's accurate. These is still a problem with the clamp filtering or something. The far tiles are dark which shouldn't be. But all in good time...
There's not much to say here. Doing this using tiles is a bit of a pain, but it proves interesting, and gives us the ability to upsize the level area dramatically without a big impact on the footprint on disk, memory or framerate for that matter. Also, since the inspiration dates from the late 80's and early 90's, the tiling is sort of mandatory. Think of the new Ford Mustang. It's a faithfull homage to the old classic. The lines, the overall design harks back explicitly, but yet manages to convey a modern design. This is what these tiles are all about. Back in the old days they had maybe... 5 or 6 different ones. Today we have excellent capacity and capability, so I can have 600 different tiles split between the various geographical areas. But of course, I'd still want you to get the sense that it's tiled... just the like old games.
The screens below show two of the new tile areas, cliffs and the coastal regions. There's also a shot showing the recon vehicle in game. It's still with the basic texture. And I've not yet built in the positioning of objects (static or actor), so the palm tree and recon is in the same spot for the time being :)
It sounds like a bit of a setback, and to a certain extent it is, but I was never under any illusion that I'd be able to get away without LOD. So, I revised my content model and drawing engine a bit, and then proceeded to model different versions of some of the same models. The palm tree below as exhibit A.
I reached a point where I was forced to solve my frame-rate issues. I built an object brush for the level editor. It allowed me to pretty quickly paint many, many, many palm trees. After battling a bit to determine the exact height underneath each instance so that they 'stick' to the level tiles, I ended up with a frame-rate of about 12... And it was even slower in the game when the depth and shadow maps are also rendered. So, LOD as a first step. Secondly, I've had to limit the content that is used for the depth map and shadow map renders. Not all content will generate shadows, and not all content will receive shadows. Discriminating between that has helped to get the frame-rate back to around 35... which is better for what is currently all happening.. but I'll still need to spend time revising. I hope to avoid having to do LOD on the tiles - it will probably cause tears and look pretty bad. So hopefully far-plane distance and drawing distance will help to limit the lag from the tiles.
Also, Ramon has made progress with the Stingray...
Noise maps are a tricky thing. The theory of it, as with everything, is pretty straight forward. Implementation, on the other hand, proved to be more than a day's worth of frustration. But I did come up with something usefull for generating the levels in Stingray.
The second problem is knowing which tiles belong together. Apart from the fact that four tiles at a time share a single texture map, there's no other obivous link apart from the naming of the tiles. This is not something usefull. I've opted to build a tool to link tiles to one another in all four directions. It's hard work up front (read tedious) but it will make it fairly easy to determine which tiles to place where on the map. Considering the number of tiles I already have (and that are still to come), the links of all these tiles would make for some excellent graph theory examples :)
So, to achieve this, I've worked hard on the content set editor to facilitate both the actual linking and testing the linking. These screenshots also show the various elements that the drawing engine supports, although I haven't made maps for any of the slots except the diffuse.
Testing the links is simple - you select the tile in the appropriate direction and it's drawn next to the tile being edited. It's worth while to note that the coordinate system in XNA is different (Y-Up) from the modelling software (Z-Up). So, when modelling you have to remember that north becomes south, and west becomes east... maybe thats the future of world politics as well?
The office asked me to do a presentation on Stingray for one of the Knowledge Sharing Sessions they have on a monthly basis. A couple of guys at the office have been keeping tabs on the progress and they've deemed it worthy of a recommendation for a session. We'll mostly cover the performance side of things - optimal code with optimal structures - to keep it relevant.
As part of the preparation for it, we decided to wrap up the production on the actual Stingray chopper model and stick it into the game for real. Ramon had actually delivered the model to me a while ago, and it's been lying in my inbox ever since. But the weekend I decided to take it in, clean it up, finish the unwrapping and well... see for yourself...
I decided to start with a 'stealth' texture. There will be more options later on, which will be determined by your upgrades. The other neat success about this is that the canopy of the chopper is the first real transparent item in the game. I've had to tweak the shaders a bit to get the sun/moon reflection off it looking good, and it pretty much all worked out well.
I've also built some more items for the levels and overall there's much more going on in the scene than before. The frame rate on my laptop seems to still hover around 30 after I revised some infrastructure and optimised distance sorting, but I think that's the limit of the hardware on here. I should start taking screens from my gaming rig now. All in all it's now really starting to look like a game... At least that's what Ramon said :D
Progress has been steady, but nothing that was worth posting. I've finished all the tiles for the basic level layout. There were quite a few do to, but now that it's done I can start working on the level generation. There is already something happening there, but with missing content things didn't work very well.
Other than that, I've also started on the targeting system, e.g. basic hit testing. The chopper's gun follows the cursor on screen and the system correctly identifies which object is being aimed at. Some simple reverse projection calls and maths really. The biggest challenge was to do that as part of the pre-process loops to avoid having to traverse the object structures a second time. Of course it's easy to just make a bunch of global variables... but come-on... seriously? So, since there's already loops happening to identify viewable objects and LOD distance in the pre-process phase, there was no point in looping through that list again to find my target. Also, the gun does fire, ammo gets expended, but no visual cue and no damage is being delt yet.
Next on my agenda, I'm looking for a small success item, so I'm gonna do the HUD. But not as you might think ;)
There's also other stuff that I'm starting to think of. Especially sound and music. I've asked Ramon to start on an intro sequence as well. Whether that will be stills based or movie based we're not sure yet. But now that the basic level layout options are done for the most part I can get on with rounding out the experience, story line, missions etc. At some point though I'll have to go back and revise all the art, get normal maps in there etc. That will be the polish phase.
There are still a few missing tiles that needs to be made in order to complete the puzzle. These are the obscure tiles that will appear maybe five times in the level in very suspicious nooks and crannies. But those nooks and crannies are there because the random decides for them to be there. That is the problem with the random level generation. If everything was sand, for instance, the problem would not be present at all. But with the transition areas from sand to ground, and with the cliff tiles in the mix, the current seed I'm testing with throws me a few curve balls with regards to the layout.
Apart from that though, other level bits like the trees, the shacks and the prefab houses are now also being 'strewn' accross the level. It's kinda like discriminatingly shaking a pepper grinder over the basic layout. But palm trees should stick to the sand tiles. The shacks and prefabs can land anywhere. And nothing should land on the dune tiles. Of course, since this is random, the specific locations are not exactly controlled. Hence sometimes (again on the transition areas) the trees do land on the ground. But that's ok.
And 'land' is the operative word here. I know the level elevation will never go higher than 240. So I start by placing the object on an altitude of 1000. From there I cast a ray straight down and get the intersection on the bounds, and then get the intersection on the exact face. It's the same routine I use for the chopper's altitude calculation. From that I can determine with a high degree of certainty exactly what Y value the object must have to be on the ground. Basically firing the objects from space.
The other bit of work I had to so was to restructure some bits of the entity model so that I could create an object preset. These presets are used to define objects that will be used in the level. For example, the guard tower is made up of the main building model, and then the windows/screens that has an alpha component. The alpha components are drawn last for obvious reasons, so it has to be two separate models in the content set. The preset combines these and from the preset various different instances is created as level objects.
The HUD has also been tweaked and the display errors on the alti-meter has been corrected. But there's more changes I want to do on it before I'll show you what it looks like.
I initially just set off doing my own thing, using the existing architecture of the game. Things worked... but it looked utter crap. I was initially using an instanced quad, and was about to get into how to billboard it. But it wouldn't have worked. Calculating rotation angles for 600+ particles per smoke plume was always going to be too expensive. Of course, you can argue that you only need to calculate it once because each particle needs to face the same direction. But only if you're viewing it from a horizontal position. Instead I decided to look at the AppHub 3D Particle sample. And boy did that one look pretty damn good.
So I set about rewriting my particle system a bit to make use of the clever ideas implemented in that sample. The circular array instead of a list (must faster). The dynamic vertex buffer instead of an instanced quad. And the vertex shader which does almost all the calculations on the GPU instead of on the CPU. Clever stuff.
There's still one bit of this implementation that I don't quite understand: the way it calculates the actual screen space coordinates of each particle based on the viewport scale (??) and a single position vector. It's something I'd never have thought of in the first place, but using this method evidently requires very little overhead to do billboarding. So I'm quite embarassed to say that at least that bit of code is a straight copy and paste from the sample.
In the end though it's at least looking proper. That said, the first implementation is something I'd want to keep, because there will be use for a system that uses instanced geometry. I'm thinking debris particles when something blows up. That would just look 100 times better using actual models than billboards, and you can do some excellent random rotation per particle.
And lastly, untweaked and not done yet, is the new HUD showing in these screenshots. It's fully integrated with the chopper, and doesn't required the player to move focus from the action in order to see the details. Granted, at some angles it does become less readable, but so far to me that doesn't pose a problem.
If you expected to see some gameplay footage though, sorry to dissapoint. But I have sort of completed the shooting. This followed from my chat to Danny from QCF Design after Wednesday's game dev session. Basically it went something like : "You say you're writing a game, but there's no gameplay..?" "Um..yeah.. but...um.."
I was looking for a way to determine an exact hit. Until now I targeted the objects using the bounding boxes. It's fine to know what your aiming at in the general area, but not good enough to determine what exactly you are hitting. So I got an idea last night as I lay in bed, got up, and tried it out. As it turned out, it only worked in my head. But I then I found another solution, and that worked like a charm.
The chorus goes something like this:
- Find the ray that is the gun sight
- Use that ray and object bounding boxes to find potential targets
- Test every object found if there is an exact hit based on the point in triangle method
- Now I know exactly which object is hit, and I know precisly where that object is being hit based on the UV coordinates
Two things here to note: Firstly, I already have a FOR loop to determine viewable objects in a pre-process method. I implemented these steps into this same FOR loop, otherwise you're doubling up on CPU time going through the same list of things. Secondly, when using the point- in-triangle method, I use my lowest detail models. They closely mimick the shape and size of the high detail versions, and there's no point in hit-testing detail. You're only interested in the bottom line - is it hitting exactly and where is it hitting? If I was writing Battlefield 4, then yes I'd use the higher detail versions to determine of an overhead power cable is being hit and break apart and spew electricity on everyone :)
All that was left to do now was to pass a couple of event handlers around to effect the damage dealt by the gun. This actually happens per round being fired. I have a single particle system, attached to the chopper, that generates one particle for each round being fired. Each particle is assigned it's target at the time of creation based on what the chopper was targeting at that specific time. When it expires it triggers its event that is hooked up to the linked object and some method calls sorts out the rest.
So, I finally have some real gameplay. Go figure :)
Started this last night, and they're all moving around already. Simple waypoint manager class attached to each actor objects. At this point I just randomly generate a circular route or each object.
As far as problems go, correct orientation was a slight issue. At some point all of them moved around in reverse gear. But once that got sorted it wasn't too difficult to make them actually turn around to go to the next waypoint. Just like a car would, e.g. not turn in the same spot.
Another one was to stick to the ground. The tiles are not flat. There's bumps and stuff on them. So I hijacked the code used for the chopper's altitude calculation to determine the correct height of each object at their location.
And then the speed. At the moment they're all travelling at max speed. It's fine, but it looks strange when they first set off - immediately barelling along at 25 m/s. There needs to be a run up. So I've been mucking about in Maxima to determine a good formula.
At first I was trying for a formula that I could simply use at any point between two waypoints. But the multiplier, which is the maximum speed, doesn't actually result in the maximum speed. So I've abandoned that one.
Then I decided I'll work on a percentage from the start of the 'from' waypoint and a reverse percentage from the destination waypoint seperately and apply the above function.
But it looks that the ramp-up is still too quick to 10 m/s, so adjusting the exponent solves that with the third function.
Now to implement! Oh yeah - also all of them always turn left. I need to look at the dot product to get a sign to apply to the direction adjuster.
It's all fine and dandy moving vehicles around the level, heading in the correct direction and at the correct height based on the tile underneath. But when it encounters a hill/dune/bump it shouldn't just float up and float down, the vehicle's orientation should change with it's nose point towards the sky as it mounts the slope.
It was easy enough reading the normal from the currently occupied face. But I had some trouble getting the measurements to work correctly according the vehicle's local axis, as opposed to the world axis. This means that if the vehicle is heading north-east, it's local axis is turned 45 degrees (or Pi over 4 :P) from the world axis. But in essense I ended up with a value that I could use to stick into the world matrix for the vehicle.
The green (tangent) vector here is the key. You cannot work with the normal, because it has no relation to the direction. I initially used the red (normal) vector to calculate an angle with the Unit Y vector, because irrespective of direction, Unit Y is still applicable to the vechicle's local axis. But in fact that was wrong. The direction is important, and the calculation of the tangent to use in conjunction with the vehicle's own direction vector is the key. In the image below the magenta lines are the face normals, and the green lines are the tangent normals.
So that solved the tilt angle, but as you can see, I still need to do the roll-angle. Hopefully this won't take me as long.
The graphical side of it is not as important for me at this time. If it's functional and it's visible, it's fine. But with the particle systems the work involved in just making it look so much better than the first draft implementation was miniscule, so I spent an hour on it.
More importantly however, technically I had to consolidate a bit. It's so easy for the code to run away from you if you're not carefull. Sloppy implementation up-front will make for big headaches later on in life. That's kinda common knowledge. The problem with prototyping though is that you tend to rush through things with your mind on the game play design and not so much on the implementation design. Because the purpose is primarily to test the game play, this isn't a problem per-se. However once the game play is confirmed and the idea is not binned, you have to go back and refactor and revise that implementation.
So after some structural changes, some new additions to the XML pipeline and three re-works of the smoke and new dust textures, this is the result. The dust trail specially adds a lot of base for me. It makes the vehicles have substance. But anyway, I hope you like!
The thing about rockets is that they fire straight from thier mounted position, much like the mounted machine guns on the old WW2 airplanes. Of course the mountings are slightly angled inwards so that eventually the two lines of fire cross each other, which determines the optimal distance to target. But in that I've now come across an issue, and it's to do with the controls. The chopper pithes and rolls, and affects where the rockets are aimed at. But with keyboard control it's really difficult to keep that reticle pointed on a specific target. Partly because my targets are now moving as well (if you aim it at a vehicle), but mostly because with keyboard controls there's no in-between. The chopper is either fully pitched flying forward, or hovering flat, or lifted up going backwards, in which case you're firing into the air.
Now, the controls as implemented at the moment are shaky at best, because I've never needed it done well enough for gameplay. So that's obviously what I now need to do next, before I even bother with the smoke effects and all the other neat stuff that will give the pleasure of firing rockets.
There was also a more minor problem with the HUD in regards the rockets. Since they have a static reticle, and since the player can swivel the view around the chopper, seeing where the rockets were going to hit didn't work out that well. Of course it's easy to say "Yes, but the player should look down the sight when using rockets", but that's not a very good argument because then it renders the use of the gun, which is tied to the camera, impossible.
Fortunately, with the reticle for the nav/gun sight, I've already solved the problem of correctly projecting the reticle at the correct position onto the HUD relative to the spot being aimed in conjunction with the camera position. So it wasn't too much of a hassle having the rocket reticle always appear to show where the rockets will hit, irrespective of where the camera is. In this way the player can now fight two battles as once - attacking one target with the gun, and another with the rockets, all at the same time.
Hopefully I'll have some screenshots towards the end of next week with smoke effects, bullet tracers etc, but first I've got to solve the control issue, otherwise there's no point to all this.
This morning I tweeted a picture of the first successful rocket smoke trails. That was a major milestone. By that time the controls were also about half way sorted, and I did a lot a of play testing through-out the day. But there was still more to do. A rocket is pointless if it can't hit anything, and the next step was to start blowing stuff up.
Without too much effort on content (I only made a new explosion particle map) I managed to get the explosions going, and soon after that the accurate hit testing followed. Fortunately, this far into the project, there's already a lot of fully functioning methods, and I really didn't have to write anything majorly new to achieve it.
All that remained was further play testing, and of course bugs. Some were small and some where pretty hard to figure out. For example, the rockets travel fast. Their speed is configured at 40 meters per second, and after failing to destroy targets that I thought I really did hit, I found that the hit testing condition is too simple. It tested how close the rocket was to the target to ascertain if it's explod'n time. But, on one frame it was just .045 units too far away, and on the next frame it was already past it, e.g. -3.5. Which meant I had to build in a prediction variable of where it will be on the next frame which is then used in confuction with the simple test.
Fortunately I managed to solve all the problems that I could uncover during all my testing, and boy, it's now really starting to look like war. On my test level the objects are pretty closely placed, so everything is within reach of your gun and rockets. At some point I had about 20 smoke plumes going up, and that's a big smile on my face...
So what have I been busy with? Well mostly player engagement. Previously I had the chopper's gun firing, and shortly after that the rockets started flying as well. It wasn't long until missles were added to the mix using locked-on targets and following the up and over flight path towards the target.
After that I messed around with the controls a bit more. Some people suggested a Battlefield control system which seems to work a lot better for aiming the rockets, but to me not such an intuitive third-person system. It's still subject to change. What I also did was put in the forward outposts. These are massive roaming landing platforms to refuel, rearm and repair at. They are commandable from within the chopper's Nav mode and they have some defensive capabilities, but they are very slow to move around and require time to deploy and redeploy.
Then I moved on to the NPCs. After some discussions with Sven (@FuzzYspo0N) regarding systems in the game, I sat down and started designing the gameplay systems with regards to the AI and player engagement. The first order of business was individual AI. Each NPC needs to react to the environment in some sort of autonomous way. Questions like "Do I attack?" and "Do I flee?" is not always subject to external commands. These questions' answers are also different depending on the type of NPC. A simple recon jeep will react differently to a tank when a chopper appears over the horizon.
So, coming off that, I first had to restructure yet again. My asset structures were incompatible with different settings for different unit types and the class hierarchy did not lend itself too well to applying these different settings. The restructuring took about a day, but it left me with a clean implementation structure for not just custom AI and individual configurations, but also for unit specific animations and other sorts of class-differentiating NPC attributes.
So, what's the outcome of that you ask? Well, the recon jeeps now react when you come into visual range. If you're still far enough and appear not to head in their direction, they will continue on their patrol route. If you come closer they will start to put distance between themselves and you. If you're really close, they start to open fire in defense. And they are also reporting your position to the central AI every 60 seconds. Of course, this is just the start of the autonomous part of it all that I've now completed. Going furthur than that, the AI should be able to form groups of recon jeeps who will then openly attack you instead of simply defending for example. But those sorts of things will all be built as the model becomes clearer and the design improves. Also they are actually shooting back and dealing damage to you - that already works too :)
Probably the most difficult part of this projet to date has been definining the various game systems and AI states. Yes, it is a bit late in the day for this sort of thing. But at least I'm there and I'm doing it. Descriptively, tiring is an understatement. Much like concept art this process starts on paper, and then I transitioned it into a mind map. But conceptually it's way more taxing than anything I've done so far. It's just hard.
Initially it seemed like it would take two ticks to do actually, hence the up-beat nature of the previous blog entry. The autonomous AI for the vehicles were quick to define and implement. And also easy to test. But when you start fleshing out the 'greater force' that the player will be up against, things start spiraling out of control very easily. And like most software projects, when you start eyeballing the details there's nothing keeping an eye on the bigger picture. I've come to refer to this as the distilling process.
Piling on states and variables is no good thing, and it's hard to take all that and boil it away until the essentials remain. So what is essential then? That rather depends, but one non-negotiable requisite is to have a very clear idea of what your game is going to be about. And I'm not talking about your idea's premise. I'm talking about your game systems.
How are you going to achieve meaningfull player decisions? Variations in player engagement? Sure, some of the story elements or the underlying premise drive towards that, but that doesn't go deep enough.
In Stingray, the premise is corporate warfare. Part of the story is infrastructure. So, a tactic that would slowly disable intallations is on the cards because if you're on the full-stealth side of the tech-tree you can't bull-run an installation out right. Take out the power supply then, that'll shut it down. Oh wait, there's more than one. But now they know where you are. Was that a good decision? Because here they come to investigate. Will they repair it while I'm dodging?
And so the spiral continues...
Earlier in the month I visited The Bakery Studio in Claremont who agreed to assist in making sound effects for Stingray. That process was completed this week and I picked up the sound effects from them. To put it simply, it was worth the very reasonable cost. The engine sounds and stuff were pretty much spot on and went into the game without a hitch. Actually, that's the case for 90% of the sounds. I was quite amazed at the difference it made. Of course there were some technical implementation issues as usual, but some intellegent queueing and what-not seems to have solved most of the issues.
And so with that in place, a gameplay video is on the cards, but there's a few things I need to do before I record one. Chief of which is the controls. The prototype control system was a bit too jerky and had a whole host of issues. I've come to know how to get around those through all the play testing, but keen viewer eyes will certainly pick up on the issues when watching the movie. So I finally pulled out the old (1998) physics text books from varsity and started overhauling. The effect was quite dramatic. It actually works very very well, and it's not super higher-grade flying mechanics either. Well, play-testing will reveal that, but so far it's smooth and weighty. It has a nice feel. However, to alleviate some complexity I've also had to build a feed-back system that basically tries to keep the chopper from ascending and descending when there's no player input. All that's left now is the tail-rotor physics. When all this is done I hope to tune it such that it will be possible to do some very cool evasive and strafe-attack manoeuvres.
I've also identified and determined the 10 main story points. This is a great leap forward for me since it will make determining the content and AI scope going forward a lot less daunting and random. In fact, I have already drawn up a list of all the various static defence systems that will be in the game. It will include beam weapons :) So go dodge that :P
So what exactly does that constitute? Well firstly, I'm not even sure that it's the correct term - it's just what I think it's called. But basically it's animating objects that doesn't have skeletons. Skeletons and thus character animations through skin modifiers is a whole different sort of animation, and also on a whole different level of complexity. I dabbled a bit with that in the MiniLD submission "Mommy there's monsters". But for Stingray, here, today, I'm not doing that.
What I'm talking about mostly mechanical objects that have different parts, and each part can rotate/move to a certain extent, but is also subject on it's parent's rotation/movement. A good general example is robot arms used for vehicle manufacture and production line stuff. The upper arm is connected to a base, which can rotate around the vertical, turning it either left or right. The upper-arm itself is constrained by it's mounting point, and can only lift and lower. The lower arm has the same constraints, but is subject to the upper arm. And so on. This situation is prevelant in Stingray, specifically with the mounted mini-gun on the front of the chopper. It's mounted to the body where it can turn around. The gun itself can only be lifted or lowered. Together, the movements of the two parts allows the gun to be aimed almost anywhere.
Now, I realise that most middleware solutions (UDK, Unity etc) has implementations of this which is (probably) easy to use and setup. Since I'm not using any of those, I had to build a small system to handle that and to configure it quickly. So far it's not a very robust system, and I'm sure there are many situations which it won't be able to handle yet. But I'll expand it as I need to. For the moment, however, it's a simple implementation with a small config that does what I need it to do.
In the image you can see the two different pivot points. The mounting bit, which turns left or right, and then the gun which is linked up off-center from the mounting point. The gun's position is dependent on the left or right rotation of the mounting.
Each object that needs to be included in the hierarchy is listed in the XML, together with which type of animation (rotation or translation) and it's own constraints in terms of the three axis. In this example, the mounting can only rotate around the Y (green) axis, and the gun can only rotate around the X (red) axis. Optionally, each object can then be linked to a previously configured item in the list and the constraints of this link, the inherited movement, is also specified in terms of the axis. So the rotation of the mounting around the Y axis causes the gun to also rotate around the Y axis. The tricky part here is that the gun's pivot should be rotated relative to the mount's position, and not relative to the world origin, and you have to keep in mind which transformations is applied before or after the model transformations in the .X file. But like I said, it's pretty basic, but it's a solution that works for now and which has a very small footprint.
Even though the gun is hardly going to be visible, it had to go in. I really just had to texture it and so one, and started looking at a bug where the gun wouldn't lift higher than a certain point. Quite quickly I noticed that it is similar to another bug on the sight. Turned out it was the Dot product that always takes the smallest angle, and you have know when it's negative or positive. So, solved that.
So Saturday I was kinda lethargic and just messed around in photoshop trying out some ideas for the normal textures for the ground and sand. This quickly turned into a quite a bit of work that carried on through Sunday, and I've only done like 12 tiles worth :) But it least helps to make things look awesome. Here's the ground and the sand, both obviously most visible in low light conditions.
It might seem superfluous, but these updates just serve to flesh out the experience on the test level. Instead of just having a small piece of land that simply ends in space, the level now extendeds all the way to the edges of the map, and this gives a well rounded impression. It will also serve to fill up the space in the final game.
I opted for the solution of the 'sprite sheet' setup. One 2084 texture with 16 frames of 512px each tiled onto it. The animated texture class finds the correct texture for the current frame, and also finds the correct texture for the next frame. The duration of a frame is pre-calculated and then the two frames are transitioned using alpha-blending depending on how far into the current frame we are. This means I can easily use only 16 frames for a 5 second loop. Naturally, a screen-shot doesn't show this off very well :)
Update: I've spent some more time on the water shader and on the assets for the water and also the coast line. The animation is now much smoother and the all the coastline assets have the shader applied. To prevent secularity on the sand and non-water bits I had to use a specular value map. This is basically a map with 8 bits per pixel detailing how much specular should be applied in the pixel shader. Instead of using a whole texture for this I've embedded it into the alpha channels of the existing normal maps. It's a bit of an extra process, but saves a hell of a lot of memory. There are some artefacts along the edges of the tiles, but this is something I can get right with a bit of shader manipulation, so not so much of a worry for me now. On to other things!
It was my first time. It took some getting used to, but ultimately I must say I'm super happy with the results of that, and the resulting normal maps that I could make.
All that's left to do now is rework the diffuse maps a bit and then get around to sculpting all the rest of the cliffs. The challenge at the moment is the tiling aspect. With the normal maps in the mix it's difficult to control at the moment particularly along the lines of the cliffs itself. If it does appear very obvious I'll have to think of something. But other than that it's all lovely.
Update Here's an updated screenshot of the cliffs with a new diffuse texture. You'll notice that the ground and cliff colours are all a bit more de-saturated and lightened. This was thanks to my wife's suggestion since she didn't think the colours matched.
Simple stuff like a main menu on the title screen and an in-game pause menu seemed easy enough, but as it turns out there were some real problems with my disposing and switching between the different sections of the game. Also, I had a bug in my sound code that caused some sounds to continue playing irrespective of the game being paused. This same bug is also what caused some strange sound corruption issues.
The effects I worked on was mostly explosions and other combat effects, like the missiles and rockets. Fighting at night time now proves to be way more epic than day-time, simply because of the updated effects. Tracer rounds now fill the sky, and the explosions at night time are pretty awesome to behold, specially on moving vehicles. I've added a small integrated tutorial as well, the end of which is visible in the shot below.
I also added actual geometry for the rockets and misses. Both have an illumination map, making their tail-pipes visible during the night. At day time they're not really that easy to spot though, due to size and speed. The missile is visible below the chopper in the following shot.
The HUD-integrated pause menu is also visible in these shots. Additionally, when landed, there is another in-game menu in the same fashion where later options to save the game and select upgrades will appear. Soon the build for the submission to Indie Cade will be made available to the public, so watch this space.
I continued to model the ordnance in the game and recently added the flak rounds and the bullets. The references I initially used was the WW2 flak cannons. The most widely used AA round was 22mm calibre, and thus I modelled the rounds based on this information. As it turns out, it's so small that it wasn't visible in the game at all. This is in contrast with the rocket and missile models which are to actual scale. Because those are launched from a position close to the player, they are visible when it matters. However as the player dodges and manoeuvres around, the flak rounds were almost never close enough to the player to see. My solution was to make them bigger. They ended up being almost 7 meters long in real world scale, and close to .5 meters diameter. This is massive. But to give the player the ability to see them, it was necessary. Similarly, the bullet rounds are the same, almost 7 meters in length.
Even after all this, I found that it looked crap. Previously I had simply drawn lines between the previous and the next positions. This had looked a lot better, and my conclusion was that it created the illusion of motion blur. I then adjusted my textures to blend some alpha towards the rear of the AA and bullet models, which did the trick! Additionally, with the use of models I'm able to make and apply illumination maps for the tracer rounds as well.
The bullet rounds are visible on it's way to the player here, and also some from the chopper being fired. With the models it looks much more realistic than the orange lines did. The design decision behind all this is to facilitate the shoot-em-up/dodge-em-up aspect of the game play. Instead of the bullets hitting almost instantaneously, it's instead very obvious to the plater that there's a burst of rounds coming his/her way, and the speed is balanced such that the player can react to it. Making the visual aspect of this work towards that goal is very important. Of course, there's no such thing as tracer flak rounds as far as I know, so those will not be visible at night and makes night-time engagement a bit more tricky.
So I Googled a bit for images of real-world HUDs, and found that almost all of them are lit up like a christmas tree. The high contrast from the background is what makes all the difference. Here's an example:
Looking at that it was obvious that I couldn't just get away with adjusting the color from Lime to something more white. I could maybe have gotten away with adding some gradients and clever masking to my PNGs files which I use for the HUD elements, but that wouldn't have solved my problem for the text. So I started writing a pixel shader. A derivation of the Poisson blur and a few pow() and clamp() calls later, and the result seems pretty ok.
Obviously this will get tweaked as time goes by. The filter settings is pretty sensitive to the render target size (where a 0.001 shift in UV could be a dramatic shift), and there's some glaring/white-out where there's overlapping, like on the radar. But all in all I'm pretty happy in a preliminary sort of way.
Rogue Trooper is a game that's still on the top of my personal charts. It's a basic shooter. Fun, and stays fairly close to it's source material. And quite cheap on Steam now. Those are not the reasons I like it though.
I like it because of the set-pieces. This is the same reason a lot of people liked Spec Ops: The Line as well. The whole game is one long Michael Bay movie. Every level is Optimus-Prime vs Megatron, and this is what I think gives that overall feeling of excellent narrative. It's not really complicated or in-depth narrative at all when taken in isolation, but because of the environment, because of the level of involvement in the set-piece, it feels like it has massive narrative. Rogue Trooper didn't have the tech to do this very well, but it is still there. Spec Ops though, that does it all. The vistas, the vertigo, the armoured enemy, the banter and the swearing. Well worth the popcorn. It's also worth noting that the Uncharted series is based on the same ideas, but I've never owned a playstation so I don't have personal experience with it.
So what makes for a good set-piece? Well, I'm not an award winning director or anything, but the first thing I've identified is size. The bigger it is, the better. This is why in the first Far Cry, they plopped down an aircraft carrier instead of a simple abandoned airbase.
The aircraft carrier is not just long and wide, but from a first-person perspective on the ground, it's also damn high. That's a set-piece right there.
The second thing I've identified is effects and animation. A dead area is dead. That's not a meme, it's a truth. If there's radars in the area, move them about. If there's a stack, make smoke come out of it. Old doors? Hinge them back and forth a bit. It's these little nuances that really makes it special. For an analogy: Look at the inside of the Pagani Zonda. They could have just gone and stuck some normal air-vents in that cabin, but they didn't. They made it look like steam-punk plumbing, chromed and polished.
So, since my submission to Indie Cade in May I've been working on the ten identified set pieces for Stingray. This isn't something I can post about easily though, since it would essentially be spoiler posts. But I wanted to share what's currently in the foundry. The process of constructing one of these set-pieces, the environment of one of these.
The first is the wireframe of the in-game model, and next to it is the same model as a solid, but colored based on which bits are mapped together. Next is the sculpted seriously high-detail model of the same area (12 million faces). This is used to generate the normal maps, which when applied together with other (still WIP textures), forms the last image, which is again the low-poly game model as it would look in the game.
As I've said before, the most time in development is spent making content. And these sort of set-pieces takes the longest of them all. The content itself, the maps, the models. But also the animations and effects, testing, the scale. Does the detail level sit on par with the rest of the game? What will be the memory requirements for this bit? There's a whole lot of planning that has to happen, but the pay-off is worth it though. If I pull this off, it would hopefully transform Stingray from a simple game to an epic spectacle with pantomime and theatre. Something memorable. Something that, hopefully, you will like and talk about.
Apparently there's a date of April 2014 around this. But, as they said: "XNA Game Studio remains a supported toolset for developing games for Xbox 360, Windows and Windows Phone," said the representative. "Many developers have found financial success creating Xbox LIVE Indie Games using XNA. However, there are no plans for future versions of the XNA product." Here the article on IndieGames.com
As these things go, I'm now flogging a dead horse. If the support is not guarenteed, there's absolutely no point in carrying on with this framework. So, I have a rather big decision to make. Port, or abandon.
Seeing as the whole world has seemingly adopted Unity, that does look like the best use-case at the moment. Although there's a lot out there, including Crytek's offering. But all that effort? Starting from scratch now, while I've got two other (non game related) projects already going seems a bit too much.
I can't even begin to hint at a direction in this blog post. It's all a bit depressing, really.