Spectragate




Fixing common Advanced C# Messenger issues

Category : Tutorials, Unity · (1) Comment · by Oct 12th, 2015

In the latest project I’m working on I’m making heavy use of the Advanced C# Messenger. It’s a brilliant script that acts more like a Mediator Pattern than a plain Send/Receive messenger, which is fine with me.

However as great as this plugin is, there are two small issues I ran into pretty quickly.

No Listeners Available

To make ACM (is that an acronym?) work like a true mediator system, it needs to give exactly zero craps about what’s actually listening to the broadcasts. Unfortunately if you try to send of a broadcast and no listeners are setup, you’ll quickly run into this error:

“BroadcastException: Broadcasting message “SaySomething” but no listener found. Try marking message with Messenger.MarkAsPermanent”.

Marking the message as permanent wont solve anything. Luckily ACM comes with a way to fix this: comment out this line at the top of Messenger.cs

This simply disables the check for any listeners before it broadcasts a message. Easy! The documentation on the wikipedia page doesn’t mention it, so unless you connect the dots yourself you’ll go down the wrong path thinking there is an issue with permanent messages, like I did.

Unexpected results when restarting scene in Unity 5.2

This one took me a bit longer to hunt down. You load your scene by pressing the play button in the Unity Editor (so no Application.LoadLevel calls are made) and everything loads and works fine. You then call “Application.LoadLevel” to restart your scene and, no matter how simple your scene is, some messages make it through and others don’t. What the horse?

This bug is because of a breaking change in Unity 5.2: Before Unity 5.2 OnLevelWasLoaded was called before Awake. Now that this has been fixed, any listener events you are setting up in your Awake calls are going to get deleted when OnLevelWasLoaded is called. This is because Messenger.cs automatically calls ‘Clear()’ (which removes all the current listeners) when this event triggers.

The simple fix is to comment out the .Clear (line 304 in Messenger.cs) that happens and call it manually yourself when you are changing scenes.

Unfortunately because OnLevelWasLoaded no longer fires before Awake, there doesn’t seem to be a replacement method yet that can take its place. Perhaps a new OnLevelWasUnloaded method would be a handy?

Solving gaps between scrolling background sprites

Category : Tutorials, Unity · (1) Comment · by Oct 4th, 2015

Note: The background sprites in this blog post were downloaded from opengameart: Forest Background by ansimuz

In the game that I’m currently working on I need an infinite scrolling parallax background behind the player. Because the camera needs to be orthagraphic but support parallax scrolling, I decided to make the world move while the player stands still. Everything was going great until I noticed this:

gap1

I had a damn gap appearing between my tiles – and it wasn’t all the tiles, in fact my foreground seemed to work ok. It seemed to happen more often with very slow moving sprites. After much research I realized that the problem was occurring because of float precision errors in Unity. Basically this coordinate:

gap2

would move a few frames and then explode into something like this:

gap3

The tile at the front of the queue that’s moving ends up with .4599998, but it still has to render to a single pixel on the screen. The camera has to take a guess how to render this and either rounds the position up or down, placing the sprite one pixel too far or short, creating a gap between the tiles. In many 2D only game frameworks you don’t notice this issue because the world unit to pixel ratio is already 1:1, so it’s easier to move around consistently.

My first solution was to round all coordinates down to 3 decimal places – it seemed like an easy fix. However, the gap started to appear again and I realized that I was just now doing in code what the camera was doing when it rendered anyway – taking a precision error and then trying to guess if it should be rounded up or down.

After 3 days of faffing about with different techniques I came up with this solution:

My orthographic camera has a ratio of 1 Unity world unit to 100 pixels (note: You can find more about getting your orthographic scale here). What I realized was that for a sprite to move a single pixel on the screen the absolute minimum distance it can travel in Unity is 0.01 world units. As long as I constrained my background movement to move only in multiples of 0.01 I would avoid any rounding or float precision errors. After all, if something lands in 10.672, how does the camera reliably render that at .672 of a pixel?

I changed my movement code to simply use 0.01 as the minimum distance a sprite can travel, which seemed to work great except for one tiny issue:

gottagofast

It’s way too fast! He’s supposed to be running but not that quick! The problem now is that 0.01 as a minimum distance isn’t small enough. If the backgrounds move that 1 pixel every frame, that’s still 60 pixels being covered every second. The solution was to take the movement code and place it into a Coroutine that runs at different intervals for different layers. For the background, they only shift one pixel every 0.05 seconds, while the foreground moves every 0.03 seconds.

Very simple but very effective. One drawback with this technique (which is less to do with the technique and just pixel based movement) is that you can’t move the sprites with anything that uses floats as its values – this includes transform.Translate, moving using a velocity or multiplying movement by delta time.

If you need pixel based movement in Unity, make sure you are only moving in whole pixel amounts based on your orthographic camera size.

Some final notes

If you find that the pixel based movement for very slow backgrounds is too jerky, you can get sub-pixel movement by setting the move distance to half your orthographic camera size (eg. 0.005 instead of 0.01) and then enable bilinear filtering on your sprites. You will lose the pixel-perfect outline of your sprites, but if your using this on far away objects (eg. clouds) the player probably wont even notice.

Also, pixel-based movement will always be jerkier than sub-pixel world based movement (which can lerp between pixels without just jumping from point A to point B in a single frame). It’s not a silver bullet and it sometimes takes some experimentation to see if the effect is worth it. If you are using pixel based movement however, turning on vsync under the quality settings will also help prevent too much sprite-jumping, owing to the fact that you can’t use time.deltatime to smooth our your frame-to-frame movement.