Devblog #3: Some minor gameplay tuning

Week three of the project has been a bit slower, but does feature some adjustments to make the gameplay feel a lot smoother

I spent a little less time on the infinite runner project this week so most of the progress has been small adjustments, like increasing the game's speed, making controls more responsive, prototyping the user interface and some small visual adjustments. I'm also looking into reviving one of my older learning projects.

Here's a short gameplay video (also watchable on YouTube):

I'm looking to replace these raw video embeds with Video.js or something, but who knows when I manage to get that done.

Gameplay

After spending some time playing my game, a couple of flaws became apparent. For one, it was way too slow. An infinite runner basically has one mechanic, dodging obstacles, and that becomes boring real quick if the game is not fast enough. I solved this by doubling the player's speed and reduced the traffic density slightly to compensate.

The second main problem was somewhat unresponsive controls. I think the main cause for this was that you couldn't trigger a change to a new lane if you were already changing lanes. The player car's motion when changing lanes is also slightly smoothed, which meant that the car would appear to have finished its lane change even though it was still technically moving. I re-did the player's input handling and it's better now but will probably need some more tuning. In particular, the car's turning animation changes its state only after the lane change is finished which causes the car to visually snap straight after horizontal movement has already stopped.

As for some lesser glitches, whenever a level started it would look empty initially as traffic could only be spawned in front of the player. This meant that the player would need to catch up to the spawned traffic. I can see this being a useful effect in the future, but for now I made each lane's object spawners pre-fill the game area on level start. Now the player has some traffic around them from the start of the level. I had to disable this for the player's starting lane because there was a good chance of getting telefragged by a bus the second the level started.

There was a common problem where an impassable line of cars would spawn in front of the player resulting in an immediate game over. I added a random initial delay to each spawner to reduce the likelihood of all of them firing at the same time, which mitigates the problem but hasn't removed it completely. Sometimes the RNG just doesn't like you. In the final game crashing into something will likely only cost you a life, so it probably won't be a game breaking issue.

Finally, I changed the appearance of the bonus stars. The geometry if now a bit thicker and the color is a friendlier blue. The bright purple looked vaguely dangerous to me and I felt the player might be confused whether they were supposed to pick up the stars or to avoid them. Now it more resembles experience point/player level symbols I've seen in other mobile games. The same icon will appear with the player's level in the UI as well, including the leveling progress bar on top which I added but haven't quite gotten to work yet. How Unity's RectTransform sizing works remains mostly a mystery to me.

Audio

I added a sound effect for when the player picks up an experience star and some background music, both from the Humble Bundle asset pack I bought in December. The electronic music is clashing a bit with the current cheery and colorful look of the game, so I think I'll experiment with a darker, cyberpunk neon lights look at some point.

Persistence

So far the game has had no persistence (save game) systems at all, so all progress has been lost on exit. As a quick experiment I added a wrapper to my inventory system that saves the contents of the player's inventory into a PlayerPref as JSON whenever the inventory changes. It works, but has two flaws I don't like.

First, my inventory item types are defined as ScriptableObjects and Unity serializes these references using some magical internal file ID. It works for now but it makes the save-game file more fragile because if that file ID ever changes, for example if I want to change to a different inventory system, saved games will become corrupted. I'm working on a better system which will reference the item type ScriptableObjects by name instead so I have more control over everything.

To-do

  • The lane change animation needs to be fixed so the car straightens itself out before the smooth lane change finishes, or the lane change needs to finish faster.
  • I thought I could get away with a canned animation when the player collides with something but it's clearly not going to be enough. The player's car and the collided object need to be turned into physics objects just before they collide, with the appropriate forces set, so we get a more realistic collision.
  • Experiment with a night-time environment.

Side note: Rebooting My Sandbox Project

My longest running ongoing Unity project is an open-world sandbox that I started working on in 2017. It's had several names along the years, but is currently called just sandbox. It's never had any significant gameplay, but at its height it did at least have drivable cars. Those don't work right now.

I've kept the project on life support, upgrading to a new Unity version every now and then and making sure it mostly keeps working. This week I spent an evening looking at getting the project going again.

The biggest problem is that parts of the project predate Unity's assembly definition files so it still relies on an old utility DLL of mine. This library contains a couple of pretty extensively used types, like integer vectors from before Unity had its own and a custom, more easily serializable UUID class which is used extensively for cross-scene references.

These types would need to be moved to my regular utility submodules and the old DLL should be removed but that's more easily said than done. I tried moving the code and getting rid of the DLLs but for whatever reason Unity wouldn't deserialize the data from the old types into the new ones even though the internal structure should be identical.

Now I can either migrate to the new types by hand, try writing a script that does it for me or throw away my old test scenes. In any case, the project will live on but throwing away the old scenes would be a shame. There are systems in those files (like cross scene path waypoints, deforming a mesh along a bezier curve, AI controlled vehicles etc.) that I won't remember how to use unless I have a working example to go back to.

Hello. I'm Matti Hiltunen, a Finnish software developer and wannabe game designer. This is my blog about software development, gaming and technology.