Minotaur (Progress Update)
I’m not done with the game yet, but I have uploaded a working demo of what I’ve got so far here
Day 0: Planning (ish)
So for some reason I was thinking about the Greek mythical tale of the Minotaur, which was the child of a bull and some queen that got locked in a maze and fed off of people the king threw in there, until this one guy (who the king threw in) killed it with the help of the king’s daughter (I think?), and there was also something about some string. Anyways, I thought it would be a really cool idea to make a game out of this story. I spent maybe a total of two minutes thinking about the actual rules of the game, but basically you’re placed in a dungeon with a monster (the analagous minotaur), and you have to kill the monster before it kills you. Actually, it sounds a lot more boring when I phrase it like that. The part that makes this different from any other button-mashing roguelike is that the monster is too strong to face head-on (it will kill you immediately if it catches you), so the player has to employ more surreptitious tactics to slowly scrape at the monster’s health. The mechanism I came up with is the idea of a trap that you can set into which you can lure the monster (whose intelligence isn’t as astounding as its brute strength). With kind of a game plan in mind, I got to work.
Day 1: Game States
I started with the animation loop, a simple requestAnimationFrame()
call in my JavaScript. The next part was to somehow work in game states; somewhere online I’d read that many games implement states, such as the Pokémon series, which has states for when you’re walking in the overworld, for when you’re in a battle, for when you’re in a menu, and so on. I was afraid that I’d have to do some horrendous if statements in my main animation loop, but luckily I found something which I thought was much more elegant. In one of my previous endeavors, I’d stumbled across the idea of a Generator, which was pretty much perfect for what I was trying to accomplish. All I needed to do then was to create a generator for each state that I wanted in my game; my main for loop ended up looking like this:
window.onload = function() {
(function(g) {
function t() { // tick (game loop)
window.requestAnimationFrame(t)
g.states[g.state].next() // update game
}
t()
})(init()) // initialize
}
init()
initializes (who knew) the game object and feeds it as an argument to the game loop, where it calls the current state’s next()
function, drawing a new frame onto the screen. Changing from state to state is as simple as setting game.state
to the name of the next state:
g.state = "gen" // change state to gen (generate world)
I love it.
Day 2: Map Generation
Day 2 was hell. After finalizing the states system, I went onto map generation. I’d found an article sometime back that was perfect for this, so I followed its instructions. I actually won’t go through all of the steps I took, or else this post will be super long (go check out my source code if you’re brave enough, I swear I wrote comments), but I will say that I had a whole bunch of trouble on the step where I had to at one point calculate the minimum spanning tree associated with the rooms that I had generated, because there was no suitable graph theory library that I found that actually worked. So I created my own graph classes and implemented Kruskal’s algorithm to calculate the MST myself.
After that it was pretty much smooth sailing; by the end of the day I had pretty satisfactory procedurally generated dungeons, and the whole thing takes about / less than a second on my computer (2014 13” Macbook Air).
Day 3: Sprites and Textures
Day 3 was a lot of fun actually. This was the stage where I finally decided to confront my biggest fear in game development; artwork. I always knew that I was a much better programmer than I was an artist, so I tried to stay away from actually having artwork in my programs (if anything, Insanity should be a good indicator of that). However, I knew that this game would supremely benefit from having that artwork element, so I went on a hunt for some good artwork already out there. I stumbled upon Calciumtrice’s work, whose dungeon pixel art I immediately fell in love with. Coincidentally, he’d even drawn up a minotaur sprite sheet, which I was delighted to find. With his dungeon texture pack, which had pretty much everything that I needed, I started to work on the actual visuals of the game.
Loading sprite sheets into JavaScript is pretty easy thanks to their Image
object. I created a Sprite
class to help with managing both animated and static sprites, and it’s worked fine for me.
// sprite animation
function Sprite (img, w, h, ax, ay, d) {
this.delay = d || 10
this.dc = 0
this.img = img
this.w = w
this.h = h
this.ax = ax
this.ay = ay
this.c = 0
this.lcm = (function() {
return lcm(ax.length, ay.length)
})()
}
Sprite.prototype.next = function (ctx, x, y, w, h, f) {
this.dc++
if (this.dc >= this.delay) {
this.dc = 0
this.c++
if (this.c >= this.lcm) this.c = 0
}
if (f != undefined) this.c = f
ctx.drawImage(this.img, this.ax[this.c % this.ax.length], this.ay[this.c % this.ay.length], this.w, this.h, x, y, w, h)
};
I actually now realize that I could just as well use a generator to implement this Sprite
object as well. I’ll have to look into the performance comparisons sometime, as I’m creating a lot of these Sprite
objects (about 120 so far).
Then I went about drawing on the appropriate floor, wall, and ceiling textures onto the screen. For each tile in my map, I had to determine which sprite to use, depending on which tiles were surrounding it. I converted the immediate neighborhood of the tile to a decimal number, then called the Sprite
object associated with that neighborhood state. Something like this:
w = wall
f = floor
t = tile currently being inspected
fwf
wtf --> fwfwfffw (read top to bottom, left to right, skipping the tile itself) --> 01010001 --> 81 in decimal
ffw
Same thing happens for the ceiling, while the wall algorithm is slightly different. I also had to partition the wall drawing algorithm in half, in order to get the drawing order right for the perspective. The final drawing order then is as follows:
- Draw the floor
- Draw the lower half of the wall
- Draw the character
- Draw the upper half of the wall
- Draw the ceiling
And this just about works, because the character never is drawn higher than halfway up the walls.
I then added a fog of war circular thing to limit vision, because it’s a dungeon, and dungeons are dark and scary places.
Day 4: Character Movement
I originally had the character move only along the tiles of the map, which was super easy to code, but the player input for this was suuuuuper janky. It was completely unintuitive, and in respect for all games I scrapped that system and opted for a much more liberating movement system that allowed the character to move between tiles, which is nice and all, but which also introduced the key feature of being able to move diagonally. I mean, the Pokémon series did a great job of not making it suffocating to not move diagonally, but in my game I just couldn’t stand it.
While the playing experience was nice, the coding was not. The fact that I had introduced in between tile movement meant that I had to do more collision checks, since the character could now be occupying two tiles at a time. Thankfully, since my move speed is a factor of the tile sizes, I only need to check for collision when the player is right in the center of a tile (the player collision boundary is the same size as a tile), which I would like to think my processor is thankful for. Four ugly if statements later (one for each direction (ugh)), my character is no longer clipping through walls.
Day 5: Map
Since the dungeon would be pretty large, and the field of vision is pretty small, I did want to implement a map that the player could refer to, but I didn’t want to give the player the whole map at the start, in order to foster that sense of exploration and mystery.
Since I liked the theme of dungeon / old fashioned (kinda), I wanted the map to be drawn on parchment paper. Unfortunately there were no pixelated parchment maps that I could find, so I took a regular parchment image and pixelated it in Pixelmator. The parchment that I’d found had shadows near the edges, so drawing the map straight onto it looked super fake. I solved this by extracting (to the best of my ability) the shadows of the parchment in Photoshop, and then drawing the shadow on after I drew the map on. It’s a subtle touch, but I feel like it’s definitely much more immersive.
I originally had the game redraw the map only if it was visible, but doing that every tick was making the game lag a lot more than it should have. Instead, I made it so that the player would stop moving (thereby stopping the player from discovering more tiles while the map is open), and then only drew the map once when the “Open Map” button was pressed. This increased performance significantly.
The map of the dungeon itself wasn’t too difficult. There were two parts to it, drawing only the parts that the player has visited, and also outlining the dungeon’s walls. I added a process in the play loop that would mark a tile as visited if it was within a certain radius of the player, and in the map drawing process it was a simple if statement to check if the player had seen them. At first this is all I did, however, it was difficult at times to tell if the border of the map was a wall or the edge of vision, so I also added a process to draw in the borders, which made a huge difference in the aesthetics of the map.
Day 6: HUD
What is a game without its HUD (I ask this jokingly, there are many wonderful games that don’t use HUDs)? Anyway, today I worked on the HUD. I decided that the most important stats that the player should be aware of are the health (obviously) and stamina, which I put in mainly as just another thing that the player will need to manage (à la the needy modules in Keep Talking and Nobody Explodes). I found more sprites online to go with these attributes, and arranged them myself in Pixelmator, along with their corresponding bars. Pretty simple stuff actually.
Day 7: Item Drops
I’d decided a few days in that the main source of damage towards the monster would be in the form of traps, as well as some way to tell where the monster is in the dungeon in the form of a monitor (maybe a tripwire? Idk, still tbd). For now, I’ve settled with two kinds of drops, scrap metal and rope. As an avid Minecraft player, the idea of a crafting system was the first to pop into mind. I will probably settle upon crafting a placeable trap with some rope and scrap metal, and very little else, so those two items will be the only drops (for now, maybe). Calciumtrice has still got me covered, I found sprites in his spritesheet that kind of look like rope and scrap metal, only I had to recolor the scrap metal sprite in order to actually make it look like scrap metal.
After placing them onto the map, I needed to update the HUD to have indicators for the inventory. This was pretty easy, I just filled the shapes white, and wrote out the values from the game.save.player
object.