Mouse Lag

In 0.7.0, the game draws the custom mouse cursor. The mechanism it does this by is very simple: every frame, retrieve mouse position and draw the cursor sprite.

This is the simplest possible way to draw a mouse cursor in a game environment, and it has two problems (well, technically two aspects of the same problem, but I’m separating them for this post):

 • Latency: you don’t see where the cursor is, but rather where it *was* when the last frame was drawn. When the game’s running at it’s standard 30fps, this can cause the mouse to feel a little bit sluggish, but not so much you can consciously notice it (it’s only consciously noticeable if you turn the windows mouse cursor on, at which point you’ll notice that the cursor doesn’t quite keep up).

If we were making a twitch game this sluggishness might be a problem, but for a slow-paced game like Species it’s nothing major.

 • Lag. It means the mouse is susceptible to low frame rates. When there’s thousands of creatures wandering about and “every frame” means twice every few seconds, this causes it to become very difficult to control the game cursor. Factor in the latency on top of not being able to see where you’ve moved the mouse, and the game becomes practically unplayable with mouse control.

 

Artist's Rendition

Artist’s Rendition

 

This is far more a problem: Species is a game that needs to push the boundaries of what the computer running it is capable of. Having a lag-sensitive mouse is a big issue.

There’s actually an easy solution to this: use the windows cursor. It’s drawn by the operating system, not the game, so is immune to the game’s lag.

Except, of course, I want to use my custom cursor.

Don’t give me that look, the custom cursor is important. It is my right, nay duty as a game developer to hijack your mouse and make it into some ridiculously over-sized and self-indulgent custom sprite.

 

hoogeCursorMenu

(totally to scale)

 

So to achieve that, I had to redesign the cursor display function.

Describing that would be a big pile of steaming boring, so I’ll just skip to the end: rather than hiding the cursor and drawing my own, Species now instructs the windows cursor to display as a custom *.png sprite, using a similar (if slightly more complex) system to the one other programs use to display the wait cursor.

The practical upshot of this? Mouse lag immunity! The mouse now runs smoothly and without latency even when the game is drawing at slideshow speeds.

It’s not a complete fix: the UI itself is still linked to game performance, so buttons remain fairly unresponsive. I do have some idea’s on that front, and for a game like Species they might be worth exploring at a later date (I believe it should be possible, theoretically at least, to get the UI buttons and controls drawing at a consistent 30fps even if the 3d world is lagging).

But regardless of what we may or may not do in the future, 0.8.0’s mouse control is a boatload smoother and more responsive than what we had previously. Which is, by my standards, a Win.

Cheers,
Qu

,

Leave a comment

Anatomy of a bug – Loading Death

Hello minions,

Time for another “Anatomy of a bug” post. I’ll try not to get the lymph all over the place, but no promises. Vivisection is a messy business!

A recent bug fix involved a save/load problem: when you load a game, about 10-20% of the creatures would die, but *only* if the game had been running for a few minutes. This was something I hadn’t previously noticed: I didn’t really pay attention to the number of creatures, and they just looked like ordinary corpses after the load, so there was nothing to raise my suspicion.

With the new red-mist effect when creatures die, however, it was quite obvious that a large number of creatures were dying at the exact moment the game was loaded. Nothing quite says “you have a problem” like a couple dozen perfectly-synchronised bloodsplosions.

Liberties may have been taken.

Liberties may have been taken with this rendition of the event.

My first assumption was that this was somehow related to the AI changes: I’d implemented other potential culprits since 0.7.0, things like changes to how growth cost is evaluated and how temperature damage is applied, but since I’d just come off of implementing save/load functions for the creatures new brain, I assumed it was that the AI was being initialised badly. That would also fit the symptoms: 10-20% of creatures would be roughly the amount doing specific, low priority actions (the vast majority of them spend their time feeding), and they always start the game by seeking food which would explain why it took a few minutes to manifest.

But after adding a variety of reset and revaluate functions to completely refersh the behaviour tree, creatures were still dying during load. At that point I had to admit that the AI probably wasn’t the cause.

The next thing to check was that the Save/Load function itself wasn’t broken. That seemed unlikely: typo’s in the save/load routine usually either crash the game or result in *very* noticable problems. Still, maybe I was loading energy as health or something, so it needed to be tested.

I did that by saving the game with exactly 500 creatures, then loading it. Sure enough, when it comes in, there are 428 creatures.

Except… with the power of code, I can put a breakpoint in and study the game’s state at the *exact* moment it leaves the load routine. And at that moment, there are 500 creature’s. The killing blow isn’t actually being delivered until after the game is loaded, in the single update frame between when Loading finishes and the game is actually drawn to the screen.

And that thought, thinking of it as a “killing blow”, caused me to notice something something interesting. After the load, a large number of creatures were Fleeing Randomly. They’d noticed something.

Flee Randomly is actually a very specific behavior: it only occurs when Fear increases with no discernable source. Since fear is only raised under very specific circumstances, we can narrow it down further: they can’t have recieved a threatening ping (since that would give them a source), so they must have taken a significant amount of damage in a single frame.

They weren’t just fleeing in terror from some nebulous threat. They’d been attacked. Eeeenteresting.


Wait, did I say interesting? I meant terrifying. Something is in my game, causing pain and death in the single-frame of darkness between loading and playing, and I don’t know what it is.

After checking that the 8 seals on [REDACTED] were indeed still intact, I started looking for other sources of pain, misery and death in the Species universe. The first was prompted by a strangely beautiful observation: a few particles of snow falling in the desert.

Aha! The temperature map is being initialised one frame too late, hence the snow!

That would mean that for a single frame creatures are subjected to absolute-zero temperature. Or, y’know, -17 degrees Celsius, which is absolute zero in the species universe (FOR REASONS!). That would do some damage: not much, but enough to knock off some of the near-death creatures and scare the rest. Problem solved, and as a bonus we don’t have some wrathful eldritch abomination loose in the game’s universe.

So I went ahead and fixed the temperature map issue.

It didn’t work. The creatures still died.


Welp I guess it really is an elder god. Time to bury your computer, hide in your weird survivalist neighbours anti-zombie bomb shelter and await death or insanity, whichever comes first.

Or we could keep looking for a rational explanation, but where’s the fun in that?

The current UpdatableAttribute system has a neat feature where it records the cause of all changes to an attribute, called “delta’s”. So you can, in theory at least, see what type of health change the delta was: Attack Damage, Temperature, Healing, Pregnancy: you get the idea.

Of course nothing is ever so simple: there are 20-something delta’s split across 4 updatable attributes for 500+ creatures 30 times a second. Getting *specific* information out of it is difficult. Luckily, we know we’re dealing with something unusual here: a large negative spike across many creatures in a single frame. Those are rare, especially now that pregnancy happens over time.

So, some conditional breakpoints and a few false positives later, and we had a culprit:

Aha!

Aha!

ChildhoodGrowth! They’re being attacked by the cost they pay as children to grow to adulthood.

But why?


An answer gives way to more questions. Simply knowing it’s ChildhoodGrowth that is damaging them doesn’t really help: we need to know *why* ChildhoodGrowth is damaging them. What’s wrong with it’s calculation that conflicts with the loading routine?

Here’s the entirety of the code for calculating this amount of growth cost that needs to be paid this from:

if(isChild) 
{
    //Calculate energy cost for growth during childhood
    float energythatShouldHaveBeenSpent = phenotype.childhoodCost.Value * (age / (phenotype.childhoodLength));
    float thisFrameCost = energythatShouldHaveBeenSpent - energySpentOnChildHood;

    energySpentOnChildHood += thisFrameCost;
    health.QueueChange(HealthDeltaType.ChildhoodGrowth, -thisFrameCost);
}

As you can see, it calculates the total amount that needs to be spent (childhoodCost), multiplies it by the ratio between age and childhoodLength, subtracts any energy that has been spent previously, and then applies the result.

Can you see the bug?

No? I couldn’t either, so I created a number of debug variables, to test what the values of everything were before and after saving. The results were as follows:

savedChildhoodCost = 28                 : ChildhoodCost = 28
savedAge = 166                          : age = 166
savedChildHoodLength = 72               : ChildhoodLength = 72
savedEnergythatShouldHaveBeenSpent = 52 : energythatShouldHaveBeenSpent = 28    : BZZZZZT!

Ah! So the difference between what was saved before the load, and what was spent after, lies in energythatShouldHaveBeenSpent, which is…

… calculated from the other three variables. Which are the same before and after the load. So the values should be exactly the same.

What.

Can you see the bug now?

if(isChild) 
{
    //Calculate energy cost for growth during childhood
    float energythatShouldHaveBeenSpent = phenotype.childhoodCost.Value * (age / (phenotype.childhoodLength));
    float thisFrameCost = energythatShouldHaveBeenSpent - energySpentOnChildHood;

    savedEnergythatShouldHaveBeenSpent = energythatShouldHaveBeenSpent; 
            //Note: savedChildhoodCost, savedAge, and savedChildhoodLength
            //are all saved from their actual values at the moment of save.
            //energythatShouldHaveBeenSpent is a local variable, so it has 
            //to be saved here.

energySpentOnChildHood += thisFrameCost;
health.QueueChange(HealthDeltaType.ChildhoodGrowth, -thisFrameCost);
}

The same 3 values being combined in the same way can’t result in a different value. It doesn’t work that way. I must be
missing something. That saved value must have been generated at a different point in time or something…

… wait a sec.

Back up for a bit. I missed something important back here.

savedChildhoodCost = 28                 : childhoodCost = 28
savedAge = 166                          : age = 166
savedChildhoodLength = 72               : childhoodLength = 72
savedEnergythatShouldHaveBeenSpent = 52 : energythatShouldHaveBeenSpent = 28    : BZZZZZT!

There it is. There’s the bug. Can you see it? Look closely.

age = 166
childhoodLength = 72

This creature is not a child.

Why is an adult creature paying the childhood growth cost?


Suddenly everything begins to fall into place.

Immediately after a load, all creatures are initialised with isChild set to true. Their saved age will cause them to *become* adults next frame, but for that first frame, they will pay the outstanding childhood growth cost.

And that outstanding cost is calculated by multiplying the amount it takes to grow out of childhood by their *age*. So if they’ve lived as an adult for any amount of time, that’s quite a lot of growth cost they haven’t had to pay (by virtue of being fully grown), that they suddenly have to pay all at once in a single frame.

And they would have gotten away with dying horribly too, if it wasn’t for us meddling kids.

Thankfully, after all that, it’s an easy solution: just make sure “IsChild” is saved and loaded, right?

Well, not quite. Creature’s are initialised as children, they need to call the GrowToAdulthood method, or they’ll suffer permanent dwarfism. I could call this method manually, but it’s clumsy and inelegant. Plus it doesn’t really address the GrowthCost debt, which keeps accumulating in the background and only takes one wrong line of code to show up and wreck things.

So, a slightly more sideways solution is to make sure EnergythatShouldHaveBeenSpent maxes out at ChildhoodCost. No more excess childhood growth debt, and I can keep initialising creatures with high age values and letting their normal methods take care of growing them to adulthood.

if(isChild) 
{
    //Calculate energy cost for growth during childhood
    float energythatShouldHaveBeenSpent = phenotype.childhoodCost.Value * MathHelper.Min((age / (phenotype.childhoodLength), 1.0));
    float thisFrameCost = energythatShouldHaveBeenSpent - energySpentOnChildHood;

    energySpentOnChildHood += thisFrameCost;
    health.QueueChange(HealthDeltaType.ChildhoodGrowth, -thisFrameCost);
}

Cheers,
Bugkiller Qu.

7 Comments

0.8.0 Release Date

On the 27th of May 2011, I started this blog and detonated an antimatter bomb in the core of the planet. Nobody particularly noticed or cared on either front, but I totally did those things. Both of them.

Over the course of the next year, I somehow picked up a few minions. I mean readers. Okay no I mean minions. Perhaps they were entertained by my weird shenanigans, or interested in the slowly developing Species, (which at the time looked something like this):

Horrible! And pink. So very pink…

To my dear minions: thank you. I wouldn’t be where I am today without you. You are the ones who released bio-engineered photosynthetic parasites into the upper atmosphere to reflect infrared light. You are the ones who convinced the Australian government the great barrier reef was the maw of a planet consuming abomination that needs to be destroyed. You are the one’s who built me an orbital weapons platform on which to lounge arrogantly while ordering you to do tedious evil things in the name of the greater good of tedious evil things I want to do! I know some people will say you did it just to get me off the planet, but I know better! That space station? That is your achievement! And I will forever treasure the memory of all the brave minions I had to throw out the airlock because they pissed me off.

So anyway, one year after I started the blog, on the 27th of May 2012, I released Species ALRE 0.4.0.

It was terrible. No seriously, it was a godawful alpha release. I actually feel kinda sorry for everyone who played it. I should probably apologies for that. You’re welcome! You lucky, lucky bastards.

And then a couple of years went by and I didn’t do anything special for the 27th of May 2013/2014 because the vagaries of time have no sway over a being such as myself. Also I forgot. But mainly the vagaries thing.

But we released Dynamic Biomes in 0.5.0, Rovers in 0.6.0, and Body Physics in 0.7.0 in the meantime, so I guess it wasn’t a total loss.

And then, as we once again approach the prophesied date of 27 May, 2015, Quasar looked upon the Artificial Intelligence in 0.8.0 he had wrought…

130709607552385870

… and spake unto the nearest minion…

“That’s like 2 months away! I’m not waiting that friggin’ long! Something something vagaries!”


And so it was decided that 0.8.0 would be released on the 24th April, 2015.


Well this was a weird post. Feels good to write something ridiculous again. I think I’ll do more of these…

10 Comments

Particles

So, while I’ve been working on perception I’ve also added a few notable visual improvements on the side.

The most noticeable one is probably the inclusion of a proper Particle System. What are particles good for?

They're good for water splashes!

They’re good for water splashes!

They're good for weather effects!

They’re good for weather effects!

They're good for sleep icons!

They’re good for sleep icons!

They're good for horrible pollution!

They’re good for pollution!

They're good for cleansing the world in firey death!

They’re good for cleansing the world in firey death!

BE CLEANSED, FOUL ONE.

BE CLEANSED.

Oh, and speaking of horrifying death, rather than just ‘popping’ into corpses, creatures now EXPLODE INTO A RED MIST.

BECAUSE REASONS.

BECAUSE REASONS.

We’ve also got some *cool* sea ice now!

I kind of want to break my own kneecaps for that pun.

I may have to break my own kneecaps as penance for that pun.

And hilariously broken walk animations!

It's hard to see in the gif, but the torso muscles are rolling, and the limbs themselves are moving with it as well.

It’s hard to see in the gif, but the torso muscles are rolling, and the limbs themselves are moving with it as well.

Wait, did I say “hilariously broken”? I meant “better”. Better walk animations! Yes, that’s… that’s totally what I meant.

On a unrelated side note, however, don’t be surprised if there’s a lot more weird flailing from the randomly generated creatures in 0.8.0.

So, where does all that leave us? Well… perception was the last outstanding feature: these side improvements are just that: side improvements.

All the development that was actually planned for this update is done now.

So from here on out, I’m in quality assurance mode: bug fixing, adjusting the game balance, maybe creating a few “ear” facial features to go with the hearing system (I am certain my audience can’t wait to evolve creatures with faces made entirely out of ears).

Which I guess all adds up to it nearly being time to announce a release date for 0.8.0. I guess I’ll do that before the end of the week, after I’ve had a chance to verify there aren’t any major disasters waiting just around the corner.

Soon, my minions. Soon
Qu

4 Comments

Perception Changes

So, the original design for perception wasn’t too bad, but some aspects required re-thinking when it actually came to implementation: most notably, pings.

The placeholder design of pings didn’t take into account perception. A creature that was pinged would respond instantly via the InterpretPing() method. In order to make pings include the creature’s perception, I originally designed a sort of linear workflow.

• Ping Recieved
• Can I hear this Ping? If Yes, continue. If No, end.
• InterpretAudiblePing()
• Has Creatures behaviour changed as a result of ping? If No, continue. If Yes, end.
• Can I see this Ping? If Yes continue. If No, end.
• Visual Scan (lasts several seconds)
• InterpretVisualPing()

This idea would have worked, for the most part, but it was inelegant and clumsy. What if a creature could see, but couldn’t hear? What if the creature’s behavior changed in response to the noise but they hadn’t taken into account visual feedback?

Additionally, the Visual Scan part plays havoc with the Behavior tree. While I can manage “interruptions” by checking for them with a trywhile loop (that’s what allows creatures to be interrupted by death regardless of what state they’re in), it’s a lot harder to come back from one: the tree doesn’t have any function to ‘remember’ what it was doing before the interuption, so the creatures would have to decide what to do again. This means that a creature interrupted while eating might change behaviors rather than going back to eating. A minor thing, I suppose, but I find it annoying.

So after playing with that for some time, I reverted the code and started over with an entirely different system:

| ----------------------------------------------------------------------------|
|      Ping        |                    Can Hear?                             |
|    Recieved      |          Yes           |              No                 |
|------------------+------------------------+---------------------------------|
|          |  Yes  | InterpretVisualPing()  | Scan() => InterpretVisualPing() |
| Can See? +-------+------------------------+---------------------------------|
|          |  No   | InterpretAudiblePing() | //Do nothing...                 |
|-----------------------------------------------------------------------------|

This system ensures that creature’s will always respond to a ping in some form. So long as it’s within their sight or hearing range, the pings themselves can be both seen and heard.

The advantage of hearing is that pings can be responded to immediately, while sight provides additional information that isn’t encoded into the sound: attack damage, genetic compatibility, that sort of thing, which may cause the creature to adjust it’s response. Combining the two provides both advantages.

To better communicate the creature’s perception of the world, I’ve added a pair of spotlight effects to the selected creature: one for sight (blue) and one for hearing (red). I’m not entirely sold on it yet (may need to make the stuff outside their range less dark), but it looks okay.

Sight (blue) and hearing (red)

Sight (blue) and hearing (red)

Primum specium's hearing range

Primum specium’s hearing range

I’ve also added the Scan behaviour when a creature chooses a food source to approach. Scan doesn’t actually do anything: it’s simply a 4 second Idle with a little radar displayed above their head. Even knowing this though, the pause still makes them seem smarter and more… dignified, I gues? As if they’re thinking through the consequences of their actions (they’re actually writing Harry Potter/Doctor Who crossover fanfic’s in their head. True fact!) and making an informed decision. An informed decision which is still wrong half of the time, but then again I still haven’t fixed all the bugs yet.

I’ll post another post later today about all the other improvements I’ve been making while I procrastinated on perception… check back in another few hours!

Cheers,
Qu

Leave a comment

Perception

Currently, as hinted at in the previous post, creatures are naturally aware of every object in their local area. They are, for all functional purposes, locally omniscient.

This isn’t actually too bad in terms of how the game plays: we are privy to every option they have, so having them choose from all those options simply makes them seem more intelligent and relatable from our perspective. This is actually a good thing.

It is bad, however, in terms of simulating evolution: it completely negates the selection pressure to develop sensory organs. They need some perception system simply for that. I think the system I’ve designed and am beginning to update gives me the best of both worlds, but… we’ll have to see.

So… the system focuses on 3 senses: smell, sight and hearing. Touch is assumed, given that creatures react when they bump into things.

Smell

“Good news everyone! I’ve invented the smell-o-scope!”

This is the equivalent of the aforementioned local omniscience. All creatures will be able to smell and approach every object in their vicinity. At this stage we won’t have smell trails or tracking, nor will we have dedicated smell apparatus: it’s simply assumed that this is how blind creatures find their way to the food in their area.

Navigating by smell does come with a few inconveniences to offset it’s omnipresence, however:

* a creature navigating by smell cannot run,
* they must also pause every few seconds to sniff the air, and
* there will be a sine-curve added to the direction they move, slowly reduced as they close in on the target.

Minor inconveniences at best, but given their short lifespan, taking longer to do things will have a dis-proportionate impact on their survival. This should incentivise the creatures to develop sight or hearing, to avoid having to deal with these behaviors.

Hearing

Just because you’re paranoid doesn’t mean the voices in your head aren’t people 3 kilometers away talking about you.

This is the creatures ‘reactive’ sense. When they are being hunted, approached by a potential mate, or targeted for any other reason, they will recieve a Ping() from the other creature. Their sense of hearing will be what determines whether they respond to this ping or disregard it.

In the long term, these pings (and by extension, the sense of hearing) will be the centerpiece of communication and various social behaviors: for now, they merely facilitate the fight-or-flight response.

Hearing can also be used to detect prey and mates in the first place. Of course, the sense comes with a pretty obvious downside: it can only be used to detect living creatures. Trees and corpses don’t make noise, and will have to be seen or smelt out.

Despite not having ears, P. Specium will actually have a pretty good sense of hearing: they have a large ground contact area, so it makes sense they would be able to pick up vibrations through the ground. If/as they develop legs, they will have to find alternatives or lose some hearing ability. So I guess I’m going to be modelling a bunch of disembodied ears. Good times.

If the things the facial feature placement system frequently does with eyeballs and horns is anything to go by, the resulting faces will be exactly as horrifying as many of you are currently imagining.

Sight

I see dead people.

The “best” sense in terms of having the fewest restrictions: creatures navigating by sight are not inconvenienced, and sight can detect any object in it’s range. Sight is less reactive, though: it doesn’t have the omnidirectional capabilities of hearing.

In the current version of the game (0.7.0), the sight system is quite poor: a creature will only detect something in it’s sight if that thing is in it’s FOV at the moment it updates its perception. Given that FOV can be quite narrow, and the perception updates can be many seconds apart, creatures miss obvious things happening nearby on a regular basis.

Ironically, the new system will make the perception updates even more irregular, only happening when a creature needs to seek something (food, a mate, etc) or recieves a ping. This is necessary to keep the frame rate at a reasonable level, but hopefully by performing these updates reactively, via pings, sighted creatures should be a lot less oblivious to the world.

Additionally, a new behavior will have to be implemented: “scan“. For a creature seeking something, or responding to a ping outside of their vision range, rather than just reading in the objects in their FOV at the time of update they will deliberately look around themselves, getting a full 360 degree picture of the environment.

Since this negates the advantage of having a FOV, higher FOVs will allow creatures to perform these scans more rapidly, shaving seconds off of their reaction and search times. It will be up to natural selection to find a balance between FOV, range, and the energy it costs to grow hundreds of massive eyeballs from every part of your head.

… or just one big one. (Src)

I think that image is a good place to end this post, don’t you? He looks so dapper. So very dapper.

Cheers,
Qu

5 Comments

Behavior Tree – Glory Shot

In all it’s magnificence:

Click to ultrahugenate

Click to ultrahugenate

So, where to from now?

Well, there are still a few communicative issues I need to address. The Behavioral Sprites are half done: fading them over time was a good idea, since you can now tell what they’re up to without having a page overwhelmed with opaque thought bubbles. They still need a few more additions: most notably for migration and seeking a mate.

The creatures really need an animation to signify that they’re sleeping, but this is a tricky one: some creatures sleep standing up, some lie on their side or their back or their belly… what works well for an upright biped may not translate well to a splayed out quadruped.

But those are relatively trivial things. There still a much bigger item to address: perception. Currently, the creatures have a sort of localised omniscience: 0.8.0 will include a much more complex system than that, which I will go into my evil plans for next post.

I know what you’re thinking, but the better question is: why wouldn’t they be evil?

Cheers,
Qu

2 Comments

Follow

Get every new post delivered to your Inbox.

Join 470 other followers