2020-03-09
Spent a little time changing the dungeon palette to make it more distinct from UI elements. I’m using Solarized colors for this because I like Solarized and it’s easy on the eyes. Also made it so the starting “Big Room” isn’t pre-lit and always lit, so I can actually test FOV / lighting properly.
Since it’s lunch time, I moved fast and not very carefully… and added pathfinding not-so-successfully:
All the goblins move in the direction they last saw the player, indefinitely, and will attack each other if they get too close. While this is kind of hilarious to watch, it isn’t really what I wanted to do, so I’ll have to just mark this down as a fun detour and return to make sure they a) actually follow the player and b) don’t attack other monsters if those monsters are “friendly”. (For now, all monsters will be friendly with each other.)
(Later…) I removed all but one monster from the map and set a breakpoint to inspect the values of the Path enumerable, as well as the “ToDirection” function that converted an x,y pair to a compass direction. After a little bit of fiddling, I realized the problem was me (again). I was passing in the next step coordinates of the path, where this function expected the delta of current position plus new position. Afterward, with pathing working, I made it so the monster only follows the player’s current position until the player is out of sight. The monster now follows to the player’s last known position, and waits there until the monster sees the player again.
To cap the night I decided to finish changing the game’s color palette.
I think now that I have the bare bones down, it’s time to change direction again. This game is supposed to work with a combination of prefabs and procedural map generation. To start with, I’ll work on plain old static maps loaded from external data.
2020-03-10
It was suspiciously easy to implement prebuilt maps.
I downloaded REXPaint, drew some boxes, and saved the *.xp file. SadConsole has a pretty handy built-in REXPaint reader that parses the native REXPaint format, and even lets you iterate through map layers in the .xp file for reasons. Mine was a simple file, no layers, no special coloring, just floors and walls.
After drawing the file I built a StaticMapLoader class. This has a static “LoadMap” method that loads a map file based on filename, parses its contents, and returns a valid game map from the contents. Right now the parsing is dead simple: map a REXPaint tile to its tile blueprint cousin in the map generation code, and bam, we’ve got a walkable map. Player is placed based on the map’s WalkabilityView, monsters are similarly placed, and things just work!
It isn’t quite perfect. Monsters, after disappearing from my FOV, no longer reappear — though, they’re still “on” the map and will still follow, attack, and die. Also, I forgot to remove monsters from the Scheduling System when they die, so that throws a null reference exception. So got a few bugs to fix.
And now the above bugs are fixed… Next I think I’ll work on the tile blueprint stuff so it can read more tile types from REXPaint.
So I:
- drew a full starting map in REXPaint
- added mapped char values to Tile Blueprints
- added Tile Blueprints to represent map objects as drawn, with my own colors
Which resulted in:
Things are looking all right. Not sure I’m a huge fan of the way I’m doing these tile blueprints – but they work for now. It’s a fairly standard factory pattern that, when you call it with a “tile name”, returns a new instance of that type of tile object. I can’t say exactly what it is I dislike about doing it this way, except that I have to type out every type of tile I ever want to use (just the once, though, which is fine I guess) before I get to use it.
2020-03-12
Started working on a “message history” window to view some messages that are older and no longer displayed on the current message window, then I decided it wasn’t worth spending time on yet and moved on. I am, however, storing all messages in a list (for now) with the plan that, on death, you can go through and view it all, if you wanted.
Next I started on a MapFactory that I plan on using to transition between maps. This will have a handful of basic “GetMap” style methods, where you give a maptype and some settings and get a map in return. I also need to extend the basic map class with a few properties for starting position and entrance/exit. Then map generation itself will need to be updated to account for ways in and out.
If I plan on letting players go back and forth between maps (probably not, or at least not more than once in any direction), then there needs to be a way not only to clear entities from the map when transitioning, but to restore them when going back. Gonna think on that one, but my gut says to not do it. Progress should be forward-only, with “backward” being a return to “town”.
Anyway, I don’t think I’ll get too much done tonight. Work has been a little more draining than usual, and my sleep has not been very good lately, so I’m moving slowly tonight.
2020-03-13
I decided to not pass in strings for the map factory. Instead, there’s now a MapType enum, with the first two slots reserved for STATIC and PREFAB. I like the idea of having a sort of strongly typed set of map possibilities. Plus, it’s easier this way to randomly select a map generation type by picking a random integer within the range of enum types.
In putting together the map factory and the other pieces to allow for smooth map transitions, I’ve realized how scattered some of the map update / drawing code has become – to center the viewport on the player, for instance, can fail thanks to bad order of operations. Or, creating the ScrollingConsole that acts as a renderer for the map itself can fail if I try to instantiate it before the map itself is created. These are small things and very easily fixed, but it’s still a distraction and again I find myself looking at this late at night after a long day and don’t have the energy to do it. Oh, well. That’s what weekends are for, right?
What else am I going to do with that coronavirus out there? 🙂
2020-03-14
Mostly have map transitions working well. A few hitches here and there and there is definitely some more cleaning to do. I’m in phase 1 of this, which is “get it working.” Soon, I’ll be on to phase 2: “make it right.” For now, I just want to be able to hop from map to map without too much hassle.
I redid the main map a little bit to add some hard-coded stairs down and also some light sources. Then I wrote the code for light source entities, made them cast their light, etc., but there’s currently a bug where the player can sometimes not see inside the light source radius of these entities if his own FOV so wills it. Going to file that one under “fix me later”. For now, I kind of like how it is, and will spend my time further refining the flow of map-to-map travel.
Here’s the starting map with its torches:
(Later) I added some TileFlags (which is an enum of bitshifted ints) to allow for StairsUp and StairsDown — later, maybe I will split these flags based on the flag’s purpose, but for now there aren’t many and it’s Good Enough — so when the factory creates stairs I don’t need to do anything else for the map to know where they are. When descending, the player will start on the stairs that lead back up, and when ascending, the player will just pop back to “town”. For now the stairs and placed randomly on a walkable position. When you stand on stairs and ask to go down, you’re prompted so the game is sure you didn’t hit that key by accident. If you say yes, you descend.
For funsies, I made it so I can tap M to jump to the next map automatically. Here’s a gif of me holding down the M key.
I only have three “random” map generators right now: the Big Room Generator, which just makes a big room; the Cellular Automata Generator; and the Random Walk Generator. I think I’ll work on a Binary Space Partition generator next, or maybe just a regular old random room / hall placer.
Week in Review
Feels like I got an okay amount done this week. Pathfinding, dead simple AI, map transitions, static map loading… Not too shabby!
In the coming week I plan to work more on game library stuff. Right now my single monster is a hardcoded entity. I want to take advantage of my SCORLIB library and external data, and generate monsters using a Monster Factory. At first it will just be a small range of monsters, but the eventual plan is to generate specific types of monsters on specific types of “dungeon floors,” where each floor will be devoted to a deity, and the monsters there that deity’s followers. So, with the aggression system, you may end up on a floor of totally peaceful creatures.
All the “hard work” of serialization and deserialization has already been done, so right now it’s a matter of a) actually creating the data and b) plugging that data into the game itself to plop monsters down in the world. Next week.