Prototype Your Video Game First

A lesson learned from making a not fun game

October 31, 2021

Preface ✋

When I started this website, I wanted to use it to talk about the finished things that I made. But I've changed my mind. There's plenty to learn and share from unfinished projects. Whether it be on the journey to completion, or when you finally decide it's time to stop working on it all together.

There's also something to be said about knowing when to move on from something. And I guess since I'm not going to work on the project anymore, it's technically finished...just not complete.

Video Game Development 🎮

Video game development seems like it was made just for me. There's plenty of different domains that need work, both creatively and technically:

So I was excited to tackle all of those aspects when I first started learning about game dev in 2020.

I started learning how to make 2D games in Godot and then eventually 3D games in Unity. I didn't produce anything of substance from my time with either. It was more of a period of exploration in how developing games works and if it's something that I would enjoy. During this time, I stumbled upon a little piece of software called PICO-8 and was immediately smitten.

Learning PICO-8 👾

PICO-8 is a fantasy console. If you've never heard the term fantasy console before, it's an emulator for a computer/gaming system that doesn't physically exist. It's entirely self contained: you work in the console itself for programming, making visuals and audio, play-testing, and even playing games made by others!

When I started off learning PICO-8 I didn't have a specific game idea in mind. I just started off by drawing things in the pixel editor. Eventually I made this:

First character concept in pico 8.

And then a light bulb went off.

The idea that came to mind was a puzzle-platformer where you're magnetic. [1] You would have to use magnets of the same polarity to launch yourself through a level. Touching magnets of a different polarity would stop you in your tracks and you would have to jump to break free. In addition, there would be certain places where you could change your polarity.

This was the first time I had ever used PICO-8. As such, I had to learn more than just a new programming language (Lua). I had to learn how to program the PICO-8. I got as far as getting my little magnet man animated, moving around, and jumping on some platforms.

Various platforms and magnets in pico 8

At this point I moved on from the PICO-8 because I wanted to move faster. I liked this game idea so much that I didn't want to spend time learning a new platform; I just wanted to make the game.

Moving to Godot 🤖

Like I said before, I had programmed some game demos/toys before in both Unity and Godot. Given my experience level in each, and that this would be a two-dimensional platformer game, I went with Godot.

(I also just enjoy working in Godot)

The first thing that I did was redraw my PICO-8 assets for Godot. This meant redoing the previously 8 pixel by 8 pixel magnet man to 16x16.

Larger version of character for use in Godot

In addition to the main character, I drew some magnets and blocks where your polarity would get switched:

Overview of various platforms and magnets redrawn for use in Godot

Now I was ready to start setting up the character movement. When playing video games you may take for granted how your character moves; but it's really more of an art than a science. It's not just how fast the player moves, it's how quickly they get up to their top speed, how quickly they go from top speed to stopping entirely. You have to ask yourself: how high can they jump? Do they have a single jump height, or do they jump higher the longer the jump button is pressed?

These were the kind of nuanced tweaks that I was working on. Eventually, I felt like I was in a decent enough place, and I started programming the interactions with magnets.

Making Magnets 🧲

The idea was simple, if you touch a magnet with the same polarity then you'll get launched away. If you touch a magnet with a different polarity then you'll get stuck to it; unable to move until you jump.

Not only was the idea simple, but so was the code. The basic movement for the player is this:


func _physics_process(delta: float) -> void:
  var x_input = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
  
  if x_input != 0:
    motion.x += x_input * ACCEL
    motion.x = clamp(motion.x, -MAX_SPEED, MAX_SPEED)
  motion.y += GRAV
  
  if is_on_floor():
    if isMagnitized:
      motion.x = 0
    elif x_input == 0:
      motion.x = lerp(motion.x, 0, FRICTION)
    
    if isRepelled:
      motion.y = -JUMP_FORCE * 2
    elif Input.is_action_just_pressed("ui_up"):
      motion.y = -JUMP_FORCE
  else:
    if Input.is_action_just_released("ui_up") and motion.y < -JUMP_FORCE/2:
      motion.y = -JUMP_FORCE/2
    if x_input == 0:
      motion.x = 0
  
  motion = move_and_slide(motion, Vector2.UP)
  

The two user properties isMagnitized and isRepelled are set using callbacks (called Signals in Godot) when a collision occurs. If the collision is with a magnet, then we set those values:


func _on_MagPlatformDetector_body_entered(body: Node) -> void:
  if body.name == "MagPlatform":
    _set_player_magnetics(body)
func _set_player_magnetics(magPlatformObj):
  var magPairObj = magPlatformObj.get_parent()
  isRepelled = magPairObj.charge == charge
  isMagnitized = !(magPairObj.charge == charge)
  

And just like that, the magnets work!

GIF of the magnet character being repelled from magnet

Magnets by themselves can be kind of boring, so I thought it would be neat to have them move. But not on their own. They would move towards other magnets that the player can charge by touching.

Honestly, the code for this functionality to fairly boring. It's just math dealing with x and y coordinates. So I'll stick to just the explanation.

The first thing I did was combine the uncharged magnet with the magnet platform into a single object. The top-level parent of this object pair is where the code for the movement and interaction lives. In this script I got the positions of the magnet and the platform then determined if the movement of the platform would be in the x-direction or y-direction.

Then all I had to do was check if the uncharged magnet base was now magnetized and start moving the platform towards it. If the base wasn't magnetized then I checked to see if the platform was moving. If it was, then I had it start moving back toward its original position. The position values of the magnet platform also had to be clamped each time it was moved so that it didn't run into the base that was pulling it.

Lastly, there was determining when the system was magnetized. I again used a signal on collision and checked what the charge of the colliding player was, and if it was the opposite charge of the platform. Since the player was the only thing that would be colliding with the base, I knew that the system was no longer magnetized when a body left the collider. The code is incredibly simple:


func _on_Magnet_body_entered(body: Node) -> void:
  if charge != body.charge:
    is_magnetized = true
func _on_Magnet_body_exited(body: Node) -> void:
  is_magnetized = false
  
GIF of magnet character charging a magnet to move a platform.

The final functionality that I needed to write was having the player be able to switch polarity. This was dead simple as well. All I had to do was setup a collider on the converter block, detect it on the player script, and switch a property.


func _on_ConverterDetector_body_entered(body: Node) -> void:
  if body.name == "Converter":
    _convert_polarity()
func _convert_polarity():
  if charge == "N":
    charge = "S"
  else:
    charge = "N"
  

Since I had my sprites named appropriately, all I had to do was setup the calls like this:


$AnimatedSprite.play("Idle" + charge)
  

And the player could swap polarity!

GOF of magnet character changing polarity.

At this point I had most of the artwork done and the basic gameplay systems written up. The next big step was making levels for the player to enjoy. That's where things took a pause.

Taking a Break ⌚

I was thinking about what the write up for this game would look like on the website and dreaded converting the content into HTML. This was when I took some time to write up my previous project: a static site generator.

By the time I had finished that and came back to this, I had fresh eyes. Honestly, I forgot how the game even felt to play. Excited to jump back in, I started off by playing the game as I had left it. Unfortunately, there was one problem. I realized what I made wasn't fun.

I just couldn't see myself playing a game based around what I currently had because I wouldn't enjoy it. Honestly, it was disappointing, but there's a hard lesson to be learned here: prototype the core functionality first.

I was so caught up on making the final pixel art and tweaking the accelerations of the character that I missed the forest through the trees: I needed the base gameplay to be fun.

There's a big difference between software development and video game development. With software, you start off by asking what's useful. In video games, you ask what's fun.

Figuring out what's fun isn't as easy as figuring out what's useful. To see if a game is going to be enjoyable requires actually playing it. You don't want to spend a lot of time making a game and then late in the process see if people like the core gameplay loop. To get around this you should make a prototype. A bare-bones, throw-away prototype to validate your idea.

I didn't do that. [2]

I was so attached to my idea that I didn't think to consider if I would actually enjoy playing it.

Conclusion 🍻

For now, the game is in an indefinite hiatus. I don't think the idea is bad, but the demo would require significant rework to find how to make it fun. Maybe I'll come back to it; maybe I won't. If I do then I'll start from scratch. Either way, I learned a valuable lesson in not just video game development, but making software overall.

At least I had a lot of fun making this.






Footnotes

[1] Yes, yes, this sounds eerily similar to the magnetic puzzle platformer that Mark Brown came up with. It's just a case of two people coming up the same idea around the same time . It was quite surreal to watch for myself. Fortunately, Mark managed to move beyond the initial concept and onto something a bit different. And the idea of a magnet-based 2D platformer isn't all that original, see the 2021 release Super Magbot.

[2] Now, I didn't realize this when the game was in a finalized state. What I made was definitely closer to a proof-of-concept than a final game. That being said, I think to get to where the game is enjoyable, I would have to redo everything, so I'm just going to say it was a wash.