I created a new type of ornament today called a Trigger. They’re just static things that sit around, but if you “Interact” with them (Currently by having any player-controlled creature stand in front of it and clicking on it) it will cause all other ornaments that are listed as in the ThisTriggersThat list to go into “Attention!” mode.
I’ve made these very bland looking “server rack” ornaments; if you walk a creature up to them and click on it, a set of nearby computers will start flashing for attention and some other creatures will walk up to them to play with them. It’s the beginning of some very basic “gameplay” mechanic starting to rear its head. All of this work is still self contained inside the main AI loop so it’s making it very easy to expand on existing creature behaviour and allow them to make intelligent decisions about whether they should go play with an ornament that’s demanding attention, or maybe run away from something that’s shooting at them.
All the Creature and Ornament placement and statistics are now controlled by a single function call once for each creature instead of a big ugly bunch of declarations at runtime as it was previously. It’s becoming much cleaner to load in levels and fill them with things to interact with.
This afternoon was spent completely rewriting the main AI loop into what I hope will be the final layout. All decisions are now made in a boolean function called TryNewDecision where you specify things such as the creature being influenced, who is causing the influence, and how exciting the influence is.
With the entire decision making process now self-contained instead of being spread haphazardly throughout the game loop, I can now fire off decision based actions much more precisely and easily. To demonstrate this, I wrote some new hooks into the decision making process. I added a new little “Emote!” sprite to the game so creatures can have speech bubbles above their heads, and I’ve made it so when one creature can see another creature within its own cone of vision which is not one of its team-mates, it will show a little emote over its head to show that it’s looking at something interesting. Another hook I’ve added is now, when you fire off a weapon and alert an enemy that will fight back at you, the camera quickly zooms in on the enemy you attracted to show that you’ve got its attention.
With the AI code much cleaner now, I look forward to moving ahead a lot more smoothly with the design flow for creature and ornament behaviour.
I’ve added a new routine that calculates a creature’s cone of vision based on the distance they can see and how wide the cone should be. For debugging, at the moment it doesn’t do much of anything other than draw a graphical representation of a cone in front of their face, but it’s nice to see the way it collides with walls correctly and follows the creatures around as they change directions and move about.
At the moment, calculating the cone of vision for more than ten creatures at a time causes a few frames to drop, so I’m going to have to speed things up a bit, as well as be a bit more intelligent about what creatures actually need to have a cone of vision calculated at any given time.
Update: Okay, I actually spent some decent time optimising the cone of vision logic when I realized I really can’t be calculating it every frame, and it needs to be only recalculated when a creature moves, but rendered visibly every frame. I also needed to store the cone of vision in a manageable array so I can quickly check who can see who (Bool CanThisSeeThat(This, That)). I got this work done, and realized I was massively over-rendering the cone of vision graphics before. It’s now much faster and much more intelligent, meaning no more dropped frames and it’s all kept in a nice little loop called “ManageVision”. Creatures have a boolean called “HasEyes” to decide whether they need to have vision management, so the ornaments don’t get cones of vision rendered near them.
I like the attached screenshot here as you can see four creatures distracted by computers, as well as a cone of vision colliding with a wall, demonstrating how it can not penetrate the clipping plane.
It’s Anzac day, so time is well spent getting some artificial intelligence routines beefed up. After creating the “pathfinding” routine a few days back, I quickly disabled it because it was very unpleasant having your creatures always take the most direct route to a destination as soon as they were sent there. You would click on a tile to send a creature there, and the creature would instantly know that the direct path was not possible and turn around in the other direction to take the better path. It worked well, but it just wasn’t very pleasant on a tactile level.
Back when this was the case, there were two methods of travel: “Beeline” and “Pathfinding”, basically for dumb vs smart movement. Now I’ve created a single method where all creatures will always use Beeline until they bump into something, at which point they will calculate a pathfinding result and switch to that mode. The result is your creatures will try to walk directly to your elected destination, and if they crash into a wall they will follow it to a better path.
The pathfinding doesn’t take into account other creatures along the way during the calculation, assuming that by the time it gets to that part of the path, the creature will probably have moved anyway. Because of this, if a pathfind causes a creature to bump into another creature, they will currently both just stop in their place.
Aside from this development in creature movement, I’ve also now completely freed the “Currently Controlled” creature from any hard code, so you can control any creature in the game easily, and also control as many as you like at once. There is no technical difference between an AI creature and a human controlled one, just a few arbitrary things like what “Team” they play for.
One other new feature I got working today is that “Attention!” for ornaments now calls the nearest creature to come play with it. With some rudimentary “Compass” math, a creature will stand in-front of an ornament that is demanding attention and face the correct direction to play with it. They don’t actually do anything yet, currently a computer screen will start to flash green and black and a creature will hurry over to stare at it.
The engine now has working ornamental objects for breakable furniture. They can all be stored in one massive bank and just referred to by unique numbers for each animation they can play. At the moment, an ornament can be “Idle”, “Demanding Attention”, or “Dying”. Idle and Attention animations loop over and over, while the Dying animation plays once then just sits on the final frame forever.
They have health like any other entity in the engine and use the creature AI loop to decide when to change between Idle and Demanding Attention. Eventually I’ll write in reactions for nearby other creatures for when an ornament demands attention so they can go make it happy.
I also tried to create weapons with blast radius today but I was pretty unhappy with the result. I had a working “Rocket Launcher” that fired one slow bullet and created a large explosion of damage wherever it landed, but I wasn’t happy with the way it was interacting with a number of other elements such as the clipping plane. I’ve taken out the “Blast Radius” code for now and might tackle that one later.
The last few days have been spent giving in-game creatures much more real “presence” in the game scene. The clipping plane now pays attention to all creatures as they walk around, and creatures talk to the clipping plane to update it on “WhatCreatureIsWhere”.
With this development, creatures now bump into each-other and can’t walk through other creatures. This has also allowed me to start making creatures aware of each-other in many ways. When one creature fires a weapon, the weapon has a certain “audible volume” that travels a distance across the map. Any creature standing on a tile in that audible range will check what “team” the person who fired the weapon is on. If they’re not on the same team, he will decide to “React to Gunfire”. Based on the creature’s class (Noncombatant, Fighter, Enforcer, etc.), the creature will either run away from where the gunshot was heard, or perform another appropriate action.
I spent a few hours trying to get the AI for “Attack Target” to work, when someone decides to return fire, but the design I had in mind wasn’t working so I need to think about it a bit more. In the meantime, the game world is starting feel a lot more alive now that the player can run around firing off shots and making creatures run away scared.
I’ve spent the day adding lots of nice, clean variables that relate everything rendered to a global “Camera” now. Along with that, I’ve added a Z axis to the camera to allow it to zoom in on the scenery. The game slows down a lot when you zoom, so it will probably be reserved for non-interactive moments, but it’s a nice effect and I’ll keep it there.
Along with this new dynamic camera, I’ve added some intelligent camera “behaviours”. The main one I’ve got working at the moment is “Zoom To”. You can specify an X, Y, and Z co-ordinate and a number of “Steps to Take” and the camera will smoothly zoom over/in to that area. The more steps for it to take, the slower and smoother it goes. Once it finishes “Zoom To”, it switches to “Restore” behaviour and smoothly restores the Z axis back to 0 to remove any zoom-in affect that was applied.
The end result is a nice little “Quick, look at this!” effect for when something exciting happens, before restoring the camera back to its original zoom level, but leaving it sitll hovering over the item of interest.
The last couple of days have been spent building a new tool from scratch: map maker.exe. This is the program used to make files that load in all the floor tiles needed for any given scene, and also lay them out across the floor in whatever patterns you make up. These files also define basic clipping boundaries across the maps. The file format I made up for maps is really basic, it’s just a list of graphical tile file-names that are used in the map, and then a huge array of placements for them. No graphics are stored in the maps, just references to the graphic files needed to put them together.
The map editor is fairly quick and simple to use. You load in a tile and start stamping it around on the floor with the left mouse-button. Holding shift allows you to click-to-delete tiles back to a blank space. Press L on the keyboard to load a different graphical file onto your stamp and start placing that around. If you want to put a previously used graphic back onto your stamp, you just right-click on it anywhere that it’s already placed on the map to pick it back up again. Holding Left-Ctrl displays clipping boundaries in red; left clicking creates a clipping boundary, and right clicking deletes them.
I’m interested in getting 2.5D working using height-maps, but that’s a bit further in the future at this point. I’ve got some other engine-level features I need to add in now regarding camera movement.
Saturday! A productive day of making projectiles work. I’m going to talk about the projectile-based damage system that’s working in the prototype now because there’s a pretty unusual design to it.
When a creature fires a projectile, a line is instantly drawn from the start pixel to the end pixel using yesterday’s line drawing algorithm. As the line passes over isometric tiles, it increases the temperature of the tile. The degree of temperature is the amount of damage the tile will deal to any creature standing on it.
Like I said, the line is drawn instantly, meaning the temperature appears on the tiles instantly. However, I wanted the projectiles to have “speed” to determine how slowly they trace across the screen, and also for graphical purposes in-case I want to render a bullet flying or something. To achieve the desired result, the line not only increases the temperature of the tiles it passes over, but it also drops melting blocks of ice on the tiles.
The further the line travels, the more ice it drops on every tile; on the first tile it only drops one block of ice, and by the last one drops hundreds. Each block of ice always melts at the same speed, regardless of the temperature of the tile. If a creature is standing on a hot tile, it won’t hurt them while there is ice still on the tile. Once there is no ice at all on the tile, the full blast of the temperature affects anything standing on the tile, and then the temperature slowly starts to drop down to room temperature.
The affect is a sweeping wave of damage across the line, with dynamic speeds, damage, and time-based affects.
Once this was done, I got to work on the unified zBuffer for all graphical entities. Rather than looping through Creatures/Clipping objects in a haphazard way, everything now shares one rendering sort-order and is displayed in order on the screen. This is demonstrated by a nice row of cubes running down the screen on this version of the prototype. The red lines you see are projectiles flying about.
I’ve improved a lot of little things regarding acuracy at this point. Previously, although the program was “working” on an isoletric scale, it was cutting heaps of corners to create the illusion of an isometric layout. I’ve slowly improved the calculations everywhere to make everything perform a lot more nicely on the grid.
I’ve also implemented a new type of path-finding, with the previous one now called “Beeline” where a creature will take the most direct path across the tiles to a given point, I have now programmed in Dijkstra’s Algorithm and named that ‘Pathfinding’ in the game code. The large red wall exists to demonstrate the pathfinding.
The long line demonstrates my implementation of Bresenham’s line algorithm. It traces a straight line from one the “player” creature to the mouse cursor at the moment, to demonstrate what tiles would inflict “damage” on creatures standing on them if the creature were to fire a bullet in that direction.