Archive for category Species

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

,

1 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

Neck Improvements

Neck rotations have been implemented in the development version for a while: they give creatures a genetic “head rotation”, allowing them to hold their necks to angles other than horisontal by default. But we’ve upgraded it a bit further in the last month or so…

130531275237835909

Mobile necks. Creature’s with necks will attempt to rotate them to bring their head to the same height as whatever they’re targeting.

130531274980131169

In addition, I re-exported the neck model to fix the neck-through-head bug. Fare-thee-well hideous head-impaling neck-tongues. You will not be missed.

PS: I stumbled on this fellow whilst experimenting with the random generation. Looked too neat not to share.

130530407154504137

4 Comments

Droop

I’ve been working on applying torques to the creatures in a meaningful and well thought out manner (read: banging my head against the keyboard whilst trying to fix all the horrible signage errors). The original intention was to simply pass the torques on to the energy system and let natural selection weed out the unbalanced and physically impossible specimens. But I realised I have the perfect opportunity to overhaul a system that has bothered me since its inception: the quadruped system.

Logically, if a creature has slightly smaller front limbs than back limbs, it should lean forward in order to walk on them (unless it’s a pangolin, but they’re too awesome to be swayed by our petty logic).

Throw logic out and do the impossible, that’s the way pangolin’s roll

Without something to enforce this, every creature in Species ALRE would be a biped, because every creature has at least a *slightly* different leg size.

The quadruped system governs how this is implemented. A hideously simplified description would be “if the torso rotation is less than 45 degrees, and it has fore or back legs, the creature will fall forward onto its front legs or chest. If it’s higher than 45 degrees, or it has mid-legs, it will remain bipedal.”

That “45 degrees” is completely arbitrary. It’s just a value I picked.

This system is why ‘head-down butt-up’ creatures, whose bodies hang forward from their back legs are so common: Any creature with large back legs and a small torso rotation will end up with this body plan.

That’s the old system. The new one is much more sophisticated.

It starts by completely eliminating the quadruped system: creatures will initially be created *exactly* as their genes would have them (ie. with only one pair of their legs reaching the ground). It then calculates the skeleton and torques as normal.

Once that’s done, it passes control to the droop system. This applies “droops” to every body part attached to the torso: limbs, neck and tail. Legs are bent upwards by the reaction force on their legs, neck and tail are bent downwards, and the torso droops based on the creature’s balance, all in direct proportion to the torque applied on the joints.

If a body part droops into the ground, it stops drooping and adds a ground contact point, which will take some of the creatures weight in the next step.

Then pass 2 starts, the body-plan is completely reinitialised: bones are regenerated, torques and forces are recalculated. The results of pass 2 are what the creature will ultimately use for most of it’s energy calculations, so as to take advantage of the creature new quadrupedal body plan. (physical droops will affect energy, but proportionally to how much they rotate rather than as a function of torque. Small drops onto legs will be a negligible cost)

This also has a noticeable effect on creature appearances. I haven’t adjusted the rotation genes at all in the following screenshot: these variations are entirely the result of torso, neck and tail thickness changes causing different torques in the creature’s body plan.

OH GOD FAT SPIDERS

OH GOD FAT SPIDERS

One particularly noticeable change is that the creatures tail now has an effect: increasing its mass is the only way to counter the torque produced by the head and neck in the second body plan. For bipeds with centrally situated legs (raptor-like creatures), a sizable tail will be the only way to maintain balance (other than having an upright torso rotation gene and incurring a large energy cost in droop).

I’m hoping this system will be realistic enough to promote life-like body plans in place of a real-time physics system, which would be far too CPU intensive to implement across thousands of creatures. More likely, it will be exploited ruthlessly in ways I can’t yet imagine. But hey, that’s what makes it fun!

Cheers!
Quasar

“Anime references. There goes the neigbourhood”

, , , , , ,

3 Comments

Rover AI Feature Creep

I played with the Rover UI while I working out exactly how I was going to apply the (now completed and working) torques to the creatures in a realistic fashion. This led to the following thought processes, presented in conversational format for readability and not because I pay heed to the voices in my head. Because I don’t. I am sane.

“I promised to do thing X with the rover AI for 0.7.0, but with the upgrades to the code it should be possible to make it do interesting things Y and Z as well. But there are a variety of sensible, practical reasons to leave those for a later version so I can get 0.7.0 out earlier. I would have to be completely insane to distract myself with additional feature creep at this point in time.”
“I make a very sensible point. Does the opposition wish to provide a counter argument?”
“DOOOIIITNAAAAAOOOOOOWW!!!”
“Yes! Now! THIS IS A PERFECTLY RATIONAL AND SANE DECISION!”

So, umm… this (click for full size if you can’t read it):

RoverUI

In addition to the promised “creatures with genetic distance to” option, we’ve now got “trees with high/low stat”, (this should be helpful for encouraging reforestation), “Species” will be good for cladogram pruning (I’d also like to add a “plus descendants” option, since it’s hardly a proper genocide if the Rovers ignore branches of the species), and most importantly, “Population when total creature count is higher/lower than” will be great for controlling population explosions and preventing mass extinctions.

It’s already mostly implemented, so this hasn’t set me back too far.

You’ll also notice that the Rovers now have randomly-chosen names. This was another small, unplanned feature. It has absolutely no effect on gameplay, and some of the names are a bit silly, but overall I’m quite happy with the addition. It gives the game as a whole a tiny bit more personality than before.

Still sane!
Qu

– – – – –

“It gets harder to not talk to yourself when there’s so many of you.”

, , ,

1 Comment

Progress Report for 0.7.0

Some of the things of which I have been the doing… (that’s totally a sentence and anyone who says otherwise will be EMP’d)

Rover AI

Rather than just adding an option to allow rovers to prioritise differently, I completely overhauled their AI. It does the same stuff as before, but in a much more versatile, object-oriented manner which will allow:
– Task queue. Allows for sequential tasks, waypoints, and 2-part actions like move and gene splice.
– Arbitrary targets. Rovers can now target anything with the “Entity” base class, which includes trees, fence posts, devices, other rovers…
– Arbitrary actions. They can now call any method in the game when they reach their target, rather than just picking through a predefined library (feed/kill in 0.6.0))
– Arbitrary prioritiser. The system for choosing which entity next merits their attention is now versatile enough to support any prioritisation method, rather than just picking highest/lowest statistics.

To test the system I added a routine that appends a “DoNothing” task tied to the camera entity. The rover finishes murdering whatever they were murdering, then comes to the camera, says hi, then runs off again on its eternal killing spree. It’s adorable.

I then implemented the UI for Targeted Rover Programming (would it be tacky to shorten that to ‘Rogramming’?).

New Rover UI

It’s not quite as user-friendly as it was, but it’s capable of a lot more. And it was really easy to hook into the aforementioned AI system! Configuring the UI itself, on the other hand… let’s just say the UI code rather desperately needs a cleanup.

The end result? I targeted Primum Specium and let 4 rovers get to work on a randomly generated species…

I'm meeeeltiiingg...

I’m meeeeltiiingg…

This “forced devolution” sequence took about 2 in-game hours, (12 minutes at 10x). I had to switch them from killing to feeding a few times to keep them from driving the creatures to extinction, and I learned something in the attempt: it seems that selectively killing a large, thriving population is a much more effective way to apply selection pressure than selectively feeding a small, struggling one. There was a different population that caught the attention of the feeders, but ultimately they were incapable of surviving even with assistance.

There will be a major change to the game as a result of this feature: the Creature Editor which has been an unofficial part of the game since 0.4.1 will enter the game officially as a means of creating your own selection targets for your rovers. You won’t be able to use it as a creature generator: designed creatures will appear in the export list as “Genome Only”.

Finally, another potential major change: this rover AI system marks the beginning of the end for the godhand tools. The goal has always been indirect gameplay, and replacing the direct “Feed” button with a way to give the rovers that command is a step in that direction (plus it steers the game away from god games like Black and White).

It should also work well with a few planned changes to the UI (not for this update, but later): rather than “Select Mode”/“Select Tool”/”Click Target”, I’m thinking of a more context sensitive “Select Target/”Click Tool”, where the mode is determined by the target. So you’ll get different tools if you’ve got a creature selected than if you’ve got a rover or a tree selected. Such a system should be more extensible for things like group selections, as well as easier to use.

Climate devices

Climate Devices

Placeholder models, but they work! They look a bit odd in 10x speed though: the optimisation that causes the biomes around forests to ‘pulse’ causes the same effect from the climate devices, except even more noticeable. I may have to work out a solution for that problem, but initial results are promising: it should now be possible to keep creatures alive on a glacial map without simply changing the global temperature.

They’ll need a UI too, though: at the moment I’m just generating them with the “G” key. Once more unto the breach!

Torques

I’ve got all the forces in play, including reaction forces, but the 3d torque calculations are still giving me trouble. Can’t work out why the tail torque is backwards. Heck, I can’t work out whether the tail torque is backwards: it’s possible that my display arrows are the things that are backwards. I’ll get there eventually.

Overall progress report!

• Mutation Map Editor: 100% done. Just need to get around to actually using it for new content.
• Fences: 90% done. A few bugs to fix, mostly AI related: creature’s need to ignore objects on the other side, and rovers need to path around.
• Targeted Rovergramming: 90% done. Some minor cleanup and bugfixes.
• Skeletal Analysis. 75% done. Slowly getting there, but the aformentioned torques are still giving me Fun.
• Physical Values: 70% done. Volume is defined, and Mass is calculated from a placeholder value for density. Should be easy to hook in the material system, which is being developed off to the side, when it’s ready (no idea when, but not for 0.7.0).
• Metric Units. 70% done. Same as “Physical Values” because they’re effectively the same thing Comes with volume and density. Not in genes, so conversion is performed in BodyPlan and fed through to the boneses.
• Climate Devices. 40% done. Mainly I just need to make a UI for them.
• Animation. Not started. If anything, my forays into step-size adjustment have just introduced more problems.

Overall? Hard to say: some of these jobs are ginormous (Skeletal analysis is taking a lot of time) while others are tiny (Climate Devices were surprisingly easy to tie into the existing system), plus I keep coming up with new things to add or overhaul.

We’re definately past the halfway point, though.

Cheers!
Qu.

, , , , ,

3 Comments

Torque Screenshot

Screenshot…

Torques

Comments:

– Darker, linear arrows are Bones.
– Brighter, circular arrows are torques.
– Torque display arrows scale with torque magnitude.
– Torque Colour matches Bone colour (the orange torque goes with the dark-orange bone, which is the neck)
– Compressive and tensile forces are not displayed (though they *are* calculated).
– The creature was animating when this screenshot was taken, which is why the bones don’t match the leg.
– Torques are only calculated with Mass: reaction forces are not yet accounted for. Imagine the creature hanging from a string wound around it’s torso: those are the forces you see here.
– I’m not doing all this visualisation just for debugging: I intend to include the skeletal view (cleaned up, of course) in the final release.

, ,

2 Comments