Published: July 1, 2022
What a week...well, let me try and go through some stuff here.
Probably not too surprising to anyone (least of all me), but the estimated release date for Rhythm Quest has been pushed back from "Late 2022 (?)" to "Early 2023 (?)". Note the question mark ;P
Some life stuff came up and I have to end up moving in the next few months so this is mostly me pre-emptively throwing myself a bone so I won't worry about it as I inevitably spend a bunch of time and energy on that. I may also be taking on some part-time work in the near future, which may provide me with some extra leeway for my timeline (i.e. not feeling like I'm spending as long draining my bank account away while working fulltime on this) while still keeping a good balance. But obviously, if I'm not working on Rhythm Quest 5 days a week my progress will naturally be at a slightly slower pace. I'm not too worried given that a large portion of Rhythm Quest was built during my previous employment, but these are factor that I'm going to be keeping in mind moving forward.
This is a silly small thing, but I finally set up an =actual= webserver (nginx) on my computer to test my websites and WebGL builds locally. Previously I was just using python's simple http server functionality, which works perfectly fine...except it can't handle the gzip compression and associated headers for Unity WebGL builds. So now I just have my localhost webserver start on boot and I can navigate to any of the websites I work on locally (rhythmquestgame.com, ddrkirby.com, cocoamoss.com, katmengjia.com) and test them out without having to kick off a python process. Probably something I ought to have done earlier, to be honest, but eh.
It had been a long time since I had played around with the WebGL demo build, so I decided to plug away at that this week. At some point, I ran it and it looked like this:
...uh, yeah, that's not right. I think this actually just ended up being a false alarm (browser caching issue), but anyways, now it's working just fine and running in my browser locally on the demo page:
As you might be able to see (sorry, it's small), I've also done a bunch of other work to flesh out this page, including adding links to downloadable builds (which don't exist yet...) and the Steam wishlist/Discord invite callouts.
I've also updated some of the text notice screens in the game, for example this one that comes up if you're playing a WebGL build:
Note that save data =should= persist across version updates normally, however this doesn't work on itch.io builds since itch uses a unique URL per uploaded build, and Unity by default persists browser-based save data based on the page URL. I briefly looked into ways to potentially work around this and then decided to just table it for now, it seemed like I should spend my time elsewhere instead...
Although I don't have (or want) DRM on my downloadable builds, I use some rudimentary copy-protection logic to avoid having web builds stolen by other websites and hosted without my permission (and profiting via ad revenue...). As I've learned from experience, this is sadly an extremely common practice when it comes to web games since they're so easy to just download and then reupload.
Of course, my simple javascript checks aren't foolproof -- in particular they can trigger false positives if you've blocked certain web browser functionality that I use to try and determine where the game is being hosted. So I wrote up some instructions on what to try in case that happens to you:
I've also updated the screen that pops up if you click on one of the worlds or features that's not available in the demo (it cycles through various screenshots here). I've added the Steam and Discord links here as well:
I also hooked up a trigger for a separate version of this that shows up after beating the last level in the demo (currently this is level 3-2). I haven't actually built out the overlay itself yet, but it'll probably have a few pages -- something to the effect of "thanks for playing the demo [...] wishlist the full version on Steam (etc)". That's something I'll be finishing up soon, hopefully.
I wrote in a previous devlog about some of the issues I had to work around in order to get a functional WebGL build up and running, including the fact that audio scheduling seemed to be broken (specifically, AudioSource.PlayScheduled seemed to always just play audio immediately on WebGL). I checked at the beginning of the week and Unity has since fixed this issue!.........sort of. AudioSource.PlayScheduled seems to work now, but unfortunately if you want to start the play head midway through an audio clip, you're outta luck as that still doesn't work. Bleh.
On the plus side, I've gone ahead and revamped my hacky workaround for audio scheduling in a few different ways. The basic idea here is that I keep a sorted list of scheduled audio clips (along with the time at which they should be played), and then I continuously poll the list and trigger the sounds at the appropriate times, removing them from the list as I do so.
This isn't new, but one important thing to take into consideration here is audio buffering. When you trigger playback of an audio clip, there's some amount of delay before the audio data is actually played back due to buffers. It's not perfect, but you can estimate this by using the AudioSettings.GetConfiguration API and looking at the dspBufferSize field and account for this by adjusting your trigger times slightly earlier to compensate.
One improvement I ended up making this week was increasing the polling frequency at which I checked the scheduled sound list. Before I was checking this once per frame by using Unity's Update method. That works, but it turns out (for whatever reason...) that if you use the OnGUI method, you can actually have your polling code run multiple times per frame, leading to more accurate timing.
Of course, originally I was looking at AudioSettings.dspTime as my time reference, which doesn't help here because that value doesn't actually update between frames. Instead you want to have something based on a timer which continually updates -- something like Time.realtimeSinceStartup which will return different values even during the same frame. Luckily I already have a system set up for mapping audio dsp times to realtimeSinceStartup and vice versa via linear regression (the previous devlog on this), so I can just plug that in here.
It's still not perfect...in particular WebGL has a lot of issues where the beginning chunk of an audio clip won't playback properly, and seamless audio looping is often broken (maybe something to do with audio compression), but it's passable at least.
I started setting up the demo version of the app on Steamworks (yay!), and while I was going through that, a couple of other things occurred to me to clean up:
First, I made sure that Steam achievements are disabled on demo builds (this is a recommended practice by Steam). The suggestion is to have those achivements automatically unlock when you transfer your save data over to the full version.
...speaking of which, I decided to save demo progress in a different folder than the real game (preferences are still shared for now). Previously the demo simply saved to the same location, which worked fine for a seamless carryover to the full game, but this feels a bit safer -- for example if you try to open a full game save in the demo it might cause some bad things to happen. The full game will check to see if a full game save already exists, and if not, it'll look for a demo save file as a fallback -- at which point I can do any logic I need to in order to convert from demo save to full game save as needed (hopefully not much, if anything).
I'll leave you all with this bonus screenshot of my Windows Jenkins build dashboard, which has exploded since adding all of the separate demo builds (and this doesn't even show the iOS / OSX builds...):
That's it for now...next week I'm going to continue working on and polishing up the demo build to get it ready for release!
<< Back: Devlog 38 - Level 4-2
>> Next: Devlog 40 - Particles and Menu Tweaks