Archive for category Game Development

Another Bug Post

I was originally going to post this as a forum post, because it’s basically just an enormous wall-o-text, but I decided what the hell you only live once. And then you die. Like everyone else. So before you die, you might as well waste a few minutes you can never get back reading this wall-o-text.

Playtesting 0.8.0 has revealed some bugs: thankfully not major, crash-inducing ones. They’re mostly problems with longer-term simulations.

I tried tracking down the two major ones this morning (over-reliance on carnivory and species-count becoming desynchonised from the creatures) and failed miserably. Couldn’t reproduce the latter at all, and the former is just plain odd.

It doesn’t seem to be an energy leak bug: creature’s can’t survive if you kill *all* the plant matter, which is a good sign. But they *can* survive extraordinarily well on a very small amount of food.

I think I’ve got an idea, though: I’m starting to think this might be a recycling issue related to the way biomass is handled.

When a creature eats a plant, the amount of energy it consumes is constant, but then other factors kick in (the creature’s diet, the plants efficiency, global efficiency if it worked properly, etc) to reduce the amount of usable energy that is actually added to the energy bar.

The unusable energy is added to the creature’s biomass value, which is little more than a storage space, keeping track of the energy that the creature has consumed during it’s lifetime. When it dies, biomass (along with any leftover health or energy) becomes delicious meat.

Meat is a more efficient food source. You might be able to see where I’m going with this.

Whether a herbivore or a carnivore eats the plant, the same amount of energy is introduced to the population. Even a near-carnivore will eat plants in an emergency, and even though the individual might not be able to make use of the biomass it picks up, it’s pure-carnivore siblings can when it dies. So the population ends up relying on these omnivorous mutants to bring energy into the system. And of course, unlike a herbivorous population, when each of these carnivores dies they can be fed on in turn by their siblings, resulting in an incredibly efficient survival strategy that requires far less energy input overall. It’s quite elegant, actually.

Alright, that’s enough admiring the enemy, what can we do about it (assuming that huge steaming pile of extrapolation was at all accurate)?

My first inclination is to reduce the meat efficiency. But that doesn’t actually stop the energy from being introduced to the population: it just means it has to go through more creatures to be usable. Plus it makes carnivory less likely. The problem isn’t carnivory so much as so efficiently recycling the incoming energy.

The large total plant energy is what caused the problem in the first place, so I could reduce that. I’d need to increase the efficiency of herbivory to compensate: the end result would be that eating plants would add substantially less biomass.

Or efficiency could actually influence the total amount of energy that’s added: rather than having a constant increase and divvying it up between biomass and energy. But functionally, that’s pretty much the same as reducing planet energy content as mentioned above, since they’re the things with the low efficiency.

Or… well, I could finally accept the fact that the biomass value isn’t hammerspace and rework it somewhat.

Honestly, I’ve been treating biomass wrong for a long time. It was originally a way to ensure the conservation of energy, but a potential storage of infinite meat on every creature is quite frankly rediculous and unrealistic.

So, how to fix?

In real life, edible biomass *isn’t* simply unused energy: that only applies to fat stores, and those are just a tiny fraction of the creature’s edible meatiness. It’s structural: muscles, flesh, etc. It’s correlated with mass. And unused or unusable food isn’t stored forever as fat stores, either: it’s expelled.

So, the sensible way to fix this might actually be a deliberately introduced energy leak. Sort of like Decay, only happening while creatures are alive. It’d work something like this:

Creatures gain biomass normally up to a set point (perhaps their childhoodCost (to represent structural biomass) plus a percentage of their mass (fat stores)), after which it leaks out over time (possibly even providing a minor energy boost as it does so). It would have to leak exponentially faster the higher it went, to prevent a creature capable of rapid consumption from outpacing the energy leak indefinately simply by gathering food.

This would put a limit on the amount of meat a single creature could provide, meaning that carnivores eating a particularly bountiful meat pile would get a much smaller meal: enough to produce one or two children, rather than dozens.

Hopefully, that should put a spanner in the works of the current dominant survival strategy.

We’ll see…

Qu

Advertisements

3 Comments

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

Still working on Torques

Hello my totally-not-expedible minions!

Finally feel like I’m getting somewhere with these torques, so I thought I’d share a bit of the pain and frustration fun times!

I gave in and repurposed the debug text routine to draw the actual values of torques to the screen so I could debug them. I wasn’t sure whether the actual calculated values were wrong, or just the display arrows.

Turns out, both were: the calculated values were wrong, and the display arrows were not even reflecting them accurately. So I’ve stopped looking for a quick fix and am stepping through the code as best I can, fixing things as I go.

I think I’ve found the first major problem: it’s a bit hard to explain, so I’ll diagram it:

And now everything makes sense forever.

And now everything makes sense forever.

The short version is that in order to calculate torque I need to calculate both distance and magnitude perpendicular to the bone. If they were parallel, then there would be no torque and the bone would face compressive forces instead.

The problem is that by crossing the Force’s Normalised Magnitude Vector with the Bone Rotation, we introduce it’s *direction* into the equation. Then later on we calculate the Dot Product of that and the Forces full magnitude vector, multiplying it’s direction a second time and resulting in a torque going the wrong way.

If you’re by some miracle still following, then a) you have a better attention span than me and b) I’ll probably fix this by removing the final Dot product: just multiply cross2 by the force length and call it a day.

And then I can finally get to work on why the display arrows are crap.

Cheers!
Qu

* * * * *

PS: The Orbital EMP Cannon is down again. We sent an investigation party, and they reported that the living quarters are for some reason highly radioactive and not fit for human habitation. They also said something about millions of spiders before descending into incoherent and extremely uninformative screaming.

I’m sure they’re fine.

We’re now taking volunteers for the cleanup party. Biohazard suits and flamethrowers will be provided.

, , , , ,

3 Comments