This is the fifth week of my Game a Week challenge. I didn’t have a clear goal this week but things really came together once I started experimenting on Friday, and you can download and play the result here.
The paddle follows the cursor, use a and d (or left and right cursor keys) to tilt the paddle slightly. Use the ball to destroy the blocks! I’ve clearly taken inspiration from the Breakout (or Arkanoid) series, but added a physics-y twist.
I didn’t have a concept for the game all week. When I started developing on Friday I decided to start with the paddle and ball, and see how it felt. I got the paddle control feeling good (using Unity’s built-in 2D physics system, a wrapper for Box2D) simply by making it follow the cursor up to a set max speed. I added the ball in and tweaked its mass, the physics materials on each, and the gravity until I felt it gave me a good amount of control over the ball. I was actually surprised at how natural and satisfying it felt. I didn’t change any of these parameters throughout the rest of the development, for fear of breaking that nice heavy feeling. I put a demo level together with bricks that fell on contact, and the game had basically put itself together at my fingertips.
The development itself was reasonably smooth, but there were a few unexpected and irksome issues.
Keeping Bricks Set
I thought making the blocks stay put until hit would be trivial. I initially tried just by explicitly setting its transform every frame until it became unset, but this resulted in some weird squishiness when blocks fell on top of it, like the other blocks were sinking into the stuck block. I didn’t like it, especially how it contrasted with how solid the paddle and ball felt, so tried a couple of alternatives.
The next solution I tried was simply setting the bricks’ isKinematic field to true until a collision with the ball. This keeps the bricks stuck firmly in their places when other bricks fall on top of them, which was good, but when hit with the ball the result was completely underwhelming. Updating the kinematic property in the OnCollisionEnter function would not update the object itself until the following frame, after which all the force from the collision had dissipated as the ball had effectively hit a solid, unmoveable object. This meant the ball and brick would both just fall limply after each hit, which didn’t look natural or feel good. I was running out of time at this point and searched for another alternate solution.
What I ended up doing was using the exact same function I used to make the paddle follow the cursor. Each brick knows its desired position and has a max speed at which it can return there. Every frame, if it is not at that position, it moves there as fast as it can. This eliminates any weirdness that setting the position outright seemed to cause, and gives each brick a nice springiness. Most importantly, they act naturally both when hit with the ball and when other bricks inevitably pile up on top of them.
My only gripe with this solution is that it makes the ball very prone to getting stuck between bricks. If you play the game for any amount of time you will probably get it completely stuck between three or more bricks multiple times. Fortunately implementing an “is the ball stuck?” algorithm was deceptively simple: it just times how long the ball is within a certain distance of a point, and once it exceeds that difference it takes its current position as the new reference point, but if it doesn’t move far away enough from that point after a few seconds, it lets the game know the ball could be stuck. This works fine, and monitoring if this happens a few times in a row lets the game know if the ball is very stuck and needs to be reset, but it doesn’t make for very satisfying gameplay. If the game were to be developed further something would need to be done to prevent this situation as much as possible.
I had an idea for a brick type that would stay set for a number of hits, but have an extremely bouncy surface, like a bumper on a pinball table. I thought this would simply be a case of setting the physics material to something with the maximum bounciness, but when I actually implemented it this wasn’t the case. The ball would just bump off it like it would the other bricks, with no noticeable change in its speed. I tried a number of things, including setting this specific brick to kinematic, thinking the springiness described above would be the problem, but even when kinematic the ball didn’t react as expected. Instead of bouncing off with equal speed, it would hit the brick and lose all of its velocity!
I was truly stumped by this. I made a brick that had all the exact same properties, but did not have the actual Brick script component attached. This worked exactly like I had wanted it to. But as soon as I put the Brick script on it, it broke again. It was Saturday evening by this point and I was itching to move on, try a couple more brick types (the dark blue ‘sensitive’ bricks and pink ‘picky’ ones, specifically), and implementing this kind of brick would clearly take some special-case code, rather than fitting into the easily extensible framework I’d written for integrating unique brick properties.
In the end, I didn’t think it would be worth the time investment, and had to shelf the idea. It’ll be on my mind for a while though, since the behaviour was so counter-intuitive and I feel that the solution would be something stupidly simple. Oh well.
Sunday Night MissingReferenceException
Imagine my horror, on Sunday evening, after finishing six of the levels and thinking the end was in sight, when I noticed that the orange bricks routinely threw up this error:MissingReferenceException: The object of type ‘StrongHitBrick’ has been destroyed but you are still trying to access it.
I had noticed it before in the form of a complete crash, but it had been very rare, only happening twice. At this point, though, I was able to reproduce the exception very reliably, on a certain few bricks each time, and only ever on the orange bricks. These bricks are unique in that they utilise a coroutine in order to slowly reset the colour (which corresponds to the value being stored for the cumulative velocity with which the brick has been hit with in the preceding few seconds). I suspected this difference would be the perpetrator somehow, but removing the calls to start and stop the coroutine just moved the exception to one of the following lines of code. Something, somewhere, had gone terribly wrong.
Looking at the exception itself, it seems obvious; I’d destroyed something somewhere I shouldn’t have. But the error was appearing within the object that it was trying to tell me did not exist! After a bunch of debugging I managed to get a breakpoint that explicitly confirmed this; the object that was calling the function, which was again within that object, was itself null. This hurt my human brain.
Regardless, I plunged further into the depths and inspected the one place I thought this could have been. In order to minimise the number of objects I was enabling and disabling all the time, I’d set the bricks up to all use the same base prefab, so that I could use one object pool for all of them. Each level is simply a list of objects that state the position, rotation, scale and BrickType for each brick in that level, the BrickType being an enum that I can use in conjunction with a bunch of derived classes that dictate the colour and have functions to enable the unique property of each brick. Essentially, it’s using the Bridge software design pattern to allow the same brick to have multiple different properties and functions.
I initially had the class that stored these differences (BrickProperties) as just an abstract parent class, subclass of nothing. But in order to enable the coroutine functionality in the orange bricks, I changed it to derive from MonoBehaviour. This meant that rather than instantiating a new subclass of it in each brick, I needed to jump through Unity’s hoops by destroying any existing components that are one of the subclasses and then adding the new version as a component again.
I found this piece of code and hypothesised that in the instances where the component being removed and added were of the same type, Unity was tripping over itself and not handling the case, due to the actions occurring in the same frame and not necessarily in the order that I had put them in the code once they reach Unity’s lower layers.
I changed the code not to destroy the component if it was the same type as the one that was going to be added. The AddComponent function simply doesn’t add the component if it already exists, so that was handled. The Initialise function I had in each component would also reset any variables anyway, so reusing the same component for different levels would also be covered.
I crossed my fingers and tested the game again. It ran perfectly! No bricks at all were causing any trouble.
So the solution makes sense, which is always a bonus, but I’ve still got no idea why it only seemed to be occurring on orange bricks. It could either be some crazy coincidence, or there was something else going on deeper down.
Anyway, if you’re getting that MissingReferenceException and you’re sure your code is watertight, check whether you’re potentially destroying and adding the same component from and to an object. Maybe that’s it.
Most of the actual game design for this happened while I was experimenting, which I covered at the start of the Development section above. There’s still a few things I can highlight, though.
The ball was initially just a single colour. I made the initial test bricks the same colour, which was fine for testing, but when it came to making the levels and finding out whether the game was fun, I had two conflicting interests:
- The different blocks must be a vibrant enough colour that the player can easily see the difference between them
- The ball must stand out
Fortunately this all worked itself out when I decided to make the ball two-toned in order to make spin on the ball visible. I kept the original blue I had given to the ball, to make it suit the blue hues of the level, but gave it red marks in order to tie it to the paddle as well, making them the only two red objects in the game. In the end, I really like the look this achieves; it makes the ball visible at all times, and the effect of spin when the ball lands on the paddle is very obviously visualised before the event. As I stated before, I find it very satisfying to control the ball, and most of its actions feel deliberate, which is something I wasn’t sure would work from relying purely on physics-based control.
I am sad that I didn’t have time to find and include any audio in this one. It would have been a no-brainer to make the game feel better. I considered adding a bunch of the other techniques described in the highly relevant ‘Juice it or lose it’ talk, but ultimately did not have enough time. I only started coding on Friday, though, so I think for three days work the game turned out pretty good.
So, to conclude, I quite like this game. It’s probably the game I’ve made during the Game a Week challenge that I managed to playtest the most, which I think helped round it out a lot. My only gripe is the ease at which the ball can get stuck. You can see in a lot of the level designs that the blocks slope in order to let the ball roll out if it gets into certain positions, but if you launch the ball between cracks in the bricks there’s nothing stopping it from getting very stuck, a lot. I’m looking at you, levels 8, 9 and 10.
But other than that, I like the concept I feel it could be easily expanded, and I like the controls. I spent a lot of time throwing the ball up and down just to see the effect of its mass on the paddle. It feels good to me. Anyway, I’m more interested to know what you think, so if you do have any feedback please don’t hesitate to contact me.