6. Live Dev Log


Introduction

I thought it would be cool to do a live development log for this weekend, so I will publish this one as soon as there is a decent bit of content. This is instead of writing it one go after I have done all my work for the weekend.

I will be coming back to it and adding more sections as I work on the game over the weekend.

16:00 - 14/04

Finished my sentence at work. The agenda for the evening is as follows.

  1. Go to the gym.
  2. Finish off the menus for this project.

18:45 - 14/04

Picking up from where I left off, the pause menu worked to an extent - that is, you could pause and resume the game, but there was no navigation. First port of call is being able to navigate to and from the main menu.

2000 - 14/04

I have build main menu navigation into the pause menu, but it unfortunately does not work at all. I'm re-using my level and menu transition system from a previous project because it's pretty robust has saved me a lot of time on this project so far. It definitely works fine - it just doesn't want to function with the main menu navigation. The weird bit is that the same system works fine when transitioning between the main menu and the game, and even between levels. Hmmmmm.

2230 - 14/04

I have been staring at this for too long now. My code is now riddled with debug messages that I've jimmied into the execution flow in order to see where it is falling over. The code is getting to the point where it triggers the fade out animation, which hides the gruesome deconstruction of the level from the player, who would otherwise surely vomit at the site of it. At this point, we wait for the transition to complete before we start tearing the levels down like a bloodthirsty barbarian waiting for darkness to fall. Unfortunately, the execution flow just silently stops. No pillaging to be seen.

I've removed the wait-for-seconds instruction and replaced it with a wait-for-end-of-frame  instruction, and this helps. The loading process successfully fades out and then loads/unloads all of the relevant levels, however it doesn't fade back in. What?

2300 - 14/04

I am getting no where. I will go to bed and come back to this tomorrow with a fresh head. That usually helps. I am bracing myself for a painful rebuild of the level transition system to see what the issue is.

0945 - 15/04

I have known for a while now that coming back to a problem the morning after a good night's sleep works wonders - I wonder whether they've tried that for global warming. Despite knowing this, I still sank way more time than I should have into trying to solve this problem yesterday evening. It  spent a mere 15 minutes solving the issue this morning.  The 15 minutes was distributed as follows.

  • Minutes 0-12: opening the project and reminding myself where I was.
  • Minute 13: The lightbulb moment regarding where the issue could be.
  • Minutes 14-15: Fixing and re-testing the issue.

The total time spent on this problem, however, was four hours.

I've copied a screen of the code that was causing me the issue below. See if you can spot the issue. Answers at the end.

Pause Code Error

The section of code causing issues with the return-to-main-menu feature.

1233 - 15/04

I have built in the ability to exit the application from the main menu. It's all kind of slapped together a bit, but I think it is good that I am easily able to tap into existing systems to do what I want. To get the application exit working, I had to do the below.

  • Add a new ApplicationExitEventChannel type derived from my EventChannel ScriptablObjects
  • Create an ApplicationDeinitialiserBehaviour
  • Create an instance of the event channel above
  • Set the MainMenuViewModel class - the code that sits behind the main menu UI - to broadcast on the above event channel
  • Set the de-initialiser to listed to the above event channel
  • Set the de-initialiser to trigger a scene change - and therefore using the existing transition system to do a nice fade out - before closing down the application after waiting a second or so.

Of course, there is probably a better system, and it will likely need to change as the game matures, but it really didn't take me long to put together, and I accredit that to the scriptable-objects-as-event-channels approach that I learned from the Unity open project.

That being said, I did proceed to spend what felt like an age getting the project to build. I had a lot of engine-editor-specific scripts incorrectly bundled up with my game scripts. When trying to build the project, it failed to compile because editor scripts are supposed to be excluded from the actual game build. I had to sort out my assembly definitions, which meant re-compiling the entire project every time I made a change. This took a minute or so with every change, and I had to make a lot of changes lot whilst I fumbled around figuring out what needed to happen. Definitely one of the more mundane parts of making games.

After all that, the build didn't even work.

1528 - 15/04

I found that my initialisation of the levels from start-up through to the main menu were off. This means that you were neither able to progress past the first level nor open the pause menu because the SceneSequencer didn't know what they were. I decided to come away and have a nice healthy lunch. I also had a lot of pots to wash, so I did those too. When I can back, I quickly drew a diagram of the game's initialisation process because that's the kind of thing I do, and I implemented said diagram shortly after.

It now works as expected, but it definitely feels very cobbled together. I made sure to unsubscribe from all the event subscriptions I was throwing around so that I don't get memory leaks. For clarity: a memory leak is when the code is so bad that the ones and zeros face their existence in the executable. They therefore conspire to drill a hole out the side of your computer in order to escape their destiny and not have to run anymore. This does unfortunately mean that contents of the hard drive seep out of the computer, rendering it useless and making a mess of your desk/lap. It's a good job I know what I'm doing!

The solution feels cobbled together, but there is no point trying to tidy it up now. My requirements are likely to change drastically as the game grows. I know I would like to build a level selection menu, so I will probably revisit it all then. I'm also not going to bother writing any unit tests at this point.

I now have an executable version of my game, which I might upload as a WebGL build once I've downloaded the engine components that will allow me to do so.

1612 - 15/04

WebGL build is taking a looooong time.

1641 - 15/04

Uploaded a pre-prototype WebGL build to itch.io. It didn't work. According to this, it could be the compression settings for my project. Re-building now.

1646 - 15/04

The above update worked, but the project still doesn't work because of some #if UNITY_EDITOR pre-processor directives in my code. I can't be arsed with this now, so I've taken the build down lol.

2003 - 19/04

I've thought about this post more since I last wrote, and I no longer think this was a good idea - in particular, I don't think I should have published it before I had completely written it. Doing so just meant that a half finished dev log was posted, and no one is really going to come back and check for updates, so I've effectively just published a half-completed job which isn't good. Nevermind - you learn from your mistakes, not your successes. The rest of the post is just a write up of the rest of the work I did over the weekend since I didn't write it up as I was going along.

15/04

I came away from this at some point on Friday. Looking at the log on the Github repo, I started work on getting some artwork for the player into the game. The player is no longer a light blue circle, but rather a little pixel man. I used artwork I found on itch here. I think the style and theme fits well with my idea - I can imagine my little time traveller running around in a lab better than I can imagine him running around in an RPG forest. Trever Pupkin will definitely be getting a mention in the credits.

I will probably use the lab artwork to skin my prototype in the first instance so that I can keep moving it forward. I don't want to get bogged down in doing artwork myself just yet. It makes more sense to use someone else's first so that I can get all the code in place. I will then be able to just drop alternate artwork in when it's all working and I have a better idea of what I need.

16/04

I didn't work on this project on Saturday. I had a house viewing at 1430, so I basically did some research for this in the morning and then left at 1315. I then just hung out with a mate in the sun for the rest of the day before going to a pub on King's Street in the evening. Nice.

17/04

I went around to a friend's house for a big Easter meal, so I was out of action for most of the day again. I did manage to sneak in a fair few hours in the morning. I spent my time re-writing the code for the player's movement. It worked fine, but it was a bit all over the place. It was one of the first things I had put together, and the integration of actions with the timeline had matured significantly since then. Since I was going to be working with the player movement system more to get the character artwork and animations in, I think the refactor was justified.

I fully re-built the player and the clone prefabs. Up to now, they were completely independent, but they share a lot of common functionality. I made a single base prefab (_PlayerBase), and I have a Player and Clone prefab variants that inherit from the base. I'm effectively using the base prefab as an abstract class rather than having the clone inherit from the player. I think it's cleaner this way - each thing inherits only the items that are truly shared.

I also wrote some nice extension methods to capture code that I was writing again and again. If you don't know what extension methods are and you are a C# developer, you should definitely read about them and start using them - they are super nice. In particular, you can write extension methods to interfaces, not just types.

I wrote some methods that can help me check for missing injections in my game object scripts. Since I am primarily using the Unity Inspector to inject dependencies as either scriptable objects or other components, I'm not notified that they are missing until they are consumed and I get a NullReferenceException. The methods I wrote all me to generically check the presence scriptable object and component injects at start-up, which is useful. For components, the methods will actually handle the injection for me and just flag a warning, which is nice. Since I wrote the extension methods to apply to an interface, I can just apply that interface to a class in order to make use of the methods. This is great because I don't have to change the underlying type.

18/04

After tidying up the player movement the yesterday, I then started to feed in the artwork and the animations. This was significantly easier the refactor, so it definitely was a good use of my time. I had to spend quite a bit of time getting the clone animations right. Since he was going back in time, he needs to face the opposite direction to the one he's walking during the rewind phase. During the replay phase, he then needs to face the direction in which he's walking. I use a scriptable object to inject this functionality into the PlayerMovementBehaviour class. I have an abstract SpriteFlipUtility, and then I derive a PlayerSpriteFlipUtility and a CloneSpriteFlipUtility from that. I then just inject an instance of each one into the relevant game object. This allows me to use the PlayerMovementBehaviour script for both the clone and the player. Nice.

I had two separate sprite sheets for the player and the clone. They were identical in layout - only the colours of the character differed. At first it looked like I would have to slice up the sheets individually, which would have been long and error-prone. I found this very useful unity forum post that gave me a neat little hack for copying the slicing from one set of sprites to another. You can effectively just copy the contents of the .meta file and then do a find-and-replace. Pretty neat.

What Next

In addition to the player movement refactor, artwork and animation, I have switched the movement to be continuous rather than incremental. This looks nicer, but it presents some challenges with the timeline. The continuous movement currently takes 0.2 seconds to complete. It is possible to press a move button several times in the window. Since the movement is grid-based, it can throw the player off of the grid, which is not good. It additionally wreaks havoc with the timeline. Fortunately, this isn't a blocking issue - I can just not button mash whilst I am developing.

Unfortunately, I am not really sure what I want to do about it. Do I want my movement to be continuous? If so, do I ignore button presses made whilst the player is already moving? That feels like it would be annoying, so do I just add them to a queue and fire them off sequentially after movement animation is complete? This feels imprecise. I initially wanted to be able to press and hold the move buttons, however this doesn't align with the discrete, command-based way in which I record movement on the timeline. I've wondered whether movement should be recorded on a separate, more continuous timeline to discrete actions.

One thing is clear: I have a bit of head-scratching to do.

Answers

In the Unpause method, I was not setting the Time.timescale back to one after setting it to zero in the Pause method. This means that the wait-for-seconds instruction as part of the level transition just doesn't work. How can you wait for a second if time is not passing. Deep.

Get Time Travel Prototype

Leave a comment

Log in with itch.io to leave a comment.