GrapeFruit Game Jam 2020: Day 2

The Last Jam of 2020 Continues…

This is the second post in a series about my entry for the GrapeFruit GameJam 2020. You can check out the first part here.

Day two of the jam begins with me taking stock of my current situation. So far I have a lot of great infrastructure in place, like a game manager to control transitions between my scenes, and some basic ECS systems that generate my player entity and read user input. But my game is totally lacking gameplay elements. There’s nothing to my game yet. All you can do is rotate a blocky, voxel monk. It’s nowhere near fun yet.

So far just a rotating monk. Not fun yet.

Continuing To Develop The Player Controls

At this point my plan is still to do some sort of zero-friction, sliding based game. The PlayerInputSystem I built during day one of the jam reads user input and rotates the player model to face the direction input by the user. The plan is to use Unity’s physics to create a fun, unique, zero-friction sliding based gameplay experience by tweaking some material interaction properties. For movement, I add a MovementSystem that will use the player input to apply directional forces to the player object. Since I’m not super confident in my 3D math skills, I start off by just setting up my system to add a small direction vector to the player position to make sure that I’m applying the force in the proper direction. Once I know that the force is being applied how I expect, I’ll tweak it to apply the desired direction vector as a force, rather than a direct modification of the player position.

After a little bit of coding I had my PlayerInputSystem refactored, my MovementSystem added, and I could move my monk around the level. I added a CameraFollowSystem to control the camera and have it follow the player position. I put a super basic pixelated grass style texture on the ground to help the player and camera motion stand out a bit. My monk could now move around the world! He wasn’t sliding yet, but it was still a step in the right direction. And all running on ECS!

It’s not sliding, but the player can move around the world, for the first time I feel like I have a game.

Happy Accidents Change Directions

My current MovementSystem is moving the player by directly modifying the Player entity’s translation. But I had attached a collider and a rigidbody to the game object that I was converting to an entity, and I was curious how those components were being converted and used by Unity’s ECS systems. For a little test I decided to just throw another game object with a collider on it into the scene and see what happened when I ran my monk character into it. And in hindsight, I should have expected what I saw happen.

Testing how my movement system interacts with the physics system.

Since my movement system moves the player by directly modifying the player’s translation, when I move my player into the box, my player’s collider is teleported over top of the box’s collider. Unity’s physics system then resolves the overlap between the colliders by forcibly separating them. Since my player model is rectangular and slightly taller than the box, the monk’s collision resolution is a little wobbly. It makes it look like he’s a little off balance after smacking his face off of the box. Repeated impacts will sometimes cause the monk to cutely flop over onto his back. It was so simple, but I loved it so much! I decided to abandon my plans for the sliding mechanics. Instead I planned to keep the simple input system I had as is, and use this mechanic of box pushing via collision resolution to create a super simple sokoban. The game mechanics were so simple I wouldn’t be able to do any sorts of puzzles, but I thought the cute falling over of the monk was entertaining enough that it could sustain a player’s interest for the duration of a jam game.

I would return to my early idea of a monk seeking enlightenment. Before he can achieve oneness and have his mind transcend into the spiritual world, the monk has to finish the chores that are binding his thoughts to the physical world. Once the number of lost boxes is returned to absolute zero, then the monk’s mind is free to achieve oneness. My new idea meant that my game wouldn’t have any reference to the absolute zero theme as the concept from chemistry. But I had references to completeness which covered the ‘absolute’ part, and the goal was to get to ‘zero’ boxes remaining. To help cover my bases I decided to call my monk Zero. I really liked the idea of making a game where you help Zero achieve oneness!

Turning The Experiment Into A Game

Pushing boxes and falling over. Now we’re having fun!

Now that I had finally decided what my game was going to be, the next step was to add the rest of the basic gameplay elements I needed to complete my game loop. I would litter a couple of lost boxes and obstacles throughout a map, and there would be an area that you could return the boxes to by pushing them.

Making the lost box entities was easy. I added a conversion system that added a LostBoxComponent to the basic 3D cube entity I had used in my collision original test. I also added a cool a retro, pixelated crate texture to the cube to make it fit into the retro visual style the project was organically beginning to adopt. With my lost boxes generated in the world, I started working on the logic that would check for the game victory conditions.

I decided to split game win condition across two systems. The BoxReturnSystem would only be responsible for tracking the LostBox entities, and if they were inside the ‘returned’ area, then the system would remove the LostBox component from the entity, and add a FoundBox component. The GameWinSystem would just query to find the number of entities with FoundBox components, and if the number of found boxes is greater than the number of boxes we’d lost at the beginning, the system would trigger the condition that the the game had been won.

Unity Physics In ECS Proves Challenging

Adding walls introduced much more violent collision resolution with static colliders.

For my first attempt at my BoxReturnSystem, I tried to just simply add a box collider to act as a trigger over an area that I could push my lost boxes into. I assumed I could use something like an OnTriggerEnter() callback to detect collision between my LostBoxes and the return area. But my game is all ECS, so there’s no OnTriggerEnter() callback for me to hook into to trigger my logic. I had to figure out how to check for physics collisions in a purely ECS way.

After struggling with problem for a couple hours, I felt like I wasn’t getting any traction on the issue. I had a system that was fetching the LostBox entity’s collider component, and I was trying to use it to find information about what it was colliding with, but I wasn’t getting anywhere. After doing some more research, it seemed like the proper way to trigger logic on physics collisions was to set up a whole system that queries for all the physics collisions, and then runs the logic it needs on a per collision basis. Whatever it was I needed, it wasn’t what I was currently building, and time was running out. I decided that the best course of action was to get something that worked. I dropped the trigger collider entirely, and instead I coded my BoxReturnSystem to check location of the LostBoxes. If the x and z values of the box were within a certain threshold, the box was considered returned. It was a clunky, inelegant solution that involved hard coded values. But it worked, and at this point in the jam, working trumped elegance.

Completing The Game

I used BeepBox.co to create music for the game.

Once I had a working way to win the game, I was onto the final stretch. After doing a quick Google for “8 bit music generator” I found a great website BeepBox.co, and used their tool to quickly generate some music for the game. The music I made is super simple, but I wanted to keep it basic to stay with the simple art style I was using on the project. I wanted the music for the game to sound like something out of an old arcade game. I found this tool great to work with and I have definitely bookmarked it for use on future projects as well.

By now with all the testing and iterating on the game loop, I had spent a fair bit of time playing with the box pushing mechanic. After the initial novelty had worn off I had to admit that pushing the boxes wasn’t really that fun in and of itself. The collision resolution made it unpredictable such that just pushing the box in a straight line was a challenge. I decided that adding any sort of obstacles would make the game way too difficult, so any level design ideas went out the window. I decided to keep the level small, so you didn’t have to push the boxes very far. I wanted the game to be over before the game mechanics wore too thin.

Lastly I went back to my game menus and spiced them up a bit. I added a starting screen that explained the point of the game to the players, and for the end screen I added Zero with little Zero’s erupting out of him to symbolize his enlightenment. With that the game was complete! As I did a final build, I captured some screenshots for the Itch.io page, and put together a nice little gif of the game to share on Twitter. I uploaded the game, and submitted the game to the jam. Zero Boxes Lost was complete!

The gif of gameplay I used to promote the game on Twitter.

GrapeFruit GameJam Ranking Results

Rankings for the jam happened over three days following the deadline. I played most of the games submitted for the jam, and enjoyed a lot of them. There were some really good games including 1 to 0, and Cold Cosmonaut. And there were some games that weren’t as polished or complete, which was to be expected in a 48 hour game jam. Overall the spread of quality was very similar to what I see at the local game jam events that I attend. I felt pretty good about my entry. I didn’t think my game was the best in the jam, but I definitely felt I ranked strongly against a lot of the field. I optimistically hoped for a finish somewhere in the top third of the submissions.

Screencap of the ranking results for the game.

Three days later, on Christmas day, the results of the ranking voting were released. I came in 16th overall, and I was disappointed. I know I had said at the beginning that I would be happy with anything higher than last place, but after all the work and seeing the game come together like it had, I expected more. I really liked this game and I was really happy with the result, but ranking so lowly extinguished some of my enthusiasm for the game.

After taking a moment to curse my low score and care for my bruised ego, I took another look at my scores and I’ll begrudgingly admit that the ranking I received is more or less fair. I did pretty well in graphics and originality. My music was sparse by choice, and I knew that would be polarizing. Some people would like it, but others would find it reputative and irritating. I wanted to get more sound effects into the game, but my inability to really harness the physics system meant I couldn’t easily trigger sound effects on things like collision events.

My game design score was hurt by the fact that I was building everything in ECS. It made building everything more technically complex, and as a consequence I purposely tried to keep what my game simple. Unfortunately there’s no score for technical complexity where I can make up my lost design points. No one sees the technical complexity under the hood, they just see the simple game their playing. Finally I came in very low in terms of adherence to theme, which I think is a little harsh. I had an alternative interpretation of the theme, but I think it’s a valid one. I think people were a little too narrowly focused on the literal interpretation of the theme as a chemistry concept. But I probably could have been a little more literal with my interpretation as well.

The End of The Last Jam of 2020

Zero has achieved oneness!

Game jams are funny things. When I sign up for them, they seem like a great idea. Make a game in a weekend! What a fun challenge! When I start them, I regret signing up for them almost immediately. Why did I decide to fill up my weekend with work? I hit walls. I get frustrated. I push through. I find solutions. If I’m lucky and the stars align, I end up with a game I can add to my resume. It might not be much of a video game, but it’s a video game. It is so satisfying to have that product at the end, and makes all the frustration and hard work worth the effort.

Overall I am very happy with how this jam went. I wanted to build a game in Unity ECS to learn more about that system, and in that regard this jam was a total success. There’s still areas of ECS that I need to dig deeper on, like the physics. But building Zero Boxes Lost has increased my experience and knowledge a substantial amount. The game is simple, but I’m really happy with how all the individual elements turned out. I like the art, I like the gameplay, I like the music, and I like the theme. I like everything about this little game! And even though it didn’t finish as highly in the final rankings as I would have liked it to, I’m still proud of what I accomplished.

Download and try Zero Boxes Lost here!

Check out the source code for Zero Boxes Lost here!