GrayScale – dev log #2
After a few small updates to the GrayScale I’ve realised that my previous concept of timing and physics was completely wrong! In short: I believed that firing extra physics steps when the timer missed 1/60 th of a second was a good idea. But what changed?
I’ve also spent some time on graphics. Preparing terrain tiles for Tiled is difficult but the results are fun to look at and really speed up level design. The bit challange is to make compatible tileset that will work with Tiled, It needs many combinations.
Cmera from the last HaxeFlixel version of GrayScale was simply awesome:
- It smoothly followed character while it was moving around
- And limited the distance from camera’s center to character (deadzone), so player can always see where he’s dashing to.
You can find the example GIF of “old” camera movement in my previous GrayScale – dev log #1.
Until now only smooth-follow was implemented, and It looked pretty. But the gameplay is too fast for it. Player can quickly dash in a direction, and now not all enemies/obstacles in front of you are visible.
First try at implementing dead zone failed. I couldn’t get the character to stay still on-screen while player was moving straight. The sprite always stutters where it’s on the edge of dead zone but should remain still. I kept trying different camera settings:
Tight smooth follow, without deadzone
As you can see (or not) the character (white box) doesn’t stay still in one position, relative to camera view, when moving straight in line (tiny stutters). This won’t look good after I add character sprite to it.
Ring deadzone without smooth follow
Interesting approach? I forgot why I thought that would feel good in-game. The white ring here only represents the zone, it wouldn’t be visible in-game (duh).
Camera makes weird sudden moves in arc when player dashes in straight lines. See below for ring deadzone with smooth follow.
This one is almost perfect! The box doesn’t stutter when it’s pushing the edge of deadzone. This one is probably going to be a winner when I add smooth follow to it. I can’t do it right now, because I broke the build while working on something else 🙂 That’s the price when you’re trying to work on many things at the same time.
This is me, not knowing how to do math properly. The original was stuttering faster than strobe lights, gif recorder couldn’t keep up 😀
Physics & timesteps (i was wrong)
My predictions from the last dev log about timing and physics were completely wrong. It was working fine when there were not much enemies around. The problem appeared with more enemies and bigger maps, when the FPS drops a bit. I took a closer look at dashing mechanic.
Here;s what I tested:
- Pick a place against a wall. Lets say you have the wall to the right
- Dash into the opposite direction – left
- Note where you stop dashing
After second try I could clearly see that the same movement gave different results. Moreover, landing position was biased more when the game got less responsive. I cannot predict that every future player will have mega powerful computer and they wouldn’t notice that difference. I had to fix it.
After couple of Google’d articles about fixing time steps I found solution in here: Fix Your Timestep! This article is from around 2006 but it still shows the accurate solution. The previous test case gave the same results after implementing this method. Go read it (after you’re done with this post 😉 )!
Big maps, performance hit
Bigger map = bigger laaaaagg. In early builds, waaay before the dev log #1, I remember not being able to even load the game with a big map. It was like 512 tiles x 512 tiles (with 16 px tiles). The game just stopped responding.
Now I started getting the same issue when the small sandbox map got twice the size. Quick glance at luxe debug console revealed that I had tens of thousands vertices “visible” in game! Clearly, not all of them were visible by player, but the renderer didn’t care. It grabs all the tiles it can and turns them into geometry with textures and all that, even if that geometry is 3000 pixels away from the camera.
This problem had a simple solution – hide all tiles out of camera bounds, or technically speaking – make sure that renderer won’t grab distant tiles.
And thus ViewDistance component was created. The name is a little misleading, because It can only work on Tiled tilemaps but whatever. Here’s what it does:
- On init – hide every tile
- Every x miliseconds – show every tile in camera bounds; hide every visible tile that’s outside this bounds.
I’m extra sensitive about performance (whenever I remember to remember about it). Running this component on each update sounded like an overkill. Component would try to check if a tile just went out of bounds, even if player moved by just 1 pixel (or less…). So ViewDistance compnent runs 30 times per second instead of… 60? hundreds?
update() function fires whenever it can. The time can be different on native and web builds, native builds have much quicker update times. PERFORMANCE, YAY!
If you followed my last dev log, you probably heard about Director. It supposed to be a singleton that knows everything about everyone in the game. I decided to drop it. For now it only had 2 functions:
- Get reference to the current physics engine
- Get reference to the current level
2 different type of entities referred by a third one?! Nonsense. I ditched it in favor of static functions in Level and MyPhysics classes. Makes more sense to get level reference directly from Level class.
Finally, something actually gameplay-related finds its way into my code. Health component. Right now It has all the basic functions and properties like: increase, decrease, kill, event listeners etc. I can’t test it though… I can’t die in game, nothing is doing damage, because collisions are still shit.
- Health/Damage – the game is nothing without it
- Collisions – maybe try and implement quad trees for faster calculations. I get huge hiccups with ~20 squares running about
- Make Terrain generation tool using mint from snowkit
- Design the world – finish the world editor also using mint
Progress on this game is really slow. With hundreds of “todo” cards on Trello it’s hard to stay in focus. I’ve decided to start planning sprints (agile developement?). I pick 2 or 3 cards and plan to finish all in 2 weeks. Those cards are the only ones that I should care about in this sprint. After that, pick other cards and set new sprint.