Latest mod updates
Latest official blog posts
Source control is amazing.
6th May 2021Do you ever get the feeling that work on your video game is coming along to slowly? It seems I've spent the last month slogging through issues and bugs that come up as I make progress toward a cohesive game.
Why isn't that object drawing it's selection when selected?
Why did that animation just hiccup?
Why is no one picking up rocks that are close to trees?
Why is the there still a random crash while background loading!? (I already 'fixed' that once.)
But that's okay - it's good to fix bugs when encountered rather than let them slide. Despite code refactors and bug fixes, it feels like I'm coming up to a critical mass of systems and the game will come together into something.... soon...
I feel like I just have more done, but maybe not? When I started Banished I had nothing, and spent 10 months working before I had the game in a playable form. This time around I've been extending the game engine, and laying foundation for something that's better to work with, and will hopefully be just as fun.
On a totally different note, I had a pretty amazing experience with source control that I haven't had before. That sounds silly to type. But having access to all the revisions of code I've written in the last 10 years is pretty amazing.
First, some background.
I've had a desire to move some code into data. The situation is how villagers will interact with objects. It comes down to a simple list of actions. Walk to some location, play an animation, add something to inventory, create this other object, play a sound, spawn an effect, etc. For each thing in the world that can be used, this needs to be defined in some way. In the last game, there were just a specific set of these written for specific categories of objects, but in general they were shared heavily. But this time around I want the option of more variety. If I want sparks to fly when hitting a certain type of rock with a hammer, which might start a nearby tree on fire, I don't want to have to write specific C++ code for that. If the rock is huge and you need explosives to break it up before using it, I don't want to have to specifically write that in the game code either.
So instead, what I want is the engine to provide the simple actions, CreateEntity, AddInventory, WalkTo, PlayAnimation, etc. And per object in the world, I wanted to be able to chain them together to allow unique behaviors.
I could have built it with my existing serialization system, (which looks something like JSON) but it would have looked ugly and verbose, been hard to use, and difficult to debug.
And so I recovered my scripting code that I deleted over a year ago from source control. I'm pretty sure this is the first time I've brought code back such a large amount of code that I deleted and found it useful in another manner. Amazing! And I started hacking it up. Mostly by simplifying and removing lots of features. And in two days, I had a functioning script system that could tie the actions together and use simple stack variables. And it has a debugger! Two days! Yay!
For a simple interact where a character is idling, it looks like this:
Plan idleInteract
{
Sequence()
{
// load values for where we are going
// @self is the villager
// @interact is the object being used
LoadInteractIndex(@interact0, @int0)
LoadInteractTransform(@self, @interact0, @int0, @transform0)
LoadInteractAnimation(@self, @interact0, "IdleInteract", @animation0)
// walk to and idle
WalkTo(@self, @transform0)
TurnTo(@self, @transform0)
PlayAnimation(@self, @animation0, Length, 0.0)
// finished using this interact, someone else can have a turn
Interact(@self, @interact0, @int0)
}
}
To extend the script, all I have to do is write a simple C++ class that exposes the action and its parameters. The script compiler uses the C++ class and its serialization function to properly parse and use the action. It's not the fanciest thing or the easiest thing to read, but it's functional and gets me where I'm going. (Is it bad that I feel like I'm writing assembly code but the instructions are more than 3 letters long and the registers are named nicely?) It's a nice step toward being able to make new objects in the game without having them hard coded.
It's a nice feeling to delete all the C++ code that was previously used to setup actions. It was far more verbose as it had to include a lot of error checking, and fetching of commonly used data.
What's also nice about the format of the script, is there is a new parser for reading objects from text. Since each line represents the data in a C++ class, I can shorten what I type depending on the object. Normally an item that is stored in inventory might look like this:
Item granite
{
Category _category = "Stone";
int32 _volume = 2;
LocalizedText _name = "[email protected]:objects";
}
But with this new parsing format it can be shortened to a terse line like this:
Item("Stone", 2, "[email protected]:objects");
Granted the former format allows for fields to be omitted and be in any order, while the latter requires all fields in a specific order.
I have a few places in data where this would be more readable and friendly so I'll change them when editing the data gets frustrating. With a simple change of adding the name of the field back in, like so:
ImageElement(_sprite = "[email protected]", _color = 0xFFFF00FF);
I'll be able to omit unneeded fields and supply them in any order.
I think my user interface data will benefit from it, and it should take very little work to turn the mess of UI layout I have now into something more friendly. Maybe. I'm always having these idea that end up being slightly more work than I think. But that's for later.
Anyway, Thanks, source control system.
Development Toys
15th March 2021When I decided to make Banished, one of my main requirements was a definite 'NO ANIMATION'! Well, at least as little animation as possible. The idea of modeling, rigging, keyframing, and adding all the things required to have animations didn't seem very feasible for a graphics programmer turned indie developer. So for the first half of Banished, everything was buildings, terrain, and a box for characters that hopped around.
Eventually came a day where I added chickens. I modeled it, textured it, rigged it, and spent probably more than a few days figuring out how to animate it. After that it wasn't so bad. I built some simple humans an made it work. But rigging models, setting up I/K, setting keyframes, and trying to make nice animation wasn't my favorite thing. With time I'm sure I could have gotten better at it. But with so much to do building the game myself, it wasn't a priority.
For my current game, I'm going to need a lot more animation. I still don't want to keyframe everything. Potentially twice too, since this time I have different male/female skeletons. There's a lot of animations I want. A walk cycle holding each and every tool. Different animations for every tool and thing the villagers can do. Running. Sleeping. Ah! Maybe hire an animator?
But instead, I decided to buy some toys (er, tools). I purchased them so I can build a bigger game than before but not have a large increase in workload, and they're helping me overcome the skills I don't have.
So. I've been wanting one for a few years, and I am now the happy owner of an inertial motion capture suit. I put it on, it records my movements, and then I have animations. Yay!
But not all is easy in motion capture land. I've spent the last week or so building a pipeline that gets my animations into the game fast. I believe that traditionally, an animator would bring motion capture into another tool, modify it slightly to make it work in game, export that, and then bring it into a game engine. I want to just record and get that data into the game without a whole lot of extra work. Luckily, the motion data from the suit is very good. I don't have joints doing funny things very often. So there's not a lot of cleanup, if any at all.
The first technical thing to consider is that the animation is being re-targeted from my body structure, to whatever I've built for my characters.
Writing the re-targeting code wasn't as bad as I feared. I export a version of the skeleton of my characters in a T-pose that matches the basic configuration of the motion capture skeleton. This doesn't have to be the same way the character is modeled. The character could be in A-pose or N-pose or whatever, I just need to rotate bones into T-pose to match and export. Any transform differences are accounted for so I can map the rotation values from skeleton to skeleton. Then per bone I can pick which skeleton I want offset and rotation data from. I also had to write some code to move forward hip movement onto the root node which the engine needs, and reorient the entire model depending on which way it was facing in the motion capture data.
So once I mapped the motion data onto my skeletons, there are still a few issues. While the motion is good and follows how I've moved, based on arm length, leg length, hip width and shoulder width, the hands and feet don't end up exactly where I expect. In many cases this doesn't matter. But when it does, traditionally an animator would tweak the captured motion. But I'm going to use 2 bone inverse kinematics to place hands where they need to be when it matters. This also helps when interacting with objects. The same animation could be used to pick up different size objects and the I/K will put the hands in the right place. Feet sliding is taken care of by scaling the speed of forward movement based on the ratio between hip height in my characters skeleton and the hip height in the motion data.
The last issue is looping animations. In a walk cycle, the end pose needs to match the start pose. But it's really unlikely I'll actually match 100% by recording data. So I blend the beginning and end of the animation with the data on the other side of the loop. It's close anyway, and by blending a few frames together the loop looks perfect.
So after all that work was done, lots of testing and tweaking, I can now build animations fast. Put on the suit, record the motion I want, Then I scrub through the recorded data to find what I want and export it. My engine can read that exported data and a simple text file configuration tells the engine how to compile the animation for a character.
So does my recorded looping walk cycle look like? Not bad!
I think this is only the 2nd time I've modeled a human. I'm getting better at modeling. And rigging for motion capture was certainly an education. (Does anyone enjoy applying skinning weights to vertices?) The models are a work in progress, and I built them as fast as possible to test the mocap. They will likely be edited and different as time goes on. I hope to add hair options, different clothes, skin tone, etc. But for now these models will move the game development forward.
Another toy that deals with motion capture, are motion capture gloves for recording hand movement. Currently my models have mitten hands, but I want it for recording hand positions while holding tools or having palms facing out while the thumb does other things. This way I don't have to go into each animation and decide where the models will be gripping something versus having relaxed hands.
One cool thing about having the full hand motion capture data, is that I have full finger data, so if in the future I wanted to add the index finger, I'd just have to modify the models, and re-import the animation data. No other work needed.
Once I got it working, (which took most of a week) I made a bunch of test animations and got them into the game engine in around 40 minutes. That includes putting the suit on and setting up, recording motion, exporting to fbx, and configuring import frame ranges.
(Why is my shadow resolution so low in this screenshot? I was looking at the characters and didn't notice til after I made the gif. Hmm...)
I think I'm still going to need to traditionally animate animals, and I might hire someone for that. But I also now have an animation re-targeting pipeline, so all similar animals could potentially share animations, reducing the work required. Or at least I could get new animals in and working while animal specific animations get built.
The last toy (er, tool) I bought a digital screen drawing pad so that I can use a pen to paint textures and models directly on the screen. Previously I did everything with the mouse, and while that's fine and I have a workflow for it, being able to use a pen directly on a model is pretty nice. Plus maybe I'll get better at drawing too. I don't have any animated gifs to show that though...
Designing the AI
16th February 2021I like designing new code. Especially when I'm starting with a blank slate. I've got the initial framework for AI built now and am slowly testing ideas and fleshing it out. I went through several iterations of design, and I've ended up with something I think will work, and that can grow as the game does.
(The bad thing about new code is it generally doesn't come with screenshots or videos of cool things right away...)
Before designing anything, or writing any code, I went through a bit of time just writing down what I'd like the AI to do in the game. I'm going to list some of it here, plus some of my vision for what the game will be, but remember, game design is fluid and not all my ideas will necessarily end up in what I finish.
What I'm trying to explore this time is a colony simulation that is higher in detail than Banished, with a smaller set of villagers. This includes things like beds to sleep in, each villager owning equipment that's stored somewhere, and having skills unique to each citizen that are needed to make the village work. I'd like to slow down the simulation to days, including time to sleep, rest, work, and join in town festivities, like weddings or annual celebrations.
So here are some things I'd like to see.
Let's say a villager wants to paint her stone house white. But she doesn't have a painting skill. So she'll let the village know what she wants. If there's a painter in the village, he'll do the job, but there might not be paint. So he'll let the village know there's a need for paint. The worker that makes paint gets to work gathering limestone, or white clay, or white flowers, or whatever it ends up being ingredients. He'll make the paint. The painter will later grab it, and paint the house. And if I want the complication, a tool maker needs to make a paint brush first using animal hair and wood. And the animal hair comes from... etc, etc. And then the first villager gets what she wants.
The main idea there is that if you've got the production line and workers setup, the player won't have to manage turning things on and off, or setting limits. The village will just do it as needed. But the player will have the option of specifying that they want to drive production of a certain resource on purpose.
I'd also like to see group activities. There might be large bison-like animals that take more than one hunter take down. So the villagers need to get organized somehow, and then all follow the same plan to get close to one and attack at the same time.
Lastly I want smarter villagers. If you've directed villagers to build a building and you need a log to complete it, it's probably more efficient to cut down the tree that's nearby rather than walk all the way across the village and back to get one. Similarly, if a wood splitter has a store of logs nearby but isn't working to cut firewood, it's okay to grab the log from that location rather than a far away generic storage yard.
My final goal is that all this needs to be data driven and extensible without the need for a full scripting language. After working with it for a few months, I should be able to add new things villagers do and locations they use without modifying any game code. There are certainly a lot of similarities to what Banished had, but that code is too rigid, messy, and not configurable. It's nice to start again knowing what sort of issues to deal with.
So how am I going to accomplish all this? We'll first I need to start with the smallest case and grow. But also keep in mind my future needs. I've also been doing some research to see what others are doing. Over the last year or so, I've read a lot of game postmortems and AI papers on getting AI characters to do things like I describe. There's a few algorithms that stand out. Namely Utility AI, Behavior Trees, and Goal Oriented Action Planning.
None of them are perfect for what I want, but they all have good ideas. So I'm blending and modifying, to get what I want.
The basics of my idea is to have each villager have goals they want, and keep track of how strongly or weakly they want to do them. As the player places buildings and objects, those objects will be able to fill those needs. Each object gives a score to the villager as to how useful it is to perform it's actions, which will be combined with the desires of the villager. Considering all the possible actions available to them, the villager will pick one of the top ones. Objects can also have their own desires. For example, if a location turns reeds into baskets, the location will desire the source materials if the number of stored materials is low. This in turn will cause villagers to consider collecting reeds when needed.
Objects and locations will also be compartmentalized. A boat building area will handle telling villagers how to use it, rather than the villager handling each and every object it can interact with. The object would hold the animations, particle systems, audio, and other resources needed for use, the actions it can give out to villagers, and the desires that it can satisfy. This way, as the game grows, I (hopefully) don't have to modify existing resources to add a new object.
But where to start!? Designing and writing a giant system with a zillion requirements is hard. Without being able to test its parts as you work is very difficult and usually doesn't work. If you try this, as the code expands it shows you where your design falls flat and needs fixing. It's hard to debug, and it's time consuming to change things when you hit the walls of your design. There are too many unknowable design issues to be able to decide on them up front and roll with it. So I like to start small and simple then grow.
I decided to find the simplest thing the villagers will actually do that makes simple cases for everything I want to be able to handle. This took me a while to come up with, because it's not really a focus in the game, but it's still in there. Of course once I thought of it, it was obvious.
I originally thought I'd implement a campfire to satisfy the desire of villagers to be warm. Seems simple, and is a scenario that will play out in many similar ways throughout the game. But it requires a lot of structure all at once and doesn't quite cover the wide berth of ai systems that I want. When the villager is cold, it desires warming up. The campfire can handle that, but it needs to be burning fuel of some sort for that. I could fake that with the campfire turning on and off automatically for testing. But I feel like to continue down that path, fuel needs to be harvested and/or stored and brought to the fire, which requires inventory, and more locations and actions, cutting trees, splitting firewood, or collecting something else that can burn. That's all too complex, and doesn't have an obvious outlet for group actions.
Trying smaller actions villagers will be able to perform was a non-starter as well. Just collecting rocks and putting them somewhere else seemed a bit to big for a start, as it still requires other systems like inventory, carrying things, and an object that can store things. I wanted to be up a running with the ai without writing other systems at the same time.
So what did I come up with? It's idling. That's right, doing sort of nothing. Find places to hang out, pick one based on distance criteria, walk around. Talking to each other, or have a party. I can get things up and running without harvesting resources, needing storage and inventory, or production chains. There's no game there, but it meets the needs of most of what I want to do. And all I had to write is the core AI systems to make it work. Extending it with more things that objects in the word can do should then be easy(ish).
So that's where I am. After my paper design phase and coming up with a plan, I've implemented the basic structure of villagers with desires, objects that can satisfy those desires, and being able to pick the best action from it's weights. It's all data driven. Each object has animations it can hand out to villagers to make interacting with it look unique and correct. Villagers look at what they can idle near, weight it based on distance and pick from the top choices. They can satisfy their own need to idle and wander randomly as another possible action. Currently it seems to be in a flexible space where it will be easy to extend and add features.
Coming up I'll be working on group idling - getting two or more villagers to decide to stand close to each other and play synced animations as if they are having a conversation. (I hope in the future this sort of thing will build friendships and relationships, but that's really getting ahead of myself...) I also want to setup up triggers for group events, where villagers immediate desire becomes attending that event over anything else. I'll probably also add some rudimentary time of day schedule which changes what sort of idling occurs at different times.
That should set me up with a fairly solid foundation for the more complex systems that will be built on top of the desire/satisfaction system. Then it will make more sense to get into the fun game parts where resources are harvested, production lines are setup, and players try to balance everything so that everyone survives.