ArmGun

Posted on June 16, 2018

Table of Contents

Intro

ArmGun was a solo project I made in ~48 hours for 2018’s McGameJam. You can try it at itch.io.

I decided to focus on the tasks that I enjoy the most in game jams: gameplay programming, polish, and doodling some pixel art. I also aimed for a tight scope so that the result would be a complete and consistent experience from start to finish.

If we pretend that I had a budget of 10$ on the production of ArmGun then I spent:

  • 4$ on gameplay systems
  • 3$ on polish
  • 2$ on art
  • 1$ on UI/UX
  • 0.01$ on game design
  • 0$ on audio

I blame budget cuts.

Goal

One of my favorite games on the PlayStation 2 was Ratchet: Deadlocked. I enjoyed the way that my weapon arsenal expanded and diversified as the game progressed. I could also purchase modifiers to attach to the weapons. Mods ranged from basic stats upgrades (rate of fire, clip size, etc) to absolutely mind-blowing ammo effects. Here’s a few that I remember:

  • Napalm - explosive ammo leaves behind a puddle of napalm which damages enemies who walk over it
  • Freeze - the shot enemy moves slower with every hit (he can eventually form into an ice block)
  • Lightning - electric arcs traverse enemies who are near shot enemies
  • Morph (personal favorite) - there’s a chance that the target will turn into a harmless farm animal

I found it fascinating how every single enemy in the game reacted consistently to a huge variety of effects. The result is a fun sandbox game loop within Ratchet: Deadlocked’s outward platformer, action, and third-person shooter layers.

With ArmGun I wanted to explore this sandbox game loop and to implement some of the systems behind it.

Overview

Controls:

The upgrade shop menu can be opened anytime, it pauses the game too:

Game screenshot:

The player earns points by eliminating zombies and can spend them to modify his weapon. There’s no ending, the game progressively becomes harder and the total points earned in a run (upper right corner) acts as the highscore.

Effects implementation

If this had been a real game then I would have focused on a modular and extensible system. But for ArmGun I determined early on which effects I wanted to include and implemented them in a straight-forward and highly-coupled manner because it was quicker.

Bouncing bullets

When bullets are spawned they’re assigned an amount of maximum bounces. In their collision callback their internal bounce counter is incremented and checked against the assigned maximum to see if they should be removed. The game engine handles the bouncing physics, only the collision callback still needs to update the bullet’s graphic’s rotation for its new direction.

Morph ammo

This was my favorite effect to implement.

In their bullet collision callbacks enemies randomly determine (based on a couple factors) if they should morph.

When an enemy morphs, he changes graphics to a randomly selected farm animal and a new state is pushed to his finite state machine which makes him do essentially nothing. The morph is reverted after a few seconds.

Freeze ammo

In their bullet collision callbacks enemies accumulate the bullets’ freeze factors. This total freeze factor (0-1 range) is used to tint an enemy’s sprite graphic blue (handled by the game engine) and to reduce their velocity. The total freeze factor slowly decreases.

Super semi and Machine gun

The weapon object uses a timer for firing bullets and has a base speed and damage values that it assigns to bullets. These effects simply modify the three values.

Shotgun ammo

This effect simply spawns two more bullets with -15 and 15 degrees target direction offset.

Enemy spawns

There’s three types of enemies:

  • Slow (green) zombie - just cannon fodder
  • Fast (blue) zombie - very fast movement speed and more health
  • Hazmat suit (orange) zombie - super fast movement speed and even more health, watch out!

There’s a minimal system in place which regulates the game difficulty. Based on the total score acquired by the player so far it determines the amount and type of enemies that should be “on the board”, and new enemies are “thrown” in through the windows. This amount follows a cyclical but ever-increasing pattern.

The X axis is the total amount of points acquired. Players earn from 5 to 20 points per enemy killed, it depends on the type. The Y axis is the amount of enemies that should be active.

It was the last thing I added to the game, and I was surprised that it was pretty decent despite being very crude.

Superficial intelligence

The enemy AI is a tiny finite state machine:

Idle state

After waiting a few seconds, enemies will begin slowly following a path towards the player (pathfinding is provided by the engine).

Pursue state

The horde effect is created by the enemies’ ability to alert others within a certain radius (pushing them into the pursue state) when they themselves enter this state.

In the pursue state enemies accelerate towards the player. It’s a lot of fun because it makes it possible for the player to dodge them by quickly changing run direction. The exception is the hazmat suit zombie which runs directly towards the player.

There’s no pathfinding in this state so zombies can agglomerate behind tables and desks which looks really cool.

On the other hand they can get stuck in rooms which is less cool. The map is designed in a mostly convex shape to minimize the frequency of them getting stuck. The map’s layout also helps them eventually gravitate towards a corridor leading to the main area when they do get stuck.

Miscellaneous polish stuff

Score counter

I added a scale tween to make it pop! when the player earns points.

Tweens

Everything is a tween. Everything.

Managing so many tweens and selecting their curves made me wish for a real-time curve editor. This could be a future project.

Blood particle emitter

There’s a few particle emitters in the game but this one is my favorite.

Chairs

I wish I’d had the time to add some meaningful environment interactions. Here’s some chairs instead.

Drop shadows

With vs without drop shadows:

They’re baked into the assets:

This creates a problem when the enemy sprites are tilted (as they rotate while they die):

Luckily it happens so fast that it’s difficult to notice.

An improvement would be to turn the drop shadows into a dynamic system, where they’re positioned and scaled at runtime.