I am currently developing a twin stick shooter from scratch using Unity. The game began as a vehicle to teach myself to program and has grown as my coding abilities increased. Development thus far has been immensely educational, demonstrating both personal and technical skills. This page showcases technical systems, as well as design philosophy about the project. You can download the latest demo here
An exploration of what it takes to make a game feel great to make, and to play
My philosophy with this project has been twofold. As a designer I strive for tools that are robust and powerful in order to make development more enjoyable, which in turn makes it easier to construct interesting gameplay to enjoy as a player. The link between these ideas has been a strong driving force in this project, governing much of my decision making. Thanks to powerful and flexible tools, iterating on gameplay has become a very quick process, allowing me to pursue interesting gameplay that feels great.
Many of the development rules I’ve created have centered around the idea that any change I want to make should be able to be made quickly, in a single location, without breaking anything else. This has led me to make good use of centralized data storage, highly layered class structure, and well commented code. Though this project is a twin stick shooter, with very little effort these systems should be able to be repurposed for a wide variety of games.
Regarding mechanics, I wanted to give players a robust set of options that can be chained together in interesting ways. This has created several tricks for players to discover as they play, resulting in a growth of understanding of how each character works and how they relate to one another. For example, the Berserker character (currently playable in the demo) can perform a melee attack, and place a bomb on the ground in front of them. Though these are two separate actions, through experimentation players will discover that if they place the bomb first they can melee attack it to send it flying forward. This increases the utility of both actions, and allows for additional options without negating the usefulness of either one separately.
The more the merrier
The main gameplay hook for this game is the interaction between various characters and their abilities. Each character should be viable on thier own, but can also be used in concert with other characters to much greater affect. Below is a brief listing of a few planned characters and their roles.
- Berserker – Rapid damage dealer at medium/short range. Has a gun, melee, and bomb used to deal low amounts of damage quickly
- Sniper – Long range damage dealer ideal for taking out priority targets. Can create a field that super charges any bullets that move through it
- Guardian – Tank/Utility character. Has a shield used to hold off and push back enemies. Shield can reflect bullets, increasing their offensive properties when doing so
Joker – Uses status affecting abilities to make enemies easier to deal with. This includes slowing down enemies, reducing thier defense and stunning them for short periods
- Grapple Knight – Melee character with a grappling hook. Hook is used to move character to a location quickly, pull enemies/object closer, and send them back out
My approach to code structure has been to use inheritance to create several levels of functionality that build on one another. This process begins with thorough planning to determine which features need to be accessible at each level. Once this is complete I go through the code and add comments regarding why it was implemented that way, and how it effects the output. A very good example of this is the class structure regarding enemy classes.
Enemy Class Structure
Given that I wanted to make a wide variety of enemy types, it was important to structure enemy code in a manner that allowed for a wide range of functionality without too much waste at runtime. This led to a multi-layered code structure with several bases of functionality:
- GameActor: A common base class that defines basics like health values, and taking damage
- Enemy_Base: Includes logic for things all enemies need such as status effects, being aware of a combat vs idle game state, and playing sounds
- SimpleEnemy_Base: Includes Enemy_Base functionality, and adds the ability to detect, track, and attack the player
- AdvancedEnemy_Base: Includes SimpleEnemy_Base functionality, and adds navigation, advanced animation components, and AI behaviors
Individual enemy classes inherit from one of these bases according to how much functionality they will need to operate. For example, a stationary turret that tracks the player’s movement would inherit from SimpleEnemy_Base, whereas an enemy that runs at the player to perform a melee attack would inherit from AdvancedEnemy_Base.
Thanks to the code structure previously mentioned, I am able to build powerful and versatile systems that make development much smoother. The best example of this is my trigger system. Taking some inspiration from Valve’s Source engine, I built triggers in a multi-tiered manner that allows a single activation to produce a cascading chain of events.
The two main aspects of this system are Triggers, and Relays:
- Triggers – Volumes that detect collisions. Defines what can interact with it and how that interaction is handled. When a valid activation is determined, all child relays are told to fire
- Relays – Objects that contain the logic for a specific task. Relays are used to spawn enemies, move objects, or change stats during gameplay. For the sake of ultimate utility there is also a ‘Special’ relay that allows designers to execute any custom script when fired
Each Trigger contains a list of child Relays that are told to fire when a Trigger is detects a valid activation. Because a Trigger’s sole job is to determine a valid activation, it allows for Relays of multiple kinds to be fired from the same Trigger, reducing the number of Trigger volumes needing to be placed in the editor. To increase utility further, Triggers can also activate other Triggers, meaning a network of behavior can be fired off very simply.
- Can be activated 3 times total
- Requires at least 2 enemies touching it at the same time for 3 seconds to activate
- Once activated goes to sleep for 10 seconds
- Child Relays activate after a 2 second delay
- Upon activation tells other specified triggers to also activate
- Can be activated 5 times total
- Spawns 2 Zombie enemies each activation
- Spawns each Zombie randomly at 1 of 4 possible spawn points
- Defines a series waypoints for Zombies to move between (until they see the player and their combat AI kicks in
Systems and Mechanics
I’m still early in the prototyping phase, and thus there are a lot of mechanics and gameplay scenarios I still want to try out. Scoring systems, combat economies based off energy drops from defeating enemies, new enemy types, and new player abilities are all planned for the future of this project. There may also be some level of rpg progression, though in a less traditional manner.
Development has been extremely educational, and enjoyable for me. I would love continue development and turn this into a high quality professional release, though it is difficult to say if that will come to light. For the moment I will continue to iterate on gameplay, build new features, and work toward making the game feel great to play.