I'm back with a new progression video. I had skipped the last month update due to not having something useful to show off. I had optimized the engine and went from 20-25 fps to a stable 60 fps in my test environment. But it is really hard to display the effect of a performance optimization ;-)
At last I moved the level generation from a designed and semi-generated approach to the new, completely procedural, in-game level generator. In combination with the reworked sewer level design finally something to show off.
Here is a new video dev-log showing the sewer level generation step for step.
With windows 8 my willingness to try out linux has been tripled over night. Is windows really that much better than linux any longer ? I bought a new laptop and set a new pre-installed windows OS aside to give linux (ubuntu) a chance. Though I will not turn my back on windows completely (at least I'm quite happy with visual studio), it could be enough to wait until windows 9 is released, hopeful setting the focus back on a desktop OS again.
When it runs good, very good, I might think about testing out a port of my game to linux...
Speaking of Gnoblins, I plan to release the first public alpha version at the end of this month, so stay tuned. Further on I'm currently in artist mode again, trying my coder hands on some programmer art, here's the current wip of my new model , the elder.
In gnoblins I use a dynamic water system, that is, some areas are flooded, you can flood or drain them. The question is now, how do your minions or other creatures react to water ? This is no trivial game design decision and here are my musing and thoughts about this issue.
First off, what options do you have when you detect that a creature is in water ? 1. You can kill it immediatly. Well, that would be little bit too harsh, wouldn't it ?
2. It would float helpless on the water, swinging wildly its arms and die after a certain time from exhaustion. Thought you could try to drain the area, it would be very harsh too. There's no option to help your minion if you can't reach the lever to drain the area and it would be a too easy way to kill of invading enemies.
3. The creature can swim around, but will not be able to do any other actions like fighting or operating a lever. Hmmm... sounds better, thought you can't operate with your environment or fight off any danger.
4. The creature can swim around and do most actions and still is able to fight to some degree. Well, we are approaching a game design zone where swimming is more or less just a visual effect and don't have such a strong impact on the game play. So, what would be a good solution ?
After some musing I choose to continue with 3. Creatures can swim, but will not be able to interact with its environment while swimming.
Done ? No, we need to check the game mechanism in more detail. Here are some questions: 1. Can a creature reach a goal by swimming through a pool of water or does it always try to avoid water ? The option to avoid water sounds easy, but what would happen if one of your creatures is trapped on a island ? You have no option to help it.
2. What is the behavior of a creature, if it is suddenly in water ? It should try to reach dry ground, shouldn't it ? But this could interference with commanding your minion to reach a certain point: entering water..eehh..water..leaving..ahh I need to reach my goal..entering water...eeehhh water...
3. Should it be allowed to have a goal in water ? This would result, that a minion would try to reach an area to execute an action, which can't be executed because it is under water. A movement command on the other hand would be valid. But what happen, when you start your movement at the time where the goal is not under water, but at the time when you reach your goal, it is suddenly flooded ?
4. Should doors work in water ? It is already hard to detect if a door is actually in water, there are floodgates, so on one side there's water, on the other side none. Not being able to interact with your environment could be deadly for your creatures, especially if you are not able to operate doors. Do we need a special rule for doors ?
5. What about flying creatures ? Hmmm.. flying creatures can ignore water, can't they ? What about interacting with the environment ? They should be able to fight swimming creatures, but can the interact with objects under water ?
6. Is water a safe haven from enemies ? Ok, most creatures can't fight when swimming. So, just command your minions to enter water to avoid some strong enemies ? This would be too easy. Water must be dangerous if you linger too long in it, so we need to drain your power during swimming resulting in exhaustion after some time.
Hmmm..I need some ruleset for the behavior of creatures and water. This ruleset should answer all the questions from above in a satisfying way. Here's my first attempt: Rule 1: A none-flying creature will not fight when it is currently in water. Rule 2: All other commands and tasks, which are planned by a creature do not depend on the creature being currently in water. Rule 3: Planing does ignore goals being in water (exception: flying creatures targeting swimming creatures). Rule 4: Planing adds a penalty to ways leading through water, but it does not completely avoid water. Rule 5: Doors can be opened by a creature being in water. Rule 6: Creatures can't interact with any other object in water. Rule 7: When idleing/roaming a creature try to reach dry ground. Rule 8: When in water a creature will exhaust much faster.
Eventually I need to think about how to implement all this rules. Impl 1: The engine needs to sample the water level at a given position. Impl 2: The pathfinding system needs to consider the water level at each waypoint. Impl 3: A parameter to modify the way costs. Impl 4: Each creature needs a swimming animation. Impl 5: No automatic swimming detection in the animation system, the game logic should add an animation overlay when the creatures body is deep enough in water. Impl 6: Creatures in water needs to exhaust much faster. Impl 7: Lax animation boundaries to avoid animation flipping all the time at the water threshold (eg. enter swimming animation when water is 1m deep, exit animation when water is less then 80cm deep). Impl 8: Sound overloading, we don't want to hear any footstep sounds when swimming. Impl 9: Target planing, check if a target is in water at the time of planing to avoid unnessary decisions. Impl 10: A in_water state at the entity to quickly check it in game logic. Impl 11: When executing an action, abort it once the creature detects, that it is in water. Impl 12: Physics: no change in the physics part, the entities will still be grounded. This way I will avoid trouble with doors etc. Impl 13: Rendering, add a visual flag to indicate, that the rendered object is floating at the water surface (Performance bonus, only rendered objects needs a detailed evaluation of the surface)
Sounds solid, enough to start a first implementation. Coding time
Sometimes you can't see the forest for the trees. I'm looking for a simple data base solution for my game since two years now. My requirements were - simple setup - file based (no real database) - write custom export scripts - able to build a simple front-end - no $$$ I simply didn't found a solution.
I'm a senior software developer and it isn't really a problem to write something like this, even with a web-frontend based on a standard db or an application server. But in my spare-time I don't want to create tools, I more or less do this at work all day ! I want to make games, not tools. Sadly custom tools are an very important factor in game development.
Nevertheless, finally I found it: OpenOffice ...well, I worked with open office since a few years now, already utilizing OO calc for my game, but I never thought that open office is delivered with a simple, yet powerful, sql database called open office base. The best thing about it is, that you can add easily forms to manipulate the data.
For you, who don't know open office. It is the open source answer to microsoft office. I.e. OO writer is the solution for MS word, OO calc for MS excel, and eventually OO base for MS access. I think that MS office is more mature and powerful than open office, but open office is free and by far all I need at the moment.
Welcome to the February update.
This time a progression video to show off the new tutorial system, the garrison system, new difficulty levels and finally a much needed end game screen.
Currently we are working on expanding the room system to support a more compact dungeon design. This will most likely result in an improvement of the room art and additional game mechanism, so stay tuned for the next update.
This is the first tutorial video for the upcoming alpha version:
The tutorial videos present an insight in the alpha version and will help new players to get into gnoblins more easily. Each video will be about 1 minute long and explain one major game feature. For now this video deals with the luring and managing of your minions, the next videos will introduce combat, crafting, and dungeon development.
I'm still playing around with the AI. This weekend I got an issue with pathfinding: How to let a hunter follow its prey without recalculating a navigation path frequently ?
Well, I think I got it. My assumption is, that the hunter is able to follow the prey step by step. With that assumption I can create a path by tracking the movement of the prey, because if the prey was able to walk a certain path the hunter will be too. I know that this approach has it's shortcoming. If the prey has abilities the hunter has not, like jumping over a barrier etc. But there are two reason the assumption is acceptable. First, it is not realistic, that a hunter is able to follow a prey around the whole map. Once the distance is too great, the hunter has failed and will pickup an other task. The second point is, that if the hunter is not overcoming a barrier a quick A* could help him, if it is not helping, he will abort the hunt.
The idea is, to start with a A* (Figure 1) and create an initial path to the prey. Now, while folling the path, the hunter will expand the path by checking, if the prey leaves a certain area of the last position in the path (Figure2). Once he has left it, the hunters path will be expanded with a new node(Figure 3).
In Figure 4 you can see a path expansion of 4 nodes. An optimization would be to check, if the prey re-enters an area of any node but the last one. In this case the hunter can take a shortcut and the according nodes can be disposed.
How good it will work depends on the choosen radius. I think I will give it a try :)
Recently I worked on the fluid simulation in Gnoblins. Until now fluids in Gnoblins were merely a visual effect, but under the hood it was already a working simulation. To utilize it completely I needed to introduce the ability to swim. So, gnoblins and other creatures are now able to swim now. When swimming, each creature will be affected by an effect. Most creature will be slowed down and get exhausted faster, but there will be although creatures, which will get faster, get healed or get damaged.
I called it fluid simulation because it is not very good suited to represent water in a realistic way. For this task the simulation is not fast and detailed enough, but for slow moving fluids like lava and slime it works great.
An other feature I have added recently is the addition of environment agents, how I like to call them. Basically it is an AI which manipulates the environment. Currently it is able to change a lot of things, but I will present this in an other post. For now it is only important, that with the help of these environment agents the fluid is able to interact with static environment objects like torches. So, when watching the video take a look at the torches when the fluid level rises.
So, why add a fluid simulation to Gnoblins ? Well, I think that it smooths the way for some interesting gameplay. For one you are able to control the fluids by using doors or better floodgates. Doors will only slow it down, whereas floodgates will stop them completely. An other effect is, that fluids will damage or destroy your furniture and limit the abilities of your minions or even hurt them. On the other way, you could use it to fend off enemies.
Eventually I want to talk about what we are working on currently. First off, I have updated two additional tilesets for the dungeon, the sewer and castle/fortress tileset. I will show them off in a future post, I think that one of the next levels will be a sewer level utilizing some slimy sewage water :-) An other task is the addition of more creatures. Currently there are 6 different kind of creatures, each with 2-4 variations, which are in the state of getting finalized. Creatures are the most costly element of Gnoblins. You need to model, texture, animate, add some behavior and add some variation to them. There's a reason that many of the 100-200 people working on a AAA title are artists.
There is some interesting stuff in the pipeline I will show off in future posts, so stay tuned
Here's the august update. This month I worked on improving the accessibility of the user interface. A lot of the more complex features have been moved on the main screen, especially the mining map has been removed and integrated directly in the game world now. I will show off the improvements next update, after testing and tweaking it a little more.
For now here an other improvement. A major goal this month was to increase the readability of the game world. The old version was too dark, your minions were hard to discover and it was not really easy to check what your minions are doing at the moment. Therefor we updated the rendering, make it more colorful and activating the toon-shading again to improve the perception. Further on I added new icons hoovering above your minions to show what they are doing currently.
Here is a comparison of version 0.2.39 and 0.2.40.
Although I added a new quest system, which will be introduced in one of the next updates.
The second pre-alpha version of gnoblins with some great improvements is out.
Most important are the addition of sound fx and music. The awesome music is created by Christian Andersson (Craze Music).
As always you can download the new version here.
The new configuration supports mixed resolution rendering, that is, the 3d world can be rendered in a lower resolution than the gui to keep a moderate framerate at higher monitor resolutions even for not high-end videocards. The following screenshots display a scene with different quality setting at a screen resolution of 1680x1050 (the fps is displayed at the left, upper corner). All screenshots have been taken on a nvidia 8800 GTS videocard.
Here's the complete changelog:
[quote] [indent=1]Changelog Version 0.0.2 ======================= Major Changes: -------------- - Added an ingame options dialog. - Sound and music have been added ! Minor Changes & Bugfixes: ------------------------- - The map displays the edge of the level properly now. - Added a pause function (clock icon in hud). - Player animation/actions don't stop while a dialog is open any longer. - Inventory item drag'n'drop behaviour improved. - Items are no longer black when dragged. - Some gui frames do not change the color any longer. - Fixed a bug, where sometimes items are not showing up properly after a game has been loaded. - Game start time and level switch time have been reduced dramatically. - Fixed the terrain texture glitch. - Added an exit button to most ingame dialogs. - Armor and combat values (damage/penetration) are displayed in the equipment dialog now. - Handling of the save games has been improved: . You can delete characters now. . You can only play saved characters with the proper game version. . Fixed some bugs related to saved games. - Removed some texture glitches (red lines). - Can't equip any item to the earring,ring,bag slot any longer. - A newly created character gets a random name, which you can change. - Un-/equiping items to a statues is displayed properly now. - Added some low level creatures to the starting area. - Added Anti-Aliasing (set postprocessing setting above very low) - You can turn off the outlines now (set postpressing settings to extreme low) - Animals can no longer open doors.
So, I have finally took the time to optimize my game. One week later and the following test scene went from ~30 fps(35-40ms) to ~60fps (16-17ms).
Well, it is not a secret that my engine is home brew and that there were and are enough optimizing potential hidden. The trick was to start profiling it in more depth. Therefor I started with extending the in-game profiling mechanism by adding a time-stamp based, detailed (microseconds level) frame logging of single threads and the GPU.
Getting a profiler I imagined was hard. Gdebugger was not enough. Many tools support DirectX , but not OpenGL, at least only halfhearted. So my first attempt to write a CSV file and transform it into a diagram with OpenOffice failed. It was hard, slow and really clumsy to show lot of data (several thousand timestamps per frame). The rescue comes in form of SVG. Scalable Vector Graphics. Really easy to generate, out-of-the-box support by browsers, good display performance, you can zoom in and out easily, and finally you can add meta information which will be displayed when you move over data with the mouse. Really perfect ! It looks like this:
So, after getting more detailed information about your game performance I was able to start tracking down issues. First off, I needed to get rid of sync points between the GPU and CPU. That occurs when the GPU and CPU wait for the other one to finish processing of certain task, i.e. uploading a buffer. Therefor I added some double and triple buffers to process data on the CPU while the GPU renders the result of a previous frame.
The next step was moving data processing from the main thread to the worker threads. Here is a list of jobs, which are processed in the worker threads now:
behavior tree (lua)
garbage collection (lua)
filling "rendering command queues" (not API supported yet !)
Moving this into a worker thread often requires some form of double buffering and sometimes it introduce some funny bugs, like this new alien gnoblin version ;-)
Finally I tracked down an old test rendering pass (additional geometry pass). And I only optimized a single shader by adding branching and reordering the rendering order.
There is still lot of potential in the expensive post-processing shaders and submitting the data to OpenGL (still not really good batching support), but for now I 'm quite happy with the result
It is a very long time since I last posted about gnoblins (almost 2 years). After a major shift in the game design and some major refactoring actions, I'm stablilzing the gameplay at the moment. I will present the result of all this refactoring/redesign in the future, for now I will write about my experience with the attempt to crash my own game engine...
From time to time I want to break my engine/game, pushing it to its boundary until it crashes or collaps. I think everyone should do it to learn more about its weaknesses. This shouldn't be too hard considering that my engine is a homebrew, hobby product.
Testcase: My testcase is spawning lot of entities, all having their individual AI, movement, sensory scanning, pathfinding, animation etc. active. I want to spawn them in a single spot. This is important, because many systems, including mine, scale better with entities distributed evenly in the world. But if you pack them all in a single spot, you suddenly have very high context density, you need to render them all, you need to simulate them all etc.
Okay... Let's go
Level 1: Task: Spawn 200 entities in a single spot. Assumption: Crash !
Hey, it crashed, my assumption was right Better said, some asserts kicked in. I use almost no dynamic allocation once the game is running. My engine design idea was: I will have enough memory, concentrate on performance first (and I dislike dynamic memory allocation and garbage collection). So, I needed to increase some constants.
Level 2: Task: Yet, again spawn 200 entities in a single spot. Assumption: Massive slow down..
It didn't slow down.. not a lot... well, party ... next step
Level 3: Task: Spawn 1000 entities in a single spot. Assumption: Massive slow down..
It didn't slow down...yeahh ... WAIT... Something is wrong . After watching the scene it didn't look like 1000 entities. *Facepalm* .. The entity pool is kicking in, reusing entities. Taking a look at the pool size, only 70... atleast the system handles massives entities spawn in a robust way.
I increase the pool size to 1000.
Level 4: Task: Spawn 1000 entities in a single spot. Assumption: Massive slow down.. finally ?
Crashed again (asserts). The problem is, that I spawn 1000 entities in a single frame. Fixing some parameters and finally not crashing..
Level 5: Task: Smaller steps, lets start with 250 entities Assumption: Massive slow down.. finally version 2.0 ?
Yep, its slows down finally. Entities spawn and start moving... well atleast partly. It seems that only groups of entities start moving, group after group start to move. A second effect is, that almost all ignore an enemy entity standing next to them.
Well, every entity is able to start multiple (4 at the moment) scanning/pathfinding requests which are processed concurrently. If the entities does not receive the answer in ~1-2 seconds, it will timeout and restart the request. The issue seems to be, that some entities will timeout at first, starting a new request. Starting a new request removes the old one from the processing queue and adding the new one at the end. This seesm to result in starvation. Once the requests of the first X entities are through, the workload on the multithreaded pathfinder/scanner is reduced and the next group of entities will receive their response in time. I could make it more robust (instead of enqueue at the end, exchange the old request with the new one). but this isn't my requirement yet, so I leave it for now.
Level 6: Task: Go for 400 entities Assumption: Massive slow down..
Yep, it goes down. From 90-110 fps to 6-8 fps at first. Later it crawls to 0.6 fps at times. The problem is a spin down (longer frametimes => more processing per frame). This was expected. Every single entity scan its environment for other entities to do steering, it scans for threats, it scan for tasks to do, it tries to find a path to its goal, collision detection with the world (not with other entities), AI update method and behavior trees.
Woah... what happens... suddenly I got 50 fps ? Hmm...ahhh... all entities are dead now. The game tracks invading entity raids and cut them off after a few minutes to prevent a system collaps during long game sessions. At least it works and the rendering system seesm not to be the bottleneck.
Level 7: Task: Final test with 100 entities only, which is more than the expected maximum number of active entities in a game session. Hope: Acceptable slow down...hopefully
Yep, it works finally like a charm. All entities start to react immediatly, hacking down two minions and a bed. The game is stable at ~330 MB, ~80 fps, 30-50% CPU (quad core) with almost equal distribution on all 4 cores ( no core reaches its limits).
Conclusion: I know, that a AAA engine is by far more powerful, but on the other hand it is really satisfying to see of what your own engine is capable of. There's enough potential for optimization left over, but eventually I'm really proud of result.
This week I'm working at the AI system. So it seems to be the right moment to talk about the implementation of the AI system in dungeon fortress. I hope that it willserve as an little inspiration to other hobby game developers.
Well, I'm not an expert in AI and several things are quite new (in relation to 11 years of development), but I've learnt a lot about AI in the past year.
The whole system is build up of several AI related components which are displayed in the figure.
The most basic component is the finite state machines (FSM). I use several FSMs in my game engine, mostly for controlling entities, but although for gui and user interactions. They are quite simple, communicate asynchronous over a central bus system and can be designed in an uml tool for which I wrote a xml converter. I can attach several FSMs to an single entity to control it. Most dynamic agent got at least two FSM, one for controlling the actual movement-action and one for controlling decisions and reactions (think of body and mind).
The second basic component is the way-point system. Instead of using a navigation mesh, I developed a multi-layered way-point system. Currently only two layers are needed, whereas one is for mostly navigation and the second layer is at a lower resolution containing additional meta data.
The third basic component is a knowledge container, containing knowledge about locations (represented by way-points). There's no special knowledge data structure about entities or events. The knowledge contains data about explored, dangerous, inaccessible, or safe locations. Each entity has its own knowledge, but certain entity group are able to share knowledge.
There are two different "traditional" AI systems which works on top of the three basic components. This is a behaviour tree which controls the behaviour of a single entity and a blackboard system for a high level orchestration of entity groups.
The blackboard system manages jobs. Each entity is able to create certain jobs( like "supply me with food") or to apply to one job. I use the blackboard system to control group of entities in a economical sense. In dungeon fortress a group of entities, like a spider nest, is a more or less simulated community of entities. They need to eat, to gather resources etc.
The control of a single entity is done by the behaviour tree which is inspired by the work of Chris Heckler, who uses a similar system in spore. A behaviour tree, is a tree of "decision" nodes. Each node is quite simple, but by combining this nodes in a tree like structure you can create more complex behaviour with ease( I really love behaviour trees!). The behaviour tree make decision based on different entity properties, by scanning the surrounding for enemies, resources, objects of interest and eventually by a modified A*.
The A* is most likely in every game AI system present. I used a modified version of it to navigate on the way-point system by using the knowledge of the according entity. This way it is possible to navigate around dangerous areas or to avoid blocked passages.
It is time for an other developer log, this time in video form. In one of the previous videos I demonstrated the water simulation capabilities in Gnoblins and I have promised to talk about further simulation stuff. Being a dungeon building game, Gnoblins has a quite dynamic level layout and the water simulation doesn't make it easier leading to some interesting questions. How does water interact with the level, with objects, with plants ? Where do plants grow ? Mushroom ? On soil, on rock ? In light or darkness ? These are all questions I wanted to consider when developing an environment simulation and you can now watch the result in this video. Have fun and stay tuned !
Well, after struggling with environment/reflection map artifacts for some time now, I have found a solution. At least I'm quite happy with the results in my game.
The issue with environment maps is, that you need more or less exact probes of the surrounding in dark areas, which is quite difficult in my game due to its dynamic nature. Env-maps simulate the reflection of the surrounding, similar to the specular highlights of close light sources. The problem occurs when the environment is dark, while the env-map displays a lit environment and acts as a light source (especially when using HDR), in this case the env-map immediately catch your eyes.
You can take a look at the screenshot. On the left side the environment map on the test sphere and the bands of the barrels is clearly visible. My new approach is displayed at the right side, where it looks similar when the environment is lit and is more or less turned off when the environment is dark.
I'm using a deferred render engine, therefor I blend the environment only in when it is close to a light source. Additionally I modify the factor by the angle between the light source and surface normal to dim the effect on unlit surfaces.float normal_factor = dot(light_direction, surface_normal) * 0.5 + 0.5;float distance_factor = smoothstep(max_light_radius,min_light_radius, distance(light_position, pixel_position));final_light += env_color.rgb * normal_factor * distance_factor;
This weekend I've finally integrated my first attempt of a procedural level generator. I'm quite happy with the result and I think I want to take it a step further, generating procedural quests.
Most people got a bad feeling when they hear about procedural quests. Most will most likely think about the "deliver item X" or "kill X monsters" quests encountered too often in MMORPGs. I want to generate more complex quest, maybe even character specific quests. I've got some ideas and I want to develop a procedural quest system slowly step by step, beginning with a simple system and refining it with each iteration. My experiences and thoughts will be documented in this journal as a little series of entries.
Well, let's start. In my first entry I want to talk about a quest and level setup. First off, I can generate indoor levels and will incoperate this in my quest generation. My approach will most likely be applicably to "closed" levels not so likely to "open worlds".
Talking about levels, I define a level as a collection of sections which are connected by gates. Each section is an isolated island where the player is able to walk around and do something, but the only way to leave or enter a section is through a gate. Take a look at figure 1. Think about a survival horror game, you're coming from town and want to investigate the house of a mad scientist. To proceed in the story you have to find the secret research labour reached by a tunnel in the cellar. Cliche pure :-) As you can see, a section could be of different size. The kitches might be quite small, whereas the ghouse could be large.
The next step is to define a goal. We start with a simple but often encountered goal: find the exit and leave the area.
Now we need to introduce some rules, my first rule is: whatever happens, the player must be able to reach his goal. Sounds pretty standard.
We need some kind of critical path through the level which the player can follow to reach his goal. The level looks coincidentally like a graph and we use this to run a minimal spanning tree algorithm which lead to the result seen in figure 2. As you can see, there are two edges (or gates) which are not included in the spanning tree. These two gates will be closed for the start. In our example this could be a barrier, a fire, a jammed door whatever.
The next step is to find the unique path to our goal. A simple depth search will deliver the wished result.
To introduce a challenge we can lock one gate on the critical path and place the key somewhere in the level, preferable in a section which is not on the critical path. To find a proper placement of the key, start a conditional depth search at the entry point on the minimal spanning tree. Take the deepest section you encounter. But do not surpass the locked gate and prefer a node, which is not included in the critical path.
That's all for the first part. To sum it up:
- Devide your level into sections which are connected by gates. - Sections are isolated parts of your level which are only reachable through gates. - Determine the minimal spanning tree. - Block all gates which are not contained in the spanning tree. - Determine the critical path to the level exit. - Lock one gates on the critical path. - Do a conditianal depth search to find a proper placement of the key.
All this is pretty basic graph theory I will start to implement some basic graph structures and algorithms. Next things to do are alternative routes, sub goals, sub quests, quest story generation etc. , so stay tuned !
So, the month is almost over and no update up-to-now. There's not much to show off. For one I was on vacation, on the other hand I play tested a lot and refined/rebalanced the game play.
The gameplay is more streamlined now. I have removed the crafting screen and transferred the game mechanism to the main screen. For one you no longer need multiple steps to craft stuff, you can hire minions directly from the main screen, research has been automated, you no longer need to craft interstage products. All this removed a lot of complexity.
On the other hand minions can carry objects now, which adds a lot of visual feedback of what minions are doing at the moment. I.e. wood logs needed to be transported to the carpenter shop for further processing and downed minions are carried to a bed room to recover.
And eventually you no longer need to place single furnitures, instead you can construct whole rooms. I.e. a bed room or a guard room. Here is a screenshot of the four most basic rooms every dungeon need as foundation.
Well, my development process is a classic iterative approach where I improve a certain part of the game for a few week until I go on to the next part.
January was the month of the "npc behaviour", I have implemented some improvements with which I'm quite happy about. So far, my dungeon dwellers are bred from nests and explore their surroundings. When they encounter some food resource they will start to take resources to their nests, on the other hand they will look for food once the got hungry and start eating. Once they encounter an object of interest, like loot lying around or an opponent, the react in different ways. Some dwellers will flee, other get curious and will take a look and others will start to hunt and attack the opponent.
Still there's enough to do, but it should settle down for some time before I revisit this topic again.
So, this month will be the month of the "player" with a strong focus on fighting mobs. This has a major visual factor. I already modelled and rigged some hands and test weapons (my game is played in the first person perspective), now I need to add some decent animations. My goal is to establish atleast 4 basic combat actions: swing a weapon, a special move, a heal spell and a fire blast. I think I have to play around with some special effects too.
Eventually I will rework the (derived)attribute system and the basic fighting rules. As a bonus I will try to invest some time into the gui. I got already a basic working gui with inventory, character sheet, character creation etc. but only with some placeholder grafics.
Looking at the vulkan api so far, it could solve many of my rendering performance issues in my engine. My engine was based on OpenGL 1.2, followed by a transition to OGL 2.0 and lot of extension later left me with a more or less modern deferred render engine. Still, there exists some really old and ugly rendering code, most famous the GUI code. My gui code is based on pure immediate mode commands, calculating and rendering every single icon and every single text letter every single frame. According to gDebugger a screen full of text adds more than 15k api calls !
But... and this is the reason I never refactored it earlier, the performance impact was relative small. On my workstation the performance difference by enabling/disabling the gui is negligible, so API calls alone are not the reason for low performance. Thought this might have more impact on slower PCs. I took comfort in thinking, that once lot of text is displayed on the screen, atleast the performance impact while rendering the 3d world is not that obvious, better said, hidden by the wall of text ;-)
Immediate mode will (most likely ;-) ) be not available in the Vulkan API, so, it would be a good idea to refactor the gui first and take the gui renderer as test object for my first vulkan based rendering approach. Thought the API is not officially available yet, it seems that it will work concurrently with OpenGL. My gui renderer although shares some of the more interesting core stuff of the 3d render engine, that is texture/shader/pipeline management.
So, what did I do to refactor my gui engine ?
First off, it is based on buffers only. Buffers are accessed by un-/mapping it, gui elements are calculated, cached and batched. I implemented a buffer allocation mechanism (multi-core ready) including defragmentation, a command queue (multi-core ready) including multiple sub-queues. And eventually my shaders needed to be updated to work with the old and new system.
I can toggle both renderer during run-time and so far both work perfectly. The performance increase depends on the hardware, my laptop with i5 running the game on an intel HD 4000 benefits most of it, but the overall performance on a HD4000 is really bad, so the felt impact isn't that great. Nevertheless, some quick tests show, that fullscreen text rendering consumed up to 30/40ms per frame (horrible!) with the old approach , and 1-2ms with the new approach. I think, that the performance could be increaded further by utilizing the buffer better (eg double buffering), but the real performance killer is the 3d-rendering engine (too many state changed, no instancing, low batching utilization).
Next I will exchange my own math library implementation with glm, maybe I can get some more performance improvements out of it.
PS: after verifying the performance again, 30/40ms seems to be just wrong. It is more like taking it down from 5-6ms to 3-4ms. Thought the game is really slow on a HD4000. At higher settings I get only 7fps, the GPU needs 112 ms longer than the CPU to finish its work, without any further API calls or whatever involved. Reducing the settings and render resolution helps a lot, but it is not really comparable to the mobile dedicated NVidia GPU I have in my notebook, where it runs flawless .
There're always topics you are aware of, but which you are ignoring most of the time until it is too late. You will thought of it as some minor feature which could be added later. Well, this could be a bad idea.
I trapped myself with one of this minor feature: loading/saving Yes, it sounds simple. After more than 10 years of developing an engine/game I came to the conclusion that it is time to add it now. It turned out to be one of the tougher challenges of the last years. When you got a C++ engine and lot of scripted code (whole game logic), then you have a problem here.
So, how to save your game ? There come two approaches to mind.
1. Serialisation/Deserialisation: You serialize every object in your game to a file. You must have some special handling for associations between objects. I use a unique id for each object and save only the ids for references. Thought after loading your game data you need to reconnect the references. A problem with this approach is, that you need a lot of post processing and you need to change class models to support it (I.e. some script languages like lua supports refering functions). You can regard this as an almost 1:1 memory copy of you game data.
The major advantage of this technique is, that you can easily add and remove data from your game. The mechnism works almost automatically. But there're some pitfalls. First your saved gamedata is really fixed to one version of your game. Reloading it with an newer version could easily lead to some disaster. This is really an issue while developing a game and when you need to release some bugfixes.
2. Export/Import Instead of just saving a copy of the whole data to a file you export and import the data. In this case you define some kind of save-fileformat for each object, relation etc. When importing it you need some kind of special parser for each entity to create and connect the according objects in your engine.
The major advantage is, that this is a clean approach and you can change the game code while keeping the save files (just adjust the importer). But you need to put some work into it whenever you change the fileformat. But this could lead to high maintainance costs at development time.
Well, after forgetting about save files for years, I choose to go for de-/serialisation. I would have prefered the import/export approach, but it is just too expensive. To soften the negative upgrade effect (new game version makes older save files obsolete), I choose to use some kind of weak references to static content. Therefore I divided the data into permanent and persistent data. Permanent data are shared, static data which are used independendly by dynamically created content. I.e. game rules, templates etc. This static content get unique ids at design time and will not be saved to a save file. When reloading a file I can reconnect objects to this version dependent data. This allows me to upgrade and change the game to some extend without making the save files obsolete.
Once the game has been released I fear that a major game update will lead to obsolete save files, but this could happen to import/export files too. Atleast minor updates should work as long as I'm careful about changing the code and content.