More server control

Planning and Development

After 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 Development

Here’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 Development

On 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 Development

The 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 Development

The 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.

Animation vindication!

Planning and Development

See 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 Development

Look 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.

Animation frustration (revisited)

Planning and Development

It turns out that my animations actually were not working correctly on my secondary test machine.  I’ve fought with this for days at this point and I’m ready to just give up on that other machine as a testing platform, but I’ve found something interesting in the process.  It appears that my other machine doesn’t like big numbers.  That makes no sense to me but here’s what was happening.  When I created a test scene with the animated character at (0, 0, 0) the character displayed and behaved fine.  However, when I moved the character and the camera to a far flung location, like (130560, 2, 130560) he suddenly disappeared.  No errors or any other indication anything was wrong, the character was just not there.  Again, this only happened on my lower-powered test machine.  On my main development machine the character shows up just fine at that location.  It’s really weird.  I’m going to create a test suite to see if I can isolate this issue further, but not right now.

The other slightly problematic thing I’m seeing at this point is a little bit of jitter in the character while an animation is playing.  It’s not huge but it seems to get worse the more loops through the animation plays, and was much more pronounced on the secondary machine.  I’ll need to do some digging on this but I may skip it for now just to keep moving forward with the project as a whole.

Next up is creating a simple attack animation then getting some enemies to walk around in the world.

Animation frustration (continued)

Planning and Development

I still don’t understand exactly what I changed but I was able to get my player character’s running animation to play on my secondary test machine.  The process isn’t exactly simple but if I have a .blend file that exports correctly that I can use as a template, and a scene that imports the .json file correctly and actually plays the animation clips correctly, I can handle it.  This is one of the major downsides of not using an integrated environment like Unity.  Since THREE.js has tons of moving parts and Blender has extra-tons of moving parts, it can be a bit tricky to get an asset to move out of one and into the other and maintain the desired behavior.  I’ll still create a tutorial on this process because simple, straightforward documentation on this specific task either doesn’t exist online, or is very difficult to find.  I’m just happy to make some headway here because I was starting to get worried that if I couldn’t figure this out the whole project would end up derailed.  Crisis averted, for now.

Animation frustration

Planning and Development

My simple animations are working in one place, but not the other.  This is very frustrating.  Maybe if I describe it here I’ll magically see what I’m doing wrong.  I develop and test Lyridia on two different machines.  One is a Windows 10 box with an old but ok graphics card and an old but decent processor.  The other is my Ubuntu machine that I wrote about earlier.  For reasons that I absolutely do not understand, when I run Lyridia on my Windows 10 machine I see my goofy animations.  When I run the exact same code in the same browser on the Ubuntu computer, the player character doesn’t render at all.  No error messages in the console, no other apparent problems, just no player character.  I can walk around just like normal, I just can’t see the character.  I know that skinned meshes will work on the Ubuntu machine because the examples on threejs.org work just fine, but I have no idea why the specific thing I’m doing works in one place but not another.  I’ll keep hacking away at it because this is a pretty big deal to get working correctly, I’m just confused.