I’ve implemented two very helpful features in the world editor, specifically for terrain editing. First, you can now change the strength of the raise/lower function. The selection sphere’s opacity gets lower (so more opaque) when the strength is higher, so you can see approximately how much the terrain will be affected by the tool. This is really helpful because when you want to make a mountain it’s almost impossible to use the tool at the same strength as when you are fine tuning the terrain around a building or other asset. Second, I added a smoothing tool. This is super, super helpful. The tool just takes the same selection sphere for raising/lowering and averages the height of all the vertices within the sphere, then moves each vertex part of the way toward that average with each onmousemove. It works almost unbelievably well and has already helped me make the terrain in Penrith Forest like 1,000% better.
Author: Bvckshot
Pigs on the MOVE!
Planning and DevelopmentOk, technically the boars were already moving around but now it’s not all jittery and jumpy. I found a fun little library called Tween.js that does, you guessed it, tweening. I have used the excellent CreateJS suite before and it includes tweening functionality, but Tween.js has examples specific to THREE.js so I went with it for now. In any case my boars are still walking around in a completely random pattern and their location only changes once per second, but in between those 1-second updates the boar model moves smoothly. This tweening thing will probably be a really big part of the whole project because rarely am I going to want anything in the world to just move instantly to a new location. Anyway, I’m excited about how Lyridia looks now and I need to decide what to do next.
More server control
Planning and DevelopmentAfter some more thinking about it and a little bit of testing I decided to see how complicated it would be to have the server completely control the movement of the boars. This involved a couple of steps. I installed THREE.js and a PNG library called PNGJS on the server using NPM. Then I had the server load in the height map for Penrith Forest and create a PlaneGeometry object with the geometry’s y values corresponding to the y values of the height map, i.e. a terrain. Then I moved over the function to calculate the terrain height at each boar’s x, z location and called it at each boar position update, then took the code that calculated the terrain height out of the client piece (to make sure updates were coming from the server) and just set each boar’s y value to whatever the server sends at each update. It works and makes sense.
This wasn’t a ton of work necessarily, but it was a big shift in thinking from the way the game has been coded up to this point. I think this is the way to go with the rest of the game, but I will definitely need to be careful to optimize the server side code because once the world gets very big at all sending updates for dozens or hundreds of entities to dozens or hundreds of connected clients multiple times per second is going to get very expensive in terms of bandwidth and just processing power on the server. It’s entirely possible that these issues will make the creation of a game in this fashion impossible from a practical standpoint, but I won’t know that until I get there so I see no alternative but to push forward and try to tackle challenges as they arise.
Next I’m going to try and smooth out the movement of the boars between server updates.
Piggies in a ditch
Planning and DevelopmentHere’s screenshot showing the boars following the terrain as they move around:
I’ve been thinking about how I want to do things like this. Specifically, how much I want the client to control the world, and how much the server should control. Right now the server only keeps up with the x and z coordinates of each boar. The client (browser) then takes those coordinates and figures out the terrain’s height at that point, then draws the boar there. I’m doing it this way because determining the terrain’s height requires access to the terrain data as well as the THREE.js raycasting function, and giving the server access to that information would make it much more complicated so I just haven’t done it yet. This probably isn’t a workable scheme in the long run. Soon enough I’ll want players to be able to attack the boars, but to do that I’ll need to know if the boar is within the player’s attack range, which will require definitive information about the boar and player’s x, y, and z positions. In order to prevent cheating or otherwise messing with the game, I think I’m going to have to assume the client is completely untrustworthy. It’s basically a terminal that displays what the server tells it to.
This is, of course, not the final answer on this topic. It’s something I will need to do much more research and testing on because I’m making some significant assumptions to come up with the conclusion above. But for now the boars roam around on the terrain and everyone is happy.
Animations workaround/fix
Planning and DevelopmentOn the THREE.js Discourse forum one of the suggestions I saw concerning my animations going wacky at large distances from the origin was to just put the SkinnedMesh at the origin, then move the world around it instead of moving the SkinnedMesh through the world. The end result should be the same. This seemed like a reasonable suggestion (although it doesn’t really address the underlying issue) but implementation seemed like it would be a real pain. Well, circumstances sort of forced me to give this a shot and after some fiddling I figured out I could accomplish this with 4 lines. These two go at the beginning of my update loop:
scene.position.set(0, 0, 0);
scene.updateMatrixWorld(true);
This puts the scene itself at the origin, then tells THREE.js to update the transform matrices of the scene and all its children. At least, I think that’s what it does. Then at the end of the update loop:
scene.position.copy(player.position.clone().negate());
camera.position.sub(player.position);
This moves the scene away from the origin in the opposite direction the amount the player is away from the origin, so it puts the player at (0, 0, 0). It then moves the camera so that it is looking at the player’s new position at the origin.
That’s it. It’s that simple. Now my animations play smoothly and I didn’t really have to change much. The center of the world is still at (130560, 0, 130560) and the player and enemies can move around all in that space, but when it gets rendered the system sees everything as being centered around (0, 0, 0).
I’m still looking forward to a fix in THREE.js r94, but if this works I may keep it this way even after the fix. Eh, we’ll see.
Animation update
Planning and DevelopmentThe export process has to be done just exactly so, but using FBX files looks like it’s going to work. I have a player character with terrible run, jump, and punch animations. When I move around in the scene the run animation plays. When I hit the space bar the jump animation plays. When I hit the ‘1’ key, the punch animation plays. The controls to transition between these actions or to play more than one at a time don’t exist yet, but I believe the animation system in THREE.js has fairly decent mechanisms to accomplish this. Next I need to work on my enemy pigs.
Happy Memorial Day everyone.
Animations are driving me crazy
Planning and DevelopmentThe reality is that the pipeline to use animated models exported from Blender into THREE.js just isn’t really ready yet. The glTF format is recommended for importing models into THREE.js going forward, but the Blender glTF exporter isn’t complete. It can only export a single animation per file, which is obviously insufficient for a game. Someone is working on improving the glTF exporter, but it’s impossible to know when that work will be done. I saw a thread on the THREE.js Discourse site mentioning the possibility of adding the option to play animations based on a range of frames. That would work just fine. I could just put the idle animation in the first 30 frames, the walk animation in the next 30, the run in the next 30, etc. Unfortunately this improvement isn’t on the roadmap for any particular release, so it may not ever be included.
I think that for now, until the glTF exporter is improved, I’m going to use FBX files. I don’t like that it’s a proprietary format, but it works in Blender and THREE.js today. Since the source files are all saved in Blender anyway, so when the glTF exporter is completed I can just re-export everything in that format then modify the game’s code to import glTF files. This creates more work for me in the long run but it also provides a way to move forward with the development of Lyridia.
v00002 (2018.05.24)
Release AnnouncementToday I’ve release v00002 of Chronicles of Tright: Lyridia. You can play by going to the Lyridia page in the top menu, or by clicking here. Things added in this version:
- Simple multiplayer support
- You can’t really interact with the world, but if multiple people are playing you should be able to see multiple characters walking around
- Basic animations
- Animations are actually a bit of a mess right now due to a bug in THREE.js. Hopefully they will get better after a new release in a few weeks.
- A starting point for adding enemies
- Right now there are 10 boars roaming around a specified region of Penrith Forest. You can’t interact with them and they don’t even move on top of the terrain, but it’s a start.
On a side note, I have added support for a development version of the Node server that runs the game. That means my development activities won’t break the game that’s running live, which is always a positive.
Check out the new version, and leave a comment with what you want to see added next.
Animation vindication!
Planning and DevelopmentSee this post: https://github.com/mrdoob/three.js/issues/13288
It turns out the issues I’ve been having with animations are not in my head and are not isolated to me. I’ll need to wait until r94 comes out before it’s fixed, but I can handle that. When doing calculations on skinned meshes that are very far from the origin the numbers get very big and apparently very inaccurate. Someone much smarter than me with the handle “denbo-ft” suggested to someone much, much smarter than me who goes by “mrdoob” that skinning computations should be done in local space, then the final product translated in world space. Mrdoob liked the suggestion and it looks like it’s on the road map for r94. My animations may look weird until that time but hopefully when r94 is release around June 13 everything will look better. If not, I at least know what the problem is and could theoretically change the way I’m going things to avoid this if necessary.
Starting with enemies
Planning and DevelopmentLook at these lovely little piggies:
I realize, again, that it’s hard to get a real sense of what’s happening here since it’s a still frame but the boar models are moving around in a random pattern. Every 1 second the server sends an update to every client with the new location of each boar. Each boar moves a random amount in the x and z directions and stays within a certain range. This is super basic functionality but it’s neat because it’s controlled by the server so every player sees the randomly placed boars in the same places. Eventually I’ll need some actual “intelligence” in the ways the boars move around, but for now this is ok.
You may have noticed there’s no player character in the screenshot above. I’m still struggling with getting that working on my secondary machine that I’m using today. Also, the boars don’t react to the terrain. That opens a can of worms I’ll have to handle eventually, specifically how much of the game is running on the server and how much is in the client. For instance, should the server somehow load the entire world and make decisions about collision detection, terrain height, etc., or should I leave much of that to the client to just tell the server what the world is like? I’m guessing it will end up as some sort of hybrid between the two, but that’s definitely a design topic I haven’t tackled mentally or in the code, so it will be fun to figure out eventually.
Lastly, I installed Forever on my server so that I can leave the Node server running all the time. Since the next release will include multiplayer (and now some random boars) it becomes dependent on the server running all the time, and Forever allows me to do that.