Devlog #1 - The Trespasser 2018 Retrospective 2 February 2019
Welcome to the first devlog for The Trespasser, a 2D action role-playing game featuring fast paced combat, a small open world, and gothic horror setting. This being the first devlog, I thought it would be good to make a retrospective of The Trespasser's development in 2018. Currently, I'm only able to work on the project part time, but I'm proud of the strides I've made this past year. A lot of the work done in 2018 set a foundation for what The Trespasser will become this year and beyond. This retrospective aims to highlight those improvements and to share my thoughts and experience on the project.
Before I get into it, I'll introduce myself. My name is Stephen Coley. I live in Indianapolis, Indiana where I work full time as a senior software developer specializing in web applications. I have been programming since middle school, but it wasn't until about 5 years ago that I became interested in game development. Since then, I've abandoned 3 game projects, competed in 2 game jams, and spent about 3 years off and on working on The Trespasser.
Enough about me. Let's talk about the game.
Combat is one of my favorite things to work on in The Trespasser. It is the place where all mechanics converge to create something engaging and fun. Making sure everything lines up is the hard part. It can be easy to jump head first into the fun bits, but I found that building out the basic actions first encouraged me to make sure all other combat mechanics enriched the basic actions.
Melee and ranged attacks are the two basic actions in The Trespasser's combat, but it was clear early on that something was wrong. The player could only move, and therefore aim, in eight directions - cardinal and inter-cardinal. This meant that if you weren't lined up perfectly with your enemy, your attack would miss. Not at your own fault, but due to the player character's limitations. This flaw led to the next action, locking on.
Lock-on was something I struggled with for a while. I thought I needed some fancy math to allow the player to circle the enemy and move in and out of action at the same time. It turned out that locking-on felt a lot better when the player character could move like normal, but always faced the target. The answer was obvious and right in front of my face, but I didn't see it until I failed few times with more complex solutions.
Now that the player character's offensive capabilities were shaping up, it was time to work on evasive maneuvers. At this point, rolling was already possible, but didn't feel right while locked onto the enemy. This is where dashing comes in. Even though I don't have a dash animation yet, the mechanic is already in place. That alone is enough to tell that dashing enriches melee and ranged attacks. If you need to close the gap between you and your enemy to make a melee attack, dash in. If you need to create some space, whether to evade or to cast a ranged attack, dash out.
Every action the player takes is tied to stamina or magic resources. Rolling, dashing, and melee attacks all cost stamina, and ranged attacks cost magic. I talk a little more about this later on when discussing the head-up display.
Combat still has a ways to go. Even though all of my work so far has been based on player behaviors, it will translate to other human-based enemies as well. The hard part will be programming the enemy AI and making enemies react to the player's actions.
Lighting and Shadows
At this point last year, I was already using Unity lights and custom diffuse shaders to create atmosphere in the game world. I had just started toying with a homegrown shadow system that I made by adapting a field of view tutorial. This is how it worked: raycast around the light, store the raycast hits as vertices, convert the vertices into a mesh, render the mesh as an image with a second camera, and finally use that image as the light object's cookie. I'm exhausted just thinking about it.
The experiment was bittersweet - it convinced me that the game needed shadows, but failed to live up my standards by proving to be expensive, inaccurate, and limited. Game performance was hindered by calculating dozens of raycasts every frame. Shadows looked odd and didn't match the shape of the object that cast them. Only one light could provide shadows per scene. These three flaws convinced me to try Unity's built-in shadows, even if it came with some overhead.
If you want to use real shadows, your scenes need to have real depth. Otherwise your shadows will look off. For me, this involved assigning heights and z-axis offsets to my level objects. If the street sprites sat on (0, 0, 0), then the curb sprite sat on (0, 0, 64) and had a height of 64. This use of the z-axis allows shadows to be cast correctly on surfaces of varying heights. In addition objects needing a sense of height, they also needed form, especially along the z-axis. I solved this by adding 3D meshes under sprites and set them to "shadows only" mode. You can see the result of using both of these techniques in the image below.
At the end of 2018 I started creating normal maps for sprites. These really help give a sense of depth to your objects, especially if you make use of moving light sources. Currently I'm hand painting all normal maps, which is a slow but worthwhile process. You can see my latest normal maps on the floor tiles, barrels, and walls in the image above.
One of my favorite additions of 2018 is parallax. The level layouts I'm using involve areas that are stacked on top of one another, and you can see multiple areas at once. Before I added parallax, there was no sense of depth and the areas didn't read very well. Now it feels a lot better, and there's no question as to whether an object is above or below you.
Cameras can be tough to get right. It's one of the things you don't want the player to notice. If they do, there is probably something wrong. For example, say the player walks into a building. As they walk through, if the camera peeks over the walls and shows the forest outside not only would it take up precious camera real-estate with unimportant information, but could also break the player's immersion. Ideally you want the edges of the camera to hug the walls of the building or room the player is walking through.
Some games might prefer it the other way. Maybe it's a sneaking game, and being able to see what's on the other side of the wall is important. It depends on the type of game you're making and the information you want to give to the player. I needed a camera that would hug walls or center itself on a room that was smaller than the camera resolution. Enter, what I call, camera snaps. There's probably a smart industry name for this technique, but what can I say? I'm an amateur.
Data-wise, a camera snap is a set of xy coordinates and an orientation. If I wanted to stop the camera from panning too far down, I would set the orientation to "bottom" and the position(xy coordinates) to the lowest point I wanted the camera to travel. Now if the bottom of the camera dips below that point, it is immediately moved back up so the bottom is flush with the camera snap. These snaps are dynamically swapped in and out as the player walks through the level and the camera adjusts between them smoothly.
Last year I stopped using Unity's built-in canvas to display the HUD. I was having a rough time getting the canvas' pixel art and text to line up with the game's pixel art, and I knew I could achieve this if I rendered it like any other game object. It required some more code - I didn't have access to the alignment tools usually provided by canvas. After implementing the features I needed, things started to look a lot better. Now the HUD is always scaled correctly, always in the right position, and it's pixel art and text are always on the pixel grid.
Currently the HUD displays the player's health, stamina, and magic resource. The health is represented by the red bar(of course), the stamina by the purple bar, and the magic resource by the number in the diamond shape.
When the player enters a different area, a title card will pop up. I like these because they give the player context for what they're about to see. They can also serve as mile markers or sign posts. Currently, they are bordered on the right and bottom by some kind of rusty barbed pikes. Eventually I would like make each title card resemble it's area, but that's not a priority at the moment.
Some say amateur devs should stay away from a feature like character customization. Prior to 2018, I heeded such advice. I knew it would require a new system, a menu or two, and many more animations. During 2018, my thoughts on this changed. I knew the player character wouldn't have a back story, at least not in the traditional sense. I knew the game wouldn't force the player to adopt the goals and desires of a contrived character persona. And I knew that the game's top-down perspective would be an obstacle for giving the player a sense of agency. This led me to the conclusion that character creation is a must. The player needs something to anchor them to the avatar they're controlling.
Allowing the player to create and customize their character goes a long way in getting them invested in the avatar. It also brings attention to the type of game ahead. Your choices and strategies, accomplishments and failures will vary each play-through - why shouldn't your character?
When I started the feature, it wasn't the implementation that worried me, but the process of creating and organizing all of the sprites. Lucky for me, I had just purchased Aseprite, a feature rich pixel art editor with animation tooling and a command line interface to boot. The high-level organization, command line interface, and low asking price made using Aseprite a no-brainer. I quickly wrote a script to export animations into sprite sheets and animation data.
Now that the sprites and data were out of Aseprite, I still had to get them into Unity and make them usable. I could have done this by hand, and for the first few I did, but I grew tired of that quickly. Thankfully Unity lets you create import scripts - scripts that are ran whenever an asset is imported. For my use case, if a "human" sprite was imported, the script knows how to configure the texture and automatically create an animation using the animation data. This Unity import script combined with the Aseprite export script automated away the tedious parts of the process and allowed me to focus on the art and animation.
So what's next? 2019 is young and there's a lot to do. My main areas of focus this year include enemies and their combat actions, the player character's combat and non-combat actions, level design and world building, and getting the game in front of more eyes. I would love to complete a vertical slice of the game - one full area where someone can play through and experience most of what the game has to offer. This would allow me to start play testing in earnest and even grants the possibility of a public demo. We'll see.
If you've read to this point, thank you for sticking around. The Trespasser has become a labor of love for me. Every time I'm able to make meaningful progress, I feel energized and ready to tackle more. I am proud of the progress I've made, especially in contrast to how the game looked in 2016. This year, I hope to spend even more of my time working on this project and writing about it too. If you'd like hear more about The Trespasser's development, you can follow me on Twitter or subscribe to the newsletter below.