Iteration 2 – Production Diary

Monday, 25th

At the end of Iteration 1, I encountered an issue where the game would crash if an enemy was killed by two monsters at the same time, due to it being removed from the enemy array. In an attempt to fix this, James and I looked into using groups instead, and extending the Phaser sprite class. However, the game was producing increasingly complex errors, mainly due to how I was having to handle collisions. Therefore, I decided to give the game a clean slate, and switch physics systems to Arcade.

I created a new repository on Github so that I wouldn’t lose my Iteration 1 code. However, looking back on this decision I could have created a separate branch in the same repository instead as this would have allowed me to gain proficiency in maintaining separate branches of code.

In Iteration 1, I gave my altar, tentacles, pause button and enemies sprite properties. To update my code, I changed how their classes worked to extend the sprite class instead. This enabled me to cut some useless code out that created animations for changing the altar’s current frame – now I use the setTexture method instead.

Tuesday, 26th

Today I worked on the tentacle physics group. When I initially created the group, I attempted to make it so that the group’s class was the TentacleClass. However, this didn’t work, as Phaser 3 was looking for properties that it couldn’t find. The fix for this was very simple, if I didn’t define the class or set any properties of the group then I could just add tentacles to the group whenever I need to.

One of my main goals for Iteration 2 is to update the UI for the game. The first way that I am doing this is by changing how the player summons tentacles. Instead of opening a menu that clutters up the screen, the player presses a button that creates a sprite that they can drag and drop wherever they want. Next, the player must press the button again to confirm their decision. To implement this, I created a SpriteButton class that will change the sprite’s frame when the button is pressed so that the player will be prompted to press the button again.

A small issue from Iteration 1 that I fixed was that some of the spritesheets looked slightly off. Turns out that I had set the margin on each of the spritesheets to 1px, when I needed to set the spacing that way. Since none of the spritesheets were more than two columns wide, I hadn’t seen any major visual problems so it took me adding a new spritesheet to notice.

Currently, the amount of health and blood the player has is displayed next to text explaining what each number represents. To make the UI more compact, I sourced a heart icon for health and created a blood droplet for blood. I then moved where the blood and health was displayed from the top left of the screen to the bottom right. I want to keep as much of the game UI in a bar at the base of the screen to keep the game clean.

I re-implemented the tentacle summoning mechanic but updated it to put the tentacles into a group and snap their positions to a grid made from 32 x 32 squares. To do this I created a new function that takes in a value x and rounds it to the nearest multiple of 32.

function snap_to_grid(x) {
     if (x % 32 >= 16) {
         x = (Math.ceil(x / 32)) * 32;
     } else if (x % 32 > 0) {
         x = Math.floor(x / 32) * 32;
     }
     return x;
 }

Wednesday, 27th

Today I went into university for several hours as I had my tutorial with Aaron and I wanted to get some additional help from James. During my tutorial, we discussed the improvements to the UI and how now that I have the core mechanics in place I need to focus on making the game more complete, such as adding Game Over screens, options and ways for the player to be more active in the game during attack waves. Furthermore, we briefly spoke about the essay at the end of the year. On Aaron’s advice, I made it so that as the player drags the tentacle around the screen to choose where to place it, the tentacle will snap to the grid.

A key feature that I added today was the enemy base class, as well as a simple art asset to represent the enemies. Whenever an enemy dies, regardless of if a tentacle killed it or it reached the altar, the player gains a small amount of blood. This is so that the player doesn’t get stuck if they can’t kill any enemies because they need more damage.

To give the tentacles an area in which they can attack, I created a hit radius group that has an overlap with the enemies. When the overlap occurs, the tentacle that is associated with the hit circle attacks the enemy.

My tentacles were instantly killing the enemies when they entered their area, even though they were supposed to have a 3 second cooldown on their attack. I resolved this issue by changing the value I passed to the tentacle class, as I had been stating the attack cooldown to be 3 milliseconds, rather than 3000 ms.

The last feature that I added today was a wave of attack system. To do this, I created a WaveProperties class that takes in all the modifiers that I want for a wave so that the level can use this information.

class WaveProperties {
    constructor(spawn_speed, total_enemies, health_modifier, damage_modifier) {
        this.spawn_speed = spawn_speed;
        this.total_enemies = total_enemies;
        this.health_modifier = health_modifier;
        this.damage_modifier = damage_modifier;
    }
}

I then created an instance of this class for each wave that I wanted and stored it in a wave_properties array that could be accessed from the base class whenever there was a new wave. These properties were then added throughout the code where needed, such as where the timer for spawning enemies is created, or where the game stores the amount of health an enemy starts with.

        this.wave_properties = [
            new WaveProperties(2500, 2, 1, 1),
            new WaveProperties(2000, 5, 1, 1.2),
            new WaveProperties(1500, 25, 1.1, 1.3)];

Sunday, 31st

Today I worked on making sure my production diary was up to date.

Monday 1st

My main focus for today was to work on the UI and to implement the pause/play mechanic. Also, I wanted to add in the tentacles attacking sound effect so that whenever they attack the player gets an audio cue.

To begin improving the UI I created a circle asset to show the attack radius of the tentacles. This was so that I could turn off debug draw which would clean up the appearance of the rest of the game, especially since I had to leave it on for testing during Iteration 1.

I updated the summoning button by changing it from being a blank blue square to having a symbol of a pentagram as this associated with the summoning of demons. When the player has tapped the summoning button it lights up red to show that there’s a monster ready to be placed and to indicate to the player that they need to tap it again to complete the summon.

I also started on an upgrade button sprite to use when I add in that feature. Plus, I created a blank red and green button that could be used for general purposes in case I needed them.

One of the key features that I added today was the pause play button. I did this by creating a new class called Pause that extends Phaser.Scene. When the player taps the pause button and the wave is attacking the game will load up the pause scene. When the player taps anywhere on the screen the game will resume. I found this simpler to implement than having a new pause play buttons spawn in for the pause scene. I added in a default case for the pause buttons frame so that it would show is playing in most cases this is because it would end up getting stuck on pause when the scene switched from pause to play.

A bug that I’d been having was that the game wouldn’t end when the last wave was reached. I found that this was due to the wave number was not reaching the total number of waves in the level when it was supposed to be. I fix this by changing how I checked for if the level was complete.

if (this.wave_no === this.no_of_waves - 1)

Wednesday 3rd

Today I started work on the upgrade button for the tentacles. I created a new upgrade button class that extends Phaser.Sprite. I spent quite a bit of time planning out how I wanted the tentacles to be improved when the player picks to upgrade them, and less time than I would have liked actually coding the upgrades. However, this does mean that when I finish working on the upgrade mechanic, I know exactly how I want to proceed.

class UpgradeButton extends Phaser.Physics.Arcade.Sprite {
    constructor(x, y, sprite_path, scene) {
        super(scene, x, y, sprite_path, 0);
        this.sprite_path = sprite_path;
        this.setInteractive();
        this.on("pointerdown", this.upgrade, this.scene);
    }
    upgrade() {
        //what improves when the tentacles are upgraded?
    }
    update() {
        //this.scene.upgrade_text.
    }
}

Firstly, I decided that when the player upgrades it will upgrade all of the tentacles rather than just a specific one. That way I can loop through the tentacle group and update each tentacle’s properties.

I initially came up with a list of ideas of how the tentacles could be upgraded to make them stronger. One of the ways that I could have chosen to upgrade them would be to increase attack radius however, this is me in that I’d need a new sprite and I’d need to create a new object for each tentacles attack area. I decided that this was a bit too complicated to implement at this stage.

A simple way to upgrade the tentacles and make them more powerful would be to decrease their attack cooldown. This would also give the player instant feedback that something has changed in exchange for them spending blood to upgrade.

Monday 22nd

The main feature that I worked on today was the upgrade button that allows the player to spend blood to make their tentacles stronger. The first thing that I did was change the upgrade button class to extend Phaser.Physics.Arcade.Image rather than Phaser.Physics.Arcade.Sprite which fixed an issue I was having where the upgrade button was not visible despite being interactive. When the player clicks the upgrade button it first checks if they have enough blood to afford the upgrade. Then it deducts the cost of the upgrade from the players total blood and it increases the tentacle level.

To upgrade all of the tentacles that the player has already summoned I iterate through them and increase their attack damage or decreasing their cooldown. Each time the player upgrades their tentacles the cooldown length decreases by 100ms; this allows me to scale the upgrade easily as I can multiply the current tentacle level by 100 and subtract that from the base cooldown of 3000ms.

To make sure that any new tentacles that are summoned were also upgraded I had to edit the way that values are passed to the tentacle class when a new tentacle is created. I also changed the way that attack power was passed from TentacleClass to MonsterBaseClass to ensure that it was accurate regardless of any upgrades.

Wednesday 24th

When I spoke to Aaron at the end of Iteration 1 he mentioned that the game was currently deterministic and suffered with a lack of interactivity during enemy waves. The first way that I dealt with this was by adding the wave system and upgrade functionalities. Today, I created an enemy modifier. Based on the current wave number there is a fixed chance of an enemy having different properties. The properties that I changed were: speed, health, damage and value when killed. This means that within each wave there is some variation and how the enemies behave causing the player to need to plan for a greater range of scenarios.

It was very simple to upgrade the health, damage or value of an enemy. On the other hand, it was more complicated to upgrade the speed due to the way I had the enemies follow the path. To get this to work I created a fast property that would either be true or false. Then, when the game moves the enemy along the path I have it check if the enemy is fast. If they are, then the game increments the pi value twice rather than once causing the enemy to move twice as fast.

The last feature that I added today was the ability of the game to move on to the next level if there was one. I did this by checking the config object to see if the next scene was a new level or the pause scene. This also allows me to add new levels to the game whenever I like without having to edit individual levels code.

  if (game.config.sceneConfig[level_num + 1].name === "Pause") {
      this.wave_text.setText("You Win!")
  } else {
      this.scene.Launch("Level_" + (level_num + 1));
  }

Saturday 27th

My goal for today was to tidy up the game and make sure that it was fully compatible with my target phone: the Google Pixel. The first thing I did was to create a Game Over scene that would allow the player to restart the game. However, upon looking into how to do this in Phaser, it’s quite complicated to completely reset a scene to its initial state. Consequently, I just gave the player written instructions to refresh the page to start again, as this would take less time, especially as I had already sunk a chunk of time into attempting to solve the problem.

A Google Pixel phone has a screen resolution of 960 x 544 pixels and I wanted to use a 32 x 32 tile size. Unfortunately, this isn’t a perfect fit, so my game’s default size was 960 x 540. Therefore, I decided to use scale manager to add a full-screen mode and make the game compatible with more devices. To allow the player to toggle this mode I added a small, white icon that enables and disables full-screen based on the current state of the game.

My final feature for the game was to add a tutorial to the start menu. First, I created a tutorial button in the same font as the start button. Then, I took an in-game screenshot where an enemy was visible and the player had summoned a tentacle. I put this into paint to add in text descriptions of what each button did, as well as an explanation of how to exit the tutorial.

Instead of using an image object for the tutorial, I used my existing button base class, since I wanted it to close when clicked. When the tutorial is clicked, its setActive and setVisible properties are made false so that it disappears from the screen and the player can’t accidentally interact with it. Due to object layering, I can simply overlay the tutorial over the start menu’s buttons as it makes them unclickable until it is no longer active. This prevents the player from being able to accidentally start the game or open the tutorial twice while attempting to close it.