I’ve made some more good progress on the world editor. Here is the full list of features as of today:
- Relatively full saving and loading capabilities. That is, you can save and load terrain changes and the location, rotation, and scale of objects in a scene. Terrain data is saved in a custom heightmap image file.
- Terrain editing including raising and lowering terrain and smoothing.
- Add assets to a scene from a menu.
- Translate, rotate, and scale assets that are added to a scene.
Listing it out, it’s not all that impressive considering the amount of work it has taken to get the editor to this point. Still, I’m fairly happy with it and I’m pretty much at the point I wanted to reach by the end of February, so that’s encouraging.
I think the best course of action is to release a new version showing off the features of the world editor. I’ll try to do that tomorrow. Then I need to spend some serious time actually designing the game. I have a vague idea of how I want the game to look and work, but I can’t develop from a vague idea. I need specifics about classes, races, maps, battle systems, crafting systems, economic systems, etc., etc. So after a version release tomorrow I’ll spend several days, if not more, trying to get the very basics of an actual game planned out so that I can start working on features in a more coordinated way.
Oh, and I guess I need to get an asset spotlight done as well. Hopefully I can do that over the weekend, although designing assets of any value without a real game plan in place is … challenging. Still, I’ll make something generic that I know I can use no matter what.
I’ve been making decent progress on the world editor over the last week. I missed my deadline to do an asset spotlight on Friday because I just haven’t had the time to work on it, but hopefully I’ll get something together this week. In the world editor you can now add assets to a scene and move them around. By default everything just “sticks” to the terrain, but you can move things vertically as well if it’s needed. I probably need to look into a finite state machine since keeping track of all the different modes and sub-modes within the world editor is getting a little hairy. I’ve never used an FSM before but I think if I put the time in to understand it, it would serve me well. For now I’m just going to push forward, but that will definitely be part of a future code refactoring. I need the ability to save a scene out to a file and then I think I will transition back over to development on the game and just add features to the world editor on an as-needed basis.
Speaking of the game, I really a clearer idea of how my world will work and look. I want to create original lore wherever possible and thought I would try to create a new battle system as well, but after thinking about it a bit more I realized the battle system I was imagining wouldn’t work well in a real-time multiplayer environment, so I’ll probably just stick with a classic MMO-style battle system. I would like to make a crafting system that challenging and rewarding at every character level, so I’m thinking that will be a big part of the game. But before I do any of that I need a basic story outline and some ideas about races and classes that will be available when the game first launches.
Last night I finished almost all of the items on my to-do list for another world editor update. Specifically, I can now:
- Zoom the camera in and out so that seeing and moving around a large map is much easier.
- Change the size and strength of the selection sphere. Changing the size is pretty self-explanatory, but changing strength means that vertices move up and down faster or slower (depending on the strength of the tool) when raising/lowering the terrain. This is handy for making big changes, then coming back to fine tune things.
- Smooth terrains. I don’t really like the smoothing functionality right now, but it does work. The problem with it is that all the vertices within the selection sphere move toward the average height of all the selected vertices at the same rate. So vertices right out at the edge of the sphere move up and down by the same amount as those near the center of the selection sphere. Ideally I would be able to choose this behavior, or have the default that smoothing has more effect on vertices near the middle and less effect on those near the edge. I tried doing it this way but ran into some issues with the lerp function in THREE.js. In any case, it works okay for now and I can improve this later.
- Flatten terrains. This tool is super basic at the moment since all it does is set the y value of any vertices inside the selection sphere to 0. Eventually it would be nice to have the option to set the desired flattening height, but that’s definitely a job for another day.
I did NOT make any improvements to the selection tool within the world editor. I looked at DecalGeometry but didn’t really like it. I did some research on shaders but quickly realized I don’t even know the basics of shaders. This doesn’t seem like a feature that should hold up progress so I’m going to leave it for now, but this is something I want to improve eventually and I think learning more about GLSL would be time well spent.
These are some nice improvements but I still have miles and miles to go. I think the next feature to add is the ability to place assets into a scene and save out a map file. I’m not going to worry about rotation or scale right now, just getting some stuff into the world then saving out a map file that can be loaded by the engine. Hopefully this will only take a few days, and I’ll post again when it’s done.
After much wailing and gnashing of teeth I seem to have heightmap saving and loading working properly. Now you can load up a scene, make changes to the terrain height, save the scene, refresh the page, load the scene you just saved, and the terrain changes you made earlier are persistent. The heightmap data is stored in a PNG image that gets stored on the server whenever you save the scene. This has been relatively complicated to get going because THREE.js dropped all non-buffer based geometry. This is, apparently, a much more efficient way to send data to the GPU but it means you can’t just loop through a geometry object’s vertices. Instead you must access the geometry’s ‘position’ attribute array, and make changes there. It’s actually not that much different it just throws my head for a loop because geometries have position attributes as well as indices that define individual faces. I may be overthinking the relationship between the indices array and the vertices array, but in any case it gives me trouble occasionally. But, for now, scene saving is working again.
My next step is to implement camera zooming. It’s really tough to edit terrains efficiently when you can only see the terrain from a fixed distance. I then need to create different terrain editing tools that are adjustable. Right now all you can do is raise or lower the terrain vertices within a statically sized selection sphere. I need to be able to perform other functions like smoothing and flattening as well as change the size and strength of the selection sphere. I also don’t like the idea of displaying the selection tool as a sphere. Hopefully I can figure out how to make it a decal instead that changes appearance based on the size and strength adjustments made by the user.
I’ll be working on these features for the next few days and will post again when they are done. Oh, and happy Valentine’s Day everyone.
I’m making decent progress on the world editor rewrite. I’m miles ahead of where I would be if I had started over from scratch, but it’s still fairly slow going. Every time I start over on this project that I’ve been dreaming of finishing for the last roughly 15 years it gets a little better. I don’t think I’m necessarily a better programmer now than I was 10 years or 5 years ago, maybe I just have better resources at my disposal (I’m looking at you, stackoverflow). In any case, the world editor now loads a flat terrain with a grass texture on it by default. You can open a single (for now) map that only contains a heightmap for the terrain and nothing else. You can then pan and orbit the camera around to look at the bumpy monstrosity of a terrain, and even save it to a heightmap file. Of course, you can’t actually edit the terrain yet so you’re just saving the file back over the one already on the server, but you can do it. Here’s what it looks like right now:
Pretty impressive, huh? Ok, I know it’s not, but it’s a good start.
Speaking of heightmaps, the heightmaps I’m using allow an absolutely huge range of heights but with incredibly fine details. The lowest possible height is -32,768 meters and the maximum height is 32,768 meters, but the height of each individual vertex can vary by as little as 4 millimeters. I will never really need the extreme detail or extreme range possible with the heightmap system I created, but it’s nice to have and doesn’t really cost anything extra in terms of storage or computation over a standard grayscale heightmap. I’ll have to do an entire post on how my system works one day. I’m sure I’m not the first to do heightmaps this way, but I’ve never found any resources describing my system so it might make a good read for someone.
I’ll keep at it with the world editor and make a concerted effort to get a second asset spotlight posted this Friday. Until then.
Penrith was feeling a little bare. I have some friendly trees, a few buildings, even some random fences and water, but the ground was still pretty bare. When walking around it was a little tough to tell if you were even moving because the trees might be far off and since there are places where there is little variation in the color of the ground, it was sometimes fairly unsatisfying. So I created tools to add grass to my scenes. There’s only one type of grass at the moment, and the whole process is Super Unoptimized™ but it already looks 10,000% better.
I also turned on shadows for the screenshot above, so that helps. The tool allows you to basically paint on grass, and it works surprisingly well. Eventually I’ll need to add in multiple type of grass but for now I’m happy with it and will probably move on to something else.
The design of Penrith Forest is going pretty well. A big part of pretty much every game I’ve played in the last several years has been water features, so I thought it was time to try and tackle some water in Lyridia. I’m shocked to say it really wasn’t all that difficult, at least to do the most basic job of getting something that looks like water into the world. I have a large pond/small lake that now has water in it. It even has waves on it, which is quite cool. I need to figure out an easy way to make videos of some of these features because it would be much more effective to *show* the water gently lapping against the shore of the pond than just talking about it, but for now you’ll have to take my word for it that it is cool, and I’m excited about it.
I have now converted all of the art assets for Penrith Forest into glTF files. Before I had a mix of .json, .fbx, and .gltf/.glb files. While I was doing this I created collider meshes for all the assets that needed them. I also added in the ability to load double sided meshes. By default meshes created by THREE are one-sided. This is an optimization that prevents WebGL from drawing triangles that are facing away from the viewer on the assumption that these triangles will probably get drawn over anyway. This works fine for most things but for very small, simple objects like grass and flower petals I need the material to be visible from any angle. This is accomplished by simple putting the word “(Double)” anywhere in the material name in Blender. This name gets exported and the object loading code looks at the name of each material getting loaded, and if it contains “(Double)” it sets that material to double sided. This only has to be done once, when the asset is loaded, so it shouldn’t have any real effect on performance and will allow me to make all kinds of foliage as simple planes.
The next thing I need to do is clean up and confirm/re-implement the terrain editing and painting code. I had this working at one point, but I’ve changed quite a bit over the last several week so I’m guessing it’s at least partially broken. Once this is fully working again, I’ll put some time into the design and layout of Penrith Forest.
I was plugging along converting my tree models to glTF by exporting them out of Blender as .glb files and replacing the references to the old .fbx files in the map when I found a piece of weird behavior. The glTF files I was loading into the world editor moved strangely. It seemed like each individual asset would move differently when selected and moved. This made absolutely no sense because the code to move any object is the same for all objects, but I could see it happening. I’ve now spent a few days investigating this and I finally figured out it was a bug in what I was selecting. My assets are structured like this (for now):
- Scene (Scene)
- Collider (Mesh)
- Asset (Group)
- Asset Mesh_0 (Mesh)
- Asset Mesh_1 (Mesh)
- Scene (Scene)
- Collider (Mesh)
- Asset (Mesh)
When an object only has one material applied to it (which will likely never happen with a production asset) the exported file contains a Scene object named “Scene” with two child objects that are Meshes, an object named “Collider” and an object named “Asset.” If an object has more than one material it follows the same patter except that the object named “Asset” is now a Group and contains children, one for each part of the Mesh to which a particular material is applied. So if the asset has three materials, there will be three child Meshes name Asset Mesh_0, Asset Mesh_1, and Asset Mesh_2.
Updating my selection code to handle both possibilities was not terribly difficult, but it took me a while to actually figure out this structure of the exported files. I’m sure it’s documented somewhere, but I’ve never actually seen it.
The problem I was seeing was caused by selecting the wrong object. If I select the Asset Mesh or Group then move it around, its transform is still ultimately affected by its parent Scene object. So if I move a selected Group like this strictly along the x-axis, but the parent Scene object is rotated along the y-axis, the resulting movement will be unexpected and it will move off of the global x-axis. Since each Scene object is rotated when it gets loaded I was seeing different translation behavior for each object and it was very confusing and frustrating. Now that I understand the structure of the loaded files a little better I can select the root Scene object and move it, and everything works the way I want it to.
One of the primary lessons I’ve learned through this whole project is that I have to just keep looking at it. When frustrations come up, and many have, if I just keep working on it a little at a time I will eventually get past the problem. Just last night I was seriously considering scrapping the whole thing and starting over with a 2d game engine like Phaser. Now I’m glad I didn’t because I didn’t even have to change much to make this work, just invest some time and effort into understanding what is actually happening inside THREE.