Designing Marble Puzzles (Patreon)
Content
I figured would journal about this world as I went along. It all started with a random idea I had one day after a nap, the vague idea of a “roll the marble” game.
Usually one of my game worlds starts with a genre I remember/discover or some other existing game. Sometimes I just sit down and brainstorm how I could iterate on older game worlds with new twists or themes. Today, I wanted to start from scratch and expand on the “marble” idea specifically because it’s really simple and could be used at a tutorial. Basically there's a marble that starts at one point and you have to place blocks so that it rolls into the end goal. Each level would give you a different start and end point, as well as different blocks that you're allowed to use and some obstacles between the two points that you have to build around.
What really gets me excited is the prospect of spending very little time on something, but getting a lot of gameplay time out of it. For this idea, I think it would be really easy to simple add more levels and blocks without much extra work at all. I really do think anyone could follow these steps and clone this idea, change it in any way, adding more levels or blocks of their own, and I actually encourage it because honestly the idea isn’t really grand or anything, just really simple.
Sometimes I also worry whether an idea is too unoriginal. I think there's a VR game on steam that's like some kind of Rube Goldberg machine simulator, but this would be cooperative. Plus it's such a simple idea that I’m more excited to try my own take on it, not discouraged because something similar might already exist.
I also like this idea because it meets some criteria I have in my head:
-VR motion controls make it really interesting, but you could still play it in desktop (might be harder though)
-Easy to learn
-Easy to crank out content for in the form of copy-pasting objects, importing data arrays, or making editor tools. In this case, I can already tell that saving a list of available building blocks and start/end points will be really easy
-Could work with VRChat's basic networking, if the physics plays nicely
-Can be graphically optimized. The physics engine runs poorly on quest, but it's just a ball.
-Not much to synchronize. Udon data sync is really slow and kinda bad right now. This game would only need to sync one number value for the level you're on, and the positions of the building blocks (already handled for free in the SDK)
To expand on “cranking out content”-- this is because I value world replay-ability and also my own development time. Since the game is played with building blocks, it should be really easy to get lots of playtime out of just a few hours of editing time. Even if the levels aren’t really “replayable,” which is something I like to do, it should still have a decent amount of content to get through and not be just one of those worlds that you just walk around for five minutes. Whether players return to play again isn’t really an issue here.
I also don’t need to actually start writing down or drawing anything other than basic shapes. Content creation will come later, I’m going to actively avoid drawing what each block or level layout looks like until a prototype is complete.
After I get the original idea for a game, I usually draw a little diagram in Paint (on a dark background of course, for less eye strain). This helps me catch anything that I might have missed big-picture wise and sometimes I even sketch geometry.
After drawing this, I realize that since this game has to do with pickups, I’m probably going to run into problems forcing players to drop items and then teleporting them to a specified place, namely returning the blocks to the block starting area when the player resets all the blocks or goes to the next level. But I’m thinking that even if I don’t reset the blocks, it’s not the end of the world. It won’t be game breaking if the blocks don’t reset to the bin at the end of each level, or if the player is holding an invisible/disabled block pickup.
I also sketched the “game logic canvas,” which a lot of my games tend to end up having in one way or another. I don’t like interacting with big, flat screens with a laser pointer in VR games, but they are really handy and it’s actually kind of fun to make them look pretty. It looks like a game this simple will only need two or maybe three buttons to control the flow of the game, but after thinking each one over for a moment, I realized that these buttons are not actually necessary.
A button to reset the blocks if you want to start over from scratch is honestly entirely optional-- just a time-saver for organization’s sake. The action would still be implemented (reset objects should happen automatically when a new level starts), so it’s not a big deal whether I skip the button or not.
The button to go on to the next level when you’re done with the current level is just a holdover from my preconceived assumptions about how mobile games like Angry Birds, etc. work. It doesn’t make much sense to have this a permanently-shown button when the action of “continue” is contextual based on whether the level is completed; It would be grayed out most of the time. This button could just be replaced with a timer that goes onto the next level automatically-- with just enough time to celebrate and reflect on your creation.
The idea of a mobile-game-like level selection screen actually kind of nice. It could let you go back and replay levels you already beat, and wouldn’t be much more extra work to set up. But will people ever use it? In VRChat, you can’t save your progress. I’m pretty sure most people would never use such a menu. Regardless, a button to display the level select screen is unnecessary, since “screen real estate” is not an issue in a VRChat world, I could just save people a click by just putting the level select menu on a wall.
I would keep the “current level” text, though. It would be nice to see your progress in big, bold letters as you play, either as text like “Level 4” or just a giant number “4” on the wall.
After analyzing the idea, I still like it. The next step is to create a new Unity project and do what’s called “Whiteboxing.” I make a rough prototype of the environment using unity primitives. Usually people just leave these as the default white material, hence the term “whiteboxing,” but I like to apply a shader I made a long time ago that applies a texture of 1 meter by 1 meter grey grid cells (so I call it “greyboxing” instead). It’s easier to measure things that way, like doorways and ceilings. It also gives your eyes more depth information than just blank white boxes, which is good because setting up a proper 3D scale is one of the things I try to figure out as soon as possible when making a new environment.
It’s not all about 3D shapes, though. I still need to prototype the game design before moving forward. The two things I’m immediately concerned about after making the Unity project are: Is the game technologically feasible? And… Is the game actually fun?
Is the idea technologically feasible? There are lots of things that can ruin a world idea, but the big important question is whether it’s even possible to bring the idea to life using the VRChat SDK. Usually I can estimate whether I can actually make the game using the VRChat SDK tools just from past experience, but sometimes I need to test out my assumptions. For this game, I want to make sure that the marble will actually roll, reset, and synchronize correctly, because I haven’t made a world based on physics objects before. If the game was more complicated, or relied on weird outside tools, I might redesign the game at this point or maybe scrap the idea completely. Better to do so early on to save time!
But perhaps more importantly, is the game actually fun? I know that’s a subjective question, but it really stinks to work on something and just feel “meh” when it’s finished. Even if you’re 100% copying an existing game idea, the only way to know for sure if a game concept is fun is to just make the crappiest “game” possible from the very beginning. I like to call it the “minimum viable” version of the game. Instead of planning out a huge game, then spending forever developing it, and only having a random chance of having a fun game at the end… it’s easier just to make a really crappy mini-game and ADD features once the mini-game is complete. It’s also more fun to develop this way because you can involve your friends and community along the way. Sometimes you end up with something different than you expected, and that’s a good thing!
The alternative would be hiding away for a couple weeks making something super secretively, maybe releasing some teasers along the way, and doing a big reveal when it’s done. Trust me, this method rarely works out well… I’ve tried it more than once before. The hard part for me, personally, is getting over the awkward feeling of showing your friends something that’s incomplete. But that’s definitely just an emotional issue of mine-- the testers totally don’t care about my perfectionism and have fun even with the “crappiest” versions of the games. I constantly have to tell myself not to overestimate how hard it is to make a viable game, and remember to start testing the “fun” factor early.
There’s also nothing wrong with throwing out a game idea that sucks or isn’t technologically feasible. But it’s way easier to throw out a bad idea early then after you’re 75% done with it and hitting a stressful roadblock. Off the top of my head, I’ve thrown own ideas during the whiteboxing stage because of:
-Variables not syncing fast enough
-Network messages too complex
-World requires a really huge and detailed map,
-Too many unique art/text assets would be needed
-Way more basic that I thought it would be
-Requires really fast reaction time, but ping ruins the experience
-Multiplayer game that’s way less fun with small groups of players (with exceptions)
-Relies on unoptimized realtime lighting/GI that wouldn’t work well on oculus quest
-More audio sources than the sound engine can handle
-Rules too complicated
-Late joiners won’t be able to participate at all
...and many more potential reasons.
Some of these aren’t total idea-killers, but more than one issue is sometimes not worth the hassle.
Setting up a new Unity project for VRChat is pretty fun. There are bunch of “boilerplate” things that I have to take care of, and it can take a little while to set it up. But then everything is super organized.
-Import the latest VRC SDK3 and Udon
-Import the latest Udon Sharp (makes writing code for VRC faster)
-Import my debugging textures and shaders
-Make a TODO.txt file
I also like to keep my Unity project organized as I go, starting from the very beginning. There’s no need to set everything up right away, but as more and more assets get added to the Assets folder, I sort everything neatly into folders based on either file type or what it’s used for. VRChat worlds are typically small enough projects that I don’t need to categorize by scene-- with the exception of Murder 4, since I’m keeping all the various map scenes in one mega Unity project.
This is also a great time to remove all the example assets that come with the VRC SDK and Udon that I don’t need. Since I don’t really refer to them anymore, they just clutter up the asset search results windows when I search for things I actually am using.
I also have an editor window layout that I think works best for working on worlds. Specifically, the animator window is docked at the bottom with the console and the lighting, navigation, occlusion, and build tabs are docked with the inspector. I always keep the project and hierarchy side by side on the left, with the project switched to a neat and compact one-column layout.
The first prototype for Marbles was just to check my assumptions about scale. A 10 by 10 meter platform seemed like enough space for a handful of players to interact with a 3d puzzle. I could estimate this without VR from past experience with room dimensions and by placing a “jar for scale” (a mannequin that’s the same size as my avatar) in the scene. I created basic versions of the game-related objects to test their scale, too. All I needed at this point was a marble (about the size of a baseball), a marble dispenser, a goal for the marble, and building blocks. I also made the building blocks into basic pickups and added a button on the dispenser that resets the marble beneath it so I could test the marble physics. That’s all I needed for a scale test, so I hopped in VR and realized a few things.
First, the play area was definitely big enough, but spawning right in the middle of the puzzle space was definitely a bad idea. I would need some kind of lobby area, like most of my worlds have, that lets new players get their bearings in the world first. I could also tell that maybe the play area was actually a meter or two larger than it needed to be, even with other players nearby (another thing the jar for scale helps with estimating). A more “cozy” size might suit the game better. Keeping these things in mind, I scaled the play area down to 8x8 meters and added an even smaller spawn area alongside it.
The marble dispenser and goal were a decent size, about 1 meter in all dimensions. The pickups could have been a bit larger, and after playing with the various floating ramps and attempting to play the prototype once or twice, I thought it might be more fun if there were fewer, but larger pieces to work with, as opposed to placing the same tiny ramp pieces over and over again 8 times.
I also tested in desktop mode, and it was a little difficult to align the pieces because of how desktop play works in VRChat. You can’t rotate the blocks when you’re holding them, but you can drop them and pick them up at different angles, rotating your view until they are aligned how you want them. Crouching and going prone helps you place the blocks at different heights, too. This game clearly might not work well for desktop users, but it’s not impossible. I would have to come back to this issue soon, but I didn’t consider it a deal-breaker.
Next I went back to whiteboxing in Unity to give the world a little bit more shape, and this is where I got a little carried away. Instead of just adding some walls and windows, I ended up building an entire scene with prototyping blocks.
At first, I just wanted to add some walls to the world, because I knew it wouldn’t just be a floating platform in the sky. Solid walls looked boring and claustrophobic, so I thought about making several walls have really large windows looking out into a pretty skybox. When starting on the window frames, for some reason I tried just lowering all the walls down to waist level. The resulting waist-high walls looked pretty good! I started thinking about whether I needed solid walls at all on a functional level. As far as the game was concerned, the walls only server to visually represent the bounds of the level, to keep the player from exiting the area, to keep the marbles inside, and maybe be a surface for building/rolling the marble. I figured that I could decide to just allow the marble to fall off the world, which would simply reset the marble. Okay, not bad. Keeping the player inside? I could do that with just a little waist-high barrier, and not have to bother with glass/fence/forcefields or whatever on the actual wall surface. I had a lot of options for the actual architecture and none of it really mattered for the game design. But my last concern, a minor one, about allowing the players to use the environment architecture as part of their marble contraption? That sounded a lot like the idea of having different obstacles in each level-- an idea I had when drawing the design in paint, but didn’t actually put together for the whitebox prototype.
So I workshopped the idea of expanding the play area into several play areas. Maybe each level would be a different shaped room, some with windows, some with walls, some with nothing. Some rooms could be L-shaped, some could have a tiny hole in an interior wall that you had to get the marble through. Whatever the shapes would be, the idea of building these obstacles into the environment sounded really cool compared to having a bunch of floating force field type obstacles in each level. I added a second play area off to the side of the main play area, and figured that different levels could just spawn the dispenser and goal in different locations, so I could keep the play areas attached to each other-- forming a sort of playground of shapes and elevations and not separate rooms with doors.
On a whim I lowered the second play area/room down a few meters and added a ramp, and I think that’s when the idea of a “sandbox” really clicked. I could just make a medium-sized blank sandbox of baked-in obstacles, and each level would just place the game entities in various places to make use of ramps, walls, tunnels, and other fun stuff. In my head I called this idea the “plaza” design, and I basically just threw in all the ideas for marble maze levels I had in some corner of the map-- imagining some possible positions for the marble dispenser and goals, and possible challenges for the player to build around. For example in each corner I put a large column, a tunnel with a narrow ceiling, some ramps in different directions, and a long horizontal pole thing that I wasn’t sure what to do with. At some point I realized that the play area was getting a bit too large, so I had to condense it down a bit.
Writing this, I realize that the resulting “plaza” idea reminded me of Forge mode in Halo, in which a map with static geometry is re-used for multiple types of game modes. Players in forge can also move objects around and play with physics and stuff, but the difference here is that I would be the one authoring the levels, and the players would be the ones playing them by manipulating physics objects, not the other way round.
I was actually pretty happy with most of the architecture that I blocked out with checkered boxes. Going forward the plan is to keep the general shape of the plaza, but try not to build any levels that are dependent on specific dimensions just in case.
The next steps involve actually writing some code for the marble dispenser and overall game flow. There are a few features worth testing before going any further with this game:
-That the marble physics are synchronized for all players
-That dropping/locking the building blocks works when the marble is dispensed, movable when it’s in the dispenser
-That late joiners see the correct puzzle
All the important code for the game is in this mega-behavior called MarbeGameLogic. It’s not always smart to put all your game logic in one behavior like this.. especially for debugging. One error at runtime will shut down the entire game this way, so if I’m testing for bugs I can pretty much only test one bug at a time. But that’s okay, there isn’t anything really complicated here.
Also side note before going forward-- I write in C# and use Merlin’s UdonSharp compiler to convert my code into Udon assembly. While the Udon noodle-graph that comes with the SDK package can technically do all the same things, using UdonSharp is way faster if you already know how to code with C# (if you’re a Unity game developer you are probably already very familiar with the Unity resources and C# syntax).
Just like with greyboxing the geometry for the level, a smart thing to do when writing code is to outline the rough overall game, with minimal features, before refining it later. Except instead of stretching boxes that represent stairs, floors, walls, etc… you’re writing almost empty functions that represent behavior. For example, I started with “Dispense Marble” and “Recall Marble” buttons that turned the marble gravity on and off-- that’s it. After testing those, I can make them both be on the same button, and maybe add the part that resets the marble’s position. Then I can turn them into remote procedures that work over the network. Etc, etc.
It’s a good thing I tested the marble physics immediately because I made a discovery that saved me a lot of time later: VRChat’s built-in rigidbody syncing is not that great. Especially when the body moves in unexpected ways, like the marble dispenser freezing and unfreezing the physics on the marble. At this point I figure it’s okay to remove the actual position syncing on the marble, and trust each player’s computer to simulate a reasonably similar path for the marble. Since the marble starts at a fixed position every time you dispense it, and the blocks are frozen in place when the game starts, and vrchat is actually very accurate (at this game’s scale, at least) about where a pickup object is dropped, it’s reasonable to rely on this. This is my first time making a physics based multiplayer game and I will definitely keep this in mind going forward if I make anything similar in the future.
Making sure that late joiners see the correct level is simple, and with Udon there’s even a way to make specific code run when the synchronized “level” variable is changed. To simplify synchronization even more, each level only needs to synchronize the level number (ex. 1, 2, 3…). I don’t have to send each player information about where the start and end are, or what pieces are used in each level. I can just save all this information in a list, and each player’s client can just look up this information when they receive the level number.
Each level has a different start point, end point, obstacles, and a different palette of available blocks. Therefore I needed to write a system that would let me author levels in the 3D scene view (I want to be able to drag and drop the start and end points), save the start/end/obstacle/block information in a list somehow, and load this information from the list at runtime using just a single number. No problem!
In the hierarchy I made an empty parent object to hold all the level data called “Stages” (oh yeah, I want to call levels “stages” going forward because I think it sounds better). Each stage is represented with a child of Stages, all in the correct order of course. This way, I can label the stages however I want, I can re-order them by clicking and dragging, and the system can look up a specific level by looking at “Stages” and using the simple GetChild(number) function.
Each stage object has at least two children, a Dispenser and a Goal. I can move these objects around in the scene to represent the position and rotation of where the dispenser and goal should be on each stage. By default, they are blue shapes that don’t actually do anything, just so I can see how big they are when dragging them around, but during the game they will be turned inactive and therefore invisible… the system just needs their position, and you can get that even if something is invisible after all. Also in each stage I can place obstacles… these won’t be turned invisible during the game, of course. I can move and rotate as many obstacles per stage as I want. When I’m all done editing the start, end, and obstacles, I can just set this entire stage object inactive so that I don’t have a whole bunch of shapes on my screen at one time from all the different stages.
Activating and deactivating the obstacle gameobjects per stage is fine, because you can’t pick them up, but what about the building blocks? I want to be able to re-use the same pickups spread across several stage. Plus, there could be potentially lots and lots of blocks… I don’t want to have to copy and paste them for each stage. What if I wanted to change the size, shape or behavior of a block type? I would have to change a lot of blocks by hand if I already authored some stages. Sure, I could use prefabs for this, but still... what if I wanted to really easily change the different blocks available for a level? I would have to do a lot of dragging and dropping.
Instead I came up with a way to save the “palette” of available blocks per stage by encoding them into the name of the stage gameobject. First, I have to give each block type a unique name ID (for example, halfpipe blocks could be “HP “and funnel blocks could be “F”). Then I can append the quantity of each block, limited from 0-9 since I won’t have more than 9 blocks of a specific type anyway and the quantity is always one digit long (Ex. Two halfpipes becomes “2HP”). Finally I just separate this list of values using the separator character “-”. That way I can just use the string.split(“-”) function later to get a list of values super easily.
Work continues on the art side in parallel to the code side. The dispenser, goal, and building blocks needed somewhat final geometry at this point so that I could start authoring levels. During the greyboxing phase I already tested out the overalls shape (and more importantly, the size), including their proportions relative to the marble, so I just needed an actual model that fit those dimensions. Don’t ask where the idea for wood and metal came from, because I have no idea, it just kind of occurred to me after sketching the trims and glowing symbols for the dispenser. I actually started modeling a more colorful dispenser, but I didn’t like it. The objects, and probably the entire world, might have ended up as a curvy, cartoony, and colorful game instead if I just decided to go in a different art direction.
Making variations of the halfpipe was actually really simple once I already had a texture map for the dispenser and goal. They all share the same texture for a consistent look. Some of the variations of the longer halfpipe shape were just simple twisting, rotating, and scaling operations on the same base shape.
At this point I’m very happy because the game is functional/playable and all that’s left is to create a bunch of content. More block shapes which are just simple shapes, more levels which are just objects dragged around and editing an encoded string, and making the environment look pretty.
Switching gears back to the environment art, I didn’t do the usual thing I do where I atlas all the textures into one. Because there are such huge surfaces, I went with tiling three or four moderate-resolution textures. One for the wall, one for the floor, one for the wood, and one for the miscellaneous concrete trims (which only tile horizontally). There are also some smaller textures for the gravel (barely visible, it’s in the tree planter boxes), bark, and leaves.
The landscape has no collision, and I honestly don’t love how it turned out, but whatever. The mountains are an actual 3d object (and not just a unity terrain) made from a heightmap I generated. I think the fog effects are pretty nice since there is actual depth to the mountains. I didn’t bake them into the skybox texture since you can see the ground surrounding the plaza very close up. The skybox is just a free unity asset, but I tinted it a bit more pink. The trees were going to be dark colored with pink leaves, but I figured why not make them the complete opposite? So they ended up write with blue leaves. Overall it’s like an alien planet maybe? Or just a bit surreal, after all it’s a strange puzzle game with floating blocks. I was going to add waterfalls, but didn’t really feel like setting up all those effects, so I went with light strips instead.
This scene is actually NOT lit with Bakery, a Unity asset which I have been using more and more lately. For some reason, it was actually taking longer to bake the light with Bakery than Unity’s built-in progressive GPU lightmapper. Also, I couldn’t get the main directional light to look as good in Bakery. It probably would have worked if I spent more time with it. In general, I do recommend Bakery as it’s very nice.
Audio and particle effects are the final flavor that I add to the world. Making the music fade in and out between a bass-heavy and bass-cut version of the same song was really fun to do and I hope to repeat that type of effect. I didn’t use any fancy audio mixer stuff in Unity for this effect, I just edited the same track in audacity (took a track I liked and looped it), applied filters, and exported two different versions, one with extra bass and one with cut bass. Both play at the same time in the unity scene, but the game logic controller blends the volume up and down so you only hear one at a time. In the final game logic behavior, you can see how I simply have to drag and drop the sound effects, music, particles, buttons that should play when certain events happen in game.
The “How to Play” board is very important and I spent a decent amount of time making it as simple as possible. I’ve noticed there are two ways people learn how to play a game in VRChat-- either you join a game in progress and learn very quickly from watching others, or from trial and error (which isn’t easy), or you’re joining alone/with some friends without a game in progress and you spend some time reading the rules. This is a problem for unfamiliar game concepts (like this game) and especially bad for board games (similar to spirit speak). One day, I want to experiment with an animated or interactive tutorial of some kind in a world I make. For now, I took some screenshots of the dispenser and my avatar and ran them through some filters in my image editing software, GIMP, to make the outline effect you see on the tutorial board in the final product.
I’m also experimenting with localizing the instructions to different languages.. in case the graphicsl representation was not enough, and the user can’t read in English. The translations are pretty bad “google translate” translations, except for Japanese which I got help with from Tony_Lewis, a patron here. So thanks for that! I hope this ends up being useful. So far I haven’t heard much feedback about it from people who speak other languages, so I don’t even know if this feature is being used, but I think it was worth a try to see how people respond for future worlds.
I couldn’t decide on a good name. I would have gone with “Marbular” but “Marble Puzzles” is more obviously descriptive when viewing the worlds inside VRChat. Final final touches are adding my Patreon, Discord, and Twitter links… and then some final testing on both PC and Quest.
Now that the world is published, I ask myself, did I accomplish the goals I set out in the beginning? I think so! Building with the blocks is a creative as I thought it would be. The obstacles make it challenging-- especially the shape of the plaza, but also because I can give a different palette of blocks each time. Was it easy to pump out a bunch of content? Definitely, the palette-encoding system and drag-and-drop level design was very efficient and I used those systems to make lots of adjustments after playtesting sessions with other people. Was the idea obviously fun after the prototyping stages? Yes, and I’m glad I finished the entire thing afterward.