Followers 0
• entries
9
• comment
1
• views
7583

## End of Day 4 (Week of Awesome)

Lots and lots of screenshots this time.

The screenshots actually give a fairly good idea of what was implemented today. Things that got done today:

• aircraft model
• addition of a throttle control
• AI players shooting back
• terrain assets, including a volcano that emits clouds of ash
• when an aircraft crashes into terrain, the terrain "catches fire" at that spot
• static gun turrets
• a new particle texture

I still need to texture the aircraft model and the AI likes to crash into the terrain at random instances, but now the game is at the point where I can almost start calling it a "game." Tomorrow is when I'm aiming to have the first level playable. I'm also hoping to have the menu/briefing room/victory/defeat UI flow implemented tomorrow so that one could actually start the game and play it. If I get around to texturing the aircraft and making a new explosion sound tomorrow, that would be great, also.

An artist (one of my roommates, actually) volunteered to help me with some of the artwork today. I expect this should expedite the schedule tremendously.

## End of Day 3 (Week of Awesome)

The game is ALMOST playable, for a certain definition of "playable." Not much in the way of screenshots today, however. In order: improved water splashes, pursuing a fleeing AI-controlled craft, and rocket exhaust.

Today was another day with not much new visually-speaking. Most of what I did get done was audio or AI related, though there were a few particle effects tweaked and I added some new controls and simulated behaviours. What was done today includes:

• a basic AI which can cruise, aggro, or flee
• sound files for every implemented mechanic as well as ambient noise, though a couple of these are placeholder or need a lot of tweaking
• adding music, though this is disabled until I slap together some music that satisfies me
• rocket exhaust
• explosion and splash effect tweaks
• a speed brake
• a throttle control

I meant to actually model the player's ship today, but didn't get around to it, having decided to focus on audio the previous night and on AI this afternoon when I had some ideas as to how to implement it. I also spent a LOT of time just tweaking what I added today, much more than I wanted to. I spent over an hour just working on a gunshot noise that would satisfy me. I don't have all that much experience (relative to my other skills) with doing sound foley or sound programming in general, so today was a bit of a learning experience for me. I'm still disappointed with all of my attempts at doing music, but after experimenting with the gameplay that may be less of an issue than I originally thought. The engine noise I put in is strangely soothing and I almost feel guilty for sullying it with music.

I keep coming up with ideas for features to add. It's stressful in a way I can't quite describe in my current frame of mine to have to repress them. I'm constantly telling myself, "no, no, save it for after the contest." Or, "no, no, that effect is fine for now, go work on something else." And then that part of myself that wants things to be completely perfect sort of splutters incoherently for a few minutes before it lets me continue.

I think tomorrow will be an artwork day more than anything. If nothing else, I'll start on the terrain and put in the altimeter and speedometer. Maybe some menu assets, too.

I'm hoping to have at least one level playable by the end of Friday.

## End of Day 2 (Week of Awesome)

Firstly, screenshots:

Today I made progress without really feeling like I made progress. Among other things, today I implemented:

• barrel rolls
• banking
• engines (propellers, rocket booster)
• a Gatling gun, which pivots to follow the player's targetting reticule
• paratrooper deployment
• goal locations + indicators
• ships and other entities having health, which dwindles when hit by gun bullets
• collision detection between water and other things and other things and bullets
• water splashes and explosions

I think the chief reason I feel like I didn't achieve much is because of what I tried to start and failed, namely putting together the player's "pteroplane" and starting on the music/sound foley, both of which I had meant to do today. In both cases, I ended up opening the relevant editor and finding that I'd run out of creative steam and couldn't continue. Furthermore, my continued lack of inspiration on music is frustrating, but the pteroplane modelling and sound foley are the real priorities, so I'm not terrifically worried. I think I could probably do without music if I really, really had to.

I also had a fun idea for a "bonus level", but I doubt I'll get around to implementing it before the end of the contest.

Tomorrow I'll start with some sound foley to ease my mind on the subject. Thereafter I'll probably continue on to adding terrain features and maybe get started on the AI if I'm not feeling "artsy" enough to start on the player's aircraft.

## "Lord, what fools these mortals be!" (Week of Awesome)

Here's the last screenshot of the day.

The title of this article largely refers to myself attempting to use GIMP to throw together the UI art that you see in the above screenshot. I'm not primarily an artist, so I don't know my tools as well as I perhaps should. I spent quite some time throwing those things together. I eventually hit upon a very silly technique involving a lot of layer masking and GIMP's gradient generator which worked, but was difficult to control. I like the result, and now that I know how to do it I may use that technique again for later UI work, but only if I absolutely have to.

I'm sufficiently tired that I'm calling it and going to bed.

At this point, the player can control his "ship" (which currently is just a white cube) by pitching and yawing around. I think to simplify things I'm not going to add explicit roll control - when the player yaws, the ship will bank a little, too, just like in the games that inspired this one. I may also add barrel rolls if I have time, if only so that I can yell "DO A BARREL ROLL!" at my roommates if they do any playtesting for me. In terms of environments, the game shows water, two cloud layers, a lens flare representing the sun, and a skybox. The two displays at the bottom of the screen are an attitude display and a radar display, both of which I'm quite happy with in terms of polish. I might add an altimeter at some point, but since it isn't super-useful to the gameplay I have in mind (which is largely fly to specific points shooting at anything that gets near you), I may delay that in favour of more important things, like the weapons implementation and island terrain. I tried to work on music, but had no real inspiration tonight. I might do sound effects before music.

I plugged a game controller in on a whim and found the default control scheme Unity gave me to be rather intuitive. When all this is done, I might develop this into a split-screen console-like game. Maybe I'll get an Ouya to play with and see if I can get this running on there.

## On the Subject of Gameplay (Week of Awesome)

Have another screenshot. Woohoo, flying cube.

So this is going to be an arcade-y flight sim in a similar vein to Star Fox or X-Wing: Rogue Squadron.The backstory here is that sentient dinosaurs have developed a technological civilization just in time to address the "asteroid problem" which caused the K-Pg extinction event. Your particular faction of sentient dinosaurs (have yet to decide on a name for their race) is building a rocket-ship to redirect/destroy the asteroid before it hits Earth, but a rival faction has stolen the parts of it and scattered them on various tropical islands. You have to take some commandos to the islands aboard your steampunk robot pterosaur (yeah....) and drop them off so that the parts can be retrieved and the rocket built. Along the way, you'll have to defend yourself against enemy fighters, of course, which is what the gameplay will mostly be about.

I guess I'm reinterpreting the theme to be, "What if the dinosaurs never went extinct because they had a space program?"

## First Screenshot (Week of Awesome)

First screenshot. Not much to this yet, just some water, fog, and a skybox.

## "There are more things in heaven and Earth..." (Week of Awesome)

First thought on the theme: the dinosaurs died out because they didn't have a space program. Suppose we gave them one, armed to the teeth to save themselves from their impending destruction?

## Purpose

One feature that a lot of games utilize is a sort of "radar" display. This idea manifests in many different forms, but as far as I can see, its most common incarnation is that of a secondary display which provides an abstract overview of the player's situation without them needing to keep track of all the details themselves. Consider (for instance) the "motion tracker" in the Halo series, which allows the player to track both allies and opponents without actually needing to see them directly. Likewise, the concept of a "mini-map" as used by many real-time strategy games provides an overview of the battlefield that frees the player from needing to watch over the entire battlefield all at once.

In the project I'm working on, these displays are actually the primary method of interacting with the player's spacecraft, both in manoeuvring and in combat. There is an "external viewer," which corresponds to a third person perspective, but it is mostly there for eye-candy purposes and has little in the way of game-play value. Those readers who have played a submarine combat simulator like the Silent Hunter series or Dangerous Waters will be familiar with the idea of a "navigation map" or "tactical display" which is used to display the player's ship (referred to hereafter as "ownship") and other objects of interest in a way that shows their relative distances and other important tactical information.

Let's pretend we're implementing one of these displays ourselves. So we want a simple display where ownship and enemy vessels are "blips" on a radar display. To implement this, it appears that we need to have some kind of object that lives on the tactical display that will represent other objects in the "real world", without actually being coupled too closely to them. Let's pursue this idea and see where we end up.

On Unity

Since the rest of this post is going to be fairly heavily Unity-centric, this seems like a good place to review how Unity's object and scripting systems work for those readers who may be unfamiliar with Unity.

All entities in a Unity game are represented by "game objects" and all behaviour is implemented by "components," which are attached to game objects. Game objects essentially behave simply as containers for these components. Game objects can be marked as "children" of other game objects to form a hierarchical scene graph. Components can be bolted onto game objects either at design time (via Unity's editor) or attached to game objects by other components at runtime. The only component which all game objects carry is a "Transform", which represents the position, rotation, and scale of a game object in Unity's game world. All other behaviour must be attached to game objects in any given scene or onto "prefabs" which can be instantiated into a scene. Users may either use components which come with Unity (such the RigidBody component or MeshRenderer component) or components which are provided by the user in the form of JavaScript (actually "UnityScript"), C#, or Boo scripts.

Note that all code presented herein will be in C#, though I'd imagine that UnityScript or Boo users would have few if any problems porting it to their preferred language.

Refinement of Requirements

It seems like setting our "radar blip" objects to be children (in the scene graph) of the objects they represent would be the simplest way to accomplish what we want, since this will ensure that, assuming we don't move them around, the blips will have the same position relative to the objects they represent - ie. they will mirror the movements of the simulated game objects. For a lot of cases, this will work just fine. However, what happens if we want to rotate, zoom into, or pan through our radar display? Sure, we could move the camera around, and that might work pretty well, but what if we just want to change the distance between the radar blips without changing their apparent scale? Suppose we want to change the way the scale is represented on the display, such as if we want to keep all the blips on the display and have them get "stuck on the edge" as FPS-MAN (which coincidentally also uses Unity) does? What happens if we want to introduce some uncertainty in the position of our little radar blips, such as to represent the fact that most kinds of sensors are not 100% accurate at long distances?

It seems to me that it may be helpful to rephrase and refine our requirements somewhat. What we actually want here is an object which represents another object, which mimics its movements and consistently represents the distance between it and other objects, but in a different coordinate system, namely the coordinate system of the radar screen/tactical display. We would also like to be able to tweak this coordinate system somehow from the editor as well as from other components in the game world.

To accomplish this, we'll need to create a custom behaviour which, for descriptive purposes, we will call a "TransformShadow." To do this, we'll create a C# class which inherits from Unity's MonoBehaviour class, as we usually do when implementing custom Unity scripts. We'll give this class a field that the user can set to whatever game object they want the shadow to follow, plus a set of fields describing the coordinate system that the TransformShadow lives in. Furthermore, we'll have the shadow update its own Transform component on every update so that it mimics the movements of the object it shadows in real time.

Here is the code for this extremely basic TransformShadow:public class TransformShadow : MonoBehaviour{ // note that these fields are public because the editor at least will need to // set these explicitly and other objects may as well. // if we only wanted these to be modified from the editor, we could make them // private and stick a [SerializeField] attribute in front of each of the fields // we want to be visible to the editor. public Transform shadowCaster = null; public Vector3 translationFactor = Vector3.zero; public Quaternion rotationFactor = Quaternion.identity; public float scaleFactor = 1.0f; // note that since all code that updates the parent transform will be in // corresponding FixedUpdate() methods, so to prevent stuttering we'll put // our shadow update code in FixedUpdate(), too. void FixedUpdate() { if (shadowCaster != null) { // note that we also rotate the translation before we apply it and scale the position // as if it were the distance from the origin transform.position = (shadowCaster.position + transform.localRotation * translationFactor) * scaleFactor; transform.rotation = shadowCaster.transform.rotation * rotationFactor; transform.localScale = shadowCaster.localScale * scaleFactor; } }}
More Features

The above code works, but it doesn't get us everything we want. In fact, it doesn't really get us anything more than we could already get by attaching our shadow objects to the shadow caster object and moving the camera around to simulate rotating, scaling, and translating the shadows together. Let's make this a little more flexible.

First of all, one of the things mentioned above was the idea of scaling the distance between shadow objects without actually scaling their form. This is quite useful for something like a radar or tactical display - we want to zoom into the display, increasing the apparent distance between "blips", but we don't necessarily want to zoom into those blips, themselves. So, we'll modify this code to actually have two different "scale factors" - one for distance, and one for form. Furthermore, for cases where we want to scale distance, but not form, we'll want some way to specify from the editor that this is the case. In fact, we can go even further and let users switch off and on specific types of shadowing if they like!

Here is the updated code to take all of this into account:public class TransformShadow : MonoBehaviour{ // note that these fields are public because the editor at least will need to // set these explicitly and other objects may as well. // if we only wanted these to be modified from the editor, we could make them // private and stick a [SerializeField] attribute in front of each of the fields // we want to be visible to the editor. public Transform shadowCaster = null; public Vector3 translationFactor = Vector3.zero; public Quaternion rotationFactor = Quaternion.identity; public float distanceScaleFactor = 1.0f; public float formScaleFactor = 1.0f; public bool mirrorTranslation = true; public bool mirrorRotation = true; public bool mirrorScale = true; public bool scaleDistance = true; public bool scaleForm = true; // note that since all code that updates the parent transform will be in // corresponding FixedUpdate() methods, so to prevent stuttering we'll put // our shadow update code in FixedUpdate(), too. void FixedUpdate() { if (shadowCaster != null) { if (mirrorTranslation) { transform.localPosition = TransformPosition(shadowCaster.position); } if (mirrorRotation) { transform.localRotation = shadowCaster.transform.rotation * rotationFactor; } if (mirrorScale) { transform.localScale = shadowCaster.localScale * formScaleFactor; } else if (scaleForm) { // note that this second cases is needed for when we are NOT mirroring scale, but // want to scale the form of our shadow object anyway. transform.localScale = formScaleFactor * Vector3.one; } } } // we extract this out for clarity's sake. public Vector3 TransformPosition(Vector3 srcPosition) { // note that we also rotate the translation before we apply it and scale the position // as if it were the distance from the origin Vector3 scaledPosition = srcPosition; Vector3 scaledOffset = (transform.localRotation * translationFactor); if (scaleDistance) { scaledPosition *= distanceScaleFactor; } if (scaleForm) { scaledOffset *= formScaleFactor; } return scaledPosition + scaledOffset; }}
Update Ordering

Now, astute readers may have noticed a subtle problem with doing things this way. That problem is that it is not necessarily guaranteed that the shadow caster will be updated before TransformShadow.FixedUpdate() runs! For most cases, this can be fixed by changing the update ordering in the Unity editor to guarantee that every frame, other components will run their FixedUpdate methods before any TransformShadows run theirs. However, what happens if the shadow caster is another TransformShadow? And yes, that can happen! There's nothing in our code prohibiting it and I'm sure the reader can imagine cases where doing it would be useful. So how do we deal with it?

This necessitates adding an extra field and two extra methods to our TransformShadow class: private bool updatedThisFrame = false; // note that LateUpdate is called immediately after Update. This means that it // actually runs LESS often than FixedUpdate(), so it's guaranteed to ensure that // we don't do any calculations that we don't need to do. protected void LateUpdate() { updatedThisFrame = false; } // we'll call this from the FixedUpdate() method private void ForceTargetUpdate() { // if the shadow caster has a TransformShadow component attached to it, update it first TransformShadow targetCaster = shadowCaster.GetComponent(); if (targetCaster != null) { targetCaster.FixedUpdate(); } }
public void FixedUpdate() { if (shadowCaster != null && !updatedThisFrame) { // if the target is another shadow caster, make sure it gets updated before we do! ForceTargetUpdate(); if (mirrorRotation) { transform.localRotation = shadowCaster.transform.rotation * rotationFactor; } if (mirrorScale) { transform.localScale = shadowCaster.localScale * formScaleFactor; } else if (scaleForm) { transform.localScale = formScaleFactor * Vector3.one; } if (mirrorTranslation) { transform.localPosition = TransformPosition(shadowCaster.position); } } updatedThisFrame = true; }