Making an arcade game with JUCE? Absolutely just look here!

For beginners coming to JUCE, I just wanted to point out that it is entirely possible to make a colorful, entertaining action arcade game with JUCE, without having to resort to OpenGL!

My Breakout game is a modern remake of an old classic, and made entirely with JUCE, and 4000 lines of C++ in VS 2019.


Two player team mode shown just starting in above picture.

Some of the JUCE features I used are; Buttons, HighResolutionTimer, Hyperlink Buttons, Image Buttons, Listeners, MixerAudioSource, and Sliders. Discovered JUCE in late August, initially wanting to make a synthesizer, but soon realized I needed to learn more about C++, so I made this game. And even after a few hours a day since, I still only know about 1% of JUCE’s potential! Sure looking forward to my next project and to learn another 1% :slight_smile:

Main game features;

  • 3 Game Modes; 1 Player, 2 Player Team, and 2 Player One-On-One where players can try and steal each other’s ball(s)!
  • Background music played between games and in main menu. Music fades out as game starts, and in as game is over, or user goes to menu. Music can be toggled on or off.
  • 21 Sound effects.
  • App screen size can be changed from within the game all the way up to full screen kiosk mode.
  • Game speed and level speed increase can be set via sliders.
  • Brick layout can be set via slider from 3 x 6 all the way up to 10 x 20 rows and columns.
  • Brick styles; Regular, black hole (swallow balls and spits it out later in a random place), extra life, morph (each ball hit morphs the brick), power (ball go straight through instead of bouncing), solid (no value but randomly messes with ball direction), and spawn (spawns a new ball).
  • Brick style probability/occurrence can be adjusted via sliders
  • Paddle size and movement speed can be adjusted, via sliders, individually for each player.
  • With precise paddle steering, player can control ball’s ricochet angle and speed
  • Pause and resume option via quick ‘spacebar’ press.
  • Classic pinball style score board.
  • 10 Cool galaxy background images, blending in between levels.
  • Automatic context help text when clicking sliders and buttons.

Check out the video https://www.youtube.com/watch?v=v1oI-cZFWbQ, or get the free self-contained game, just one exe file, at https://dkdivedude.com/?cat=12.

Over the next few days, I will publish some of the source code on my website, but in the meantime, if anyone have any questions about how it was made, please ask right here or on my website.

Without the help from various people on this forum, this project would perhaps not have been made, or perhaps be far off completion, as I must admit the JUCE tutorials, examples, and documentation, was not quite enough for me. I especially wish to thank @cpr, @daniel, @Xenakios, @tobanteAudio, @PluginPenguin

11 Likes

Nice job! Makes me want to try making a game myself…Haven’t really ever got to it yet.

Seriously, making games with JUCE is something every single plug-in developer should do once, you learn so many cool things about UI by doing so…

A few months ago, I had a lot of fun doing a Puzzle and Dragons clone, it was quite hard to have something which looked and “felt” smooth enough, but I was very happy with the result :slight_smile:

3 Likes

did you use the Juce OpenGL stuff?

Not sure if that question was for me or IvanC, but either way, I did not use OpenGL. The smooth graphic of my game was due to the user of the HiResTimer. That way the game is perceived to run at the same speed on both slow and fast computers.

1 Like

it was directed at @IvanC

@DKDiveDude if you’re not using the OpenGL renderer, all painting happens on the Message Thread. You might be offloading some processing onto the HiResTimer background thread, but all of your painting is still happening on the Message thread, and is governed by how fast that thread ends up being serviced by the operating system.

Sorry but in my experience and tests, HiResTimer is totally independent thread. Versus the “standard” Timer that runs on the message thread and in my tests showed it was synchronized with my paint () calls.

Yes, it runs on its own thread, I’m not saying it does not.

I’m saying that paint() is called from the message thread. So whatever stuff you’re running on the message thread will also slow down paint().

You might be offloading some processing onto the HiResTimer background thread

It makes perfect sense for a simulation (which a game is) to run on a separate thread like hiResTimer. That way the movement of object is consistent towards the wall clock.

Synchronisation is achieved via repaint(), that is then handled by which ever backend, no matter if OpenGL or CoreGraphics/WM messages or whatever.

The only question remains, is the drawing fast enough. It seems to be in that case, so case closed :slight_smile:

Since HiResTimer runs in its own thread, and all my graphic calculations were done there, whenever paint() is ready to paint, all screen objects will be drawn at the correct position. And since the drawing done in paint is slower than 1000+ lines in HiResTimer, if both was synchronized that would make the game too slow. Sure paint() is skipping a beat now and then, especially at higher resolution, but that only makes the animated objects move less smooth, something that is very hard to notice during the game.

This will actually jassert if you call repaint() from the HiResTimer callback

Sure, that’s pretty standard game engine design. Update your game state in a background thread. Your drawing thread just displays that state whenever it gets around to it.

I meant the way your request and the actual paint() call is synchronised. Thanks for nitpicking :wink:

You know that’s all I’m good for around here :joy: :joy: :joy: :joy:

Haha, all good :slight_smile:

As I started developing this game, I used the regular Timer, and had independent counter and “time spent” variables each for the Timer and Paint, and I saw that the code executed in Timer was zero milliseconds, but paint was like 50ms. Anyways I then switched to hires tick to calculate time spend in each, to see a more precise time for Timer. Problem with Timer was that on a slow computer, the game was too slow as paint which was synched with Timer, could not keep up, especially at higher resolutions.

Then I moved to HiResTimer and boy what a difference. Now at any resolution and even on slow computers, HiresTimer was doing exactly the number of runs I specified per second using startTimer. Sure now paint was not synced anymore, unless at medium to lower resolutions, or at high resolution on a fast computer. But at the higher resolutions and slower computers, using the thread independent HiResTimer, the perceived effect of the out of synch paint was near nil. Yes animated objects moved a bit less smooth, but playing the game one did not notice.

Check out my YouTube video, which shows 1920x1080 two players and about 10 balls in action.

@matkatmusic Nope, I don’t use OpenGL here, it’s not that useful in my case. However, I use the same approach than @DKDiveDude, I have a HiResTimer with its own thread, and then I call triggerAsyncUpdate(), which then calls repaint().

If you want to prevent the animation of being not smoothed or not synchronised, you can monitor the time between two consecutive paint calls, and use it as your “video sample rate” or current FPS, instead of using the specified rate of the timer. This way, the speed of the elements in the game is always (more or less but that’s better this way) good whatever slowes down the timer thread or repainting.

1 Like

In my case, even though I did not have a lot of animations, the 1100 lines of code in hiResTimer, was much faster than the time it took paint() to draw my background, borders, bricks, balls, paddles, score, level, and lives.

To clarify what I meant when wrote that in higher resolution and/or on a slow computer paint() was less smooth, that is could not keep up (get out of synch with timer), is that on my computer even at highest resolution, the difference was only 2:1, with hiResTimer being executed twice before paint() finally woke up and got out its brushes. So since hiResTimer in the mean time updated coordinates of my animated objects (mostly balls and paddles moving and bricks dissolving) twice, paint() then essentially drew them at an increment of two, since it missed a beat, instead of one, and I don’t think most people would notice, or at least it did not effect game play at all.

In most cases I think the code in hiResTimer will be much faster than what goes on in paint(). Main thing is try very hard not to put any calculations, testing, or branches in paint(). I had 170 lines of code in my Paint() with only 10 simple +/i calculations, 6 for loops each with a simple + increment, and 5 if branches.

I hid some arcade games in a couple of my plugins. I originally wrote them for Arduino, then ported them to Linux (on a RPi board) and finally made an adaptation using Juce that simulates the way an LCD display controller works painting pixels one by one (not ideal for speed but that let me simulate the actual display in a Juce program). One of those was a “Scopa” card game that I also compiled for Android and posted on the Play Store for free.

1 Like

In case you’re wondering… this Android game is made with Juce. Has a low score because it’s not the typical Android game with sounds, animations and fancy stuff… As I said, it was just an experiment and looks raw.