I forgot to charge my laptop yesterday so used the forced break to practice my sketching, but I’m back in it today and development continues.
The Mutation Map tool now has the ability to view and edit both the overall map and the individual stats of each head. It can also do the same for Feet, and I’m working on getting the remaining mutation maps (Limbs, Coverings, Colour Patterns, Feature Models and Feature Textures) into the tool. Hope to be done by the end of the week and moving on to other things, though that may be a bit optimistic.
Also took some time to begin taking my Stat encapsulation to the next level. Currently we have 6 types of Stat:
- GeneticStats encapsulate a mutation rate, plus mutate, randomise and blank routines, for every gene.
- FloatingGeneticStat: A hereditable decimal number, like “torsoWidth” or “headSize”. Encapsulates an upper limit and lower limit in addition to the mutation rate.
- DiscreetGeneticStat: A hereditable integer number, like “numberOfFeatures”. Just encapsulates the mutation rate.
- BooleanGeneticStat: A hereditable yes/no value, like “hasTail” or “hasNeck”. Just the mutation rate again.
- MappedGeneticStat: A stat with a mutation map, like “headType” or “bodyCovering”. Encapsulates the entire mutation map structure.
- BasalStat: a non-hereditable stat which is imported from an external file, linked to a MappedGeneticStat. Like how HeadType determines Diet, or how LimbTipType determines BaseLimbDamage. These stats are rarely used directly: usually, they feed into formulas to determine other stats. (diet is an exception)
- UpdatableAttribute: a type of Stat I have encapsulated but haven’t derived from IStat yet: these are things like Health, Energy and Biomass, which change over the course of a creature’s life. Encapsulates a list of “Deltas”, making it possible to track the source of changes to these stats (you can see these deltas listed out on the energy page in creature details).
There’s only one major type of stat still missing, at least on a per-creature level:
- DerivedStat: Any stat which calculates itself from other stats. For instance, Speed takes into account LimbSize, LimbBaseSpeed, TorsoWidth, TorsoRotation, LimbTipBaseSpeed, and so on. DerivedStat will encapsulate all these stats, plus the formula used to combine them.
The method I’m using to encapsulate the formula uses something I haven’t spent much time with in the past: delegates. I’m storing it the entire formula as a delegate inside the DerivedStat instance. This means I get to define the formula in StatData, but still use the built-in accessors of the objects, so I get the same intellisense benefits and high performance as if I was defining the calculation over in Phenotype.
The result looks like this:
"Mass", //Printable Name
"Determines how much stuff there is in the thing", //Printable Description
delegate(Genome genome, BodyPlan bodyPlan, Phenotype phenotype) //boring code stuff
return bodyplan.Volume * genome.Skin.Density; //Formula
The relevant bit is the second-last line: that’s the only place that formula needs to be defined. All I have to do later is call Initialise, and the DerivedStat takes care of calculating itself on behalf of it’s parent creature, pulling other stats in and combining them, as well as throwing errors if stats haven’t been correctly initialised.
Yes yes, making with the boring and the code and the words and the stuff, so what? Why do we care?
Here’s why we care: every calculation, limit and mutation rate from the raw genes to attributes like speed and stamina is now stored in StatData. This one file is becoming the spinal column of a lot of the simulation’s behaviour, so tweaking mutation rates, adding limits, changing names and descriptions, and now adjusting stat formula will all be possible simply by changing the input data here.
And I intend to expose that input data to modding.
Cue the maniacal laughter,
I really should have done this sooner.
It’s a graphical representation of the head type mutation map. Took me half a week to make, and it’s already showing me a number of interesting defects in the map. There’s one in the screenshot above: see if you can spot it.
If you’re wondering where that particular head should be, you can see it’s originally intended location here:
The reason for these defects is simple: so far I’ve had to build this entire map textually, with nothing to go on but the names. That’s the “Gen3C”, “Gen4CaA” and “Gen5CcAAA”. The abstract naming scheme was designed to make it easier to connect them up without being able to see them, and without making mistakes. Guess it didn’t work as well as I’d hoped.
This tool should fix that little problem by allowing me to see what I’m doing. In fact, I’m considering taking it a step further and allowing me to edit the map directly from this window.
Also, I know 0.6.1 had a smaller Content to Time-Spent ratio than previous updates. This was because I spent half my time on cleanup, rather than new features. I justified this by telling myself it would make development faster in the long run. Turns out I was right! This simple tool would have taken at least a few weeks without being able to reuse the DrawableHead class, and the fancy MutationMap classes I made for the Mod Maker all the way back in 0.4.1.
I’ve been meaning to start doing these for a while! Some of the video’s and let’s plays of Species are interesting, amusing, or (in this particular instance), horrifying.
Todays spotlight: xtomass sets the mutation rate to 4x and evolves horrifying 15-meter tall monstrosities.
I choose to believe that they are merely the 3-dimensional appendages of vast, interdimensional organisms the size of a planet. Yep, those shots from the ground level FPS camera are gonna haunt my nightmares.
I like xtomass’ style: he’s enthusiastic and easy to listen to. Give his channel a look!
Welp, we finally managed to track down the Black Ground bug, by means of Google research and an Ouija board. Turns out AMD cards can’t use a 2.0 vertex shader model in the same pass as a 3.0 pixel shader model, but rather than doing something sensible like, I dunno, telling me about it, instead it adopts the much more interesting approach of falling over randomly and not drawing anything.
Fixing this meant adjusting a whole bunch of shader files, and I lost track of which ones had been modified somewhere along the way, so to get the hotfix you’ll need to re-download the game. If you extract the files into your existing Species folder and merge/overwrite, you should be able to keep your save games and exported creatures.
Also made a few small tweaks and fixed one of the more common exceptions. Potentially-stable release ahoy!
- Fixed the Black Ground/Invisible Creatures issue people with AMD cards were experiencing.
- Fixed the ArgumentOutOfRangeException that was causing crashes after an unspecified period of time.
- Tweaked Body Pitch so creature’s don’t lean back as much as a result of growing legs
- Tweaked CalculateReach so creature’s can’t increase their reach by having a not-expressed neck length.
The 0.6.1 release went reasonably well: we managed to track down and fix most reported bugs, and the game now appears to be reasonably stable. There is, however, one remaining bug, and it’s rather major: on a number of AMD graphics cards, the shaders responsible for drawing the creatures and terrain are not working.
Other programmers get bugs that result in exceptions. I get bugs that result in unseen creatures drifting silently through a world of infinite darkness. I love my job.
Nonetheless, this is a frustrating bug. Since Google is turning up nothing, I have no elegant fix for it (a small number of people reporting similar problems with AMD cards on other games, and that’s about it). Since I don’t have a computer with an AMD Card in it, I can’t even go for the inelegant fix for it (namely, continually keep tweaking random stuff until the damn thing works).
My current plan is to create a suite of non-functional shaders, each commenting out or otherwise reducing a different section of the original shader, then distributing these to people with the bug to try out. If we can narrow down what it is specifically that the AMD cards have trouble with, we might be able to work around this issue.
While trying to find that solution, I’ve been further developing my new Stat Control System. It’s actually the first time I’ve been genuinely proud not just of what the game does, but of how it does it. The code behind this new system is a pleasure to work with, and it realises a dream I’ve had for for a while: a centralised, decoupled stat library.
The ultimate goal of this particular piece of work is to extract every creature stat in the game into a central StatData class, which defines all their common characteristics. This includes things like a Printable Name and Description for the UI’s benefit, as well as mutation rate (for genetic stats), upper and lower limits, where to find them in external files (for base stats), and so on.
"Limb Type", //Printable Name
"The shape of the limb.", //Description
1f / 40f); //Mutation Rate
"Limb Tricep Width", //Printable Name
"The cross sectional radius of the limb's upper bone.", //Description
0.6f, //Mutation Rate
0.01f, //Lower Limit
float.MaxValue); //Upper Limit
The way it’s implemented imposes certain restrictions: for instance, I am no longer able to bias the mutation direction for any stat. I wasn’t doing this anyway (well, not deliberately. People who were with us back in 0.4.1 will remember the fat-bug which caused creatures to swell progressively larger until they became crippled by their own weight and died out), but now the compiler will make it physically impossible. Mutations must be random.
A huge bonus of the way it’s implemented is that it’s no longer necessary to hard code stat properties. I still have to hard code their usage and implementation (softening those is stage 2), but all of the properties I mentioned above could easily be extracted to an editable file. Want to triple the mutation rate for leg size? Edit the file! Re-enable negative tail lengths? Edit the file! Translate the UI into ancient Sumerian? File!
As always with cleanup tasks, though, the real advantage will come in making it an order of magnitude faster to add, remove and tweak things in the future.
I’ve also been doing some design work. I’ve decided, rather than just progressively improving the stat calculations for 0.7.0, I’m going to rewrite them as a low level physics engine. The result will work like this:
Each body part will have a given mass and a pivot. A few simple engineering calculations later, we have a linear force and a torque for that pivot. (okay, technically we’re treating the creature as a static mechanism so the proper term is “moment”, but torque’s easier). The linear force will propagate from leaf bones like the head towards the ground contacts, so torque on the neck pivot will come from both head mass and neck mass.
The Passive Strength of the pivot will come from cross-sectional area, and will determine how much torque it can handle. If torque exceeds Passive Strength, the joint will “droop” and the creature will need to continually expend energy on it to compensate. Creatures will need to find their own balance between Passive Strength and Growth Cost for each joint.
My hope is that this bottom-up approach will pay off as creature’s grow more complex. It would be awesome to see stuff from biophysics appearing as emergent properties of the simuation.
Finally, my real life has recently been a little more interesting than usual, and my free time has dropped significantly. I haven’t even had time to feed my swarm of carnivorous nano-squid, let alone reconfigure the Orbital EMP Cannon to deploy them upon the hapless citizens of earth.
It hasn’t had any effect on actual development since I have dedicated time for that, but it’s made it impossible to pay as much attention to spreading the word about the 0.6.1 release as I would have liked. Yeesh, the front page of the website still has 0.6.0 screenshots: that’s how busy it’s been.
Hopefully the event responsible for this will come to a close in the next month or so, and I can get back to the important things in life. Like swarms of carnivorous nano-squid.
We’ve been busily hotfixing since the release, and 0.6.1 is now much more stable than when it was first released. We recommend downloading the entire thing again:
(Tip: if you extract the latest version directly over the top of the previous one, you won’t lose any of your saved worlds or exported creatures!).
… but if you’re an advanced user and don’t want to download the full 75MB again, you can download the patches. Make sure you apply them in order.