Skip to main content

Game Jam #2 - Van Helsing (PART 3) - Functionality

 

At the end of Part 1, we had a simplistic 2D platformer with a freely rotational gun arm that fired bullets. A good start, but there was more work to be done.

Between me and the other programmer, we split the work in two. I was in charge of the foundational gameplay and mechanics, while he was in charge of the lighting, particle systems, sound effects and other fancy stuff that you throw on top. In this log and the next, I'll be covering the remainder of the functionality I added to the game, these being: 

- Enemy damage
- Player damage & Invincibility frames
- Reloading
- The ghost
- Adding the animations created by our artist

 


 Enemy Damage

First of all: zombie damage. This was easy to add. Godot has this node called Area2D that reacts every time an object overlaps with the area that you can draw in the visual editor. This makes it really useful for multiple instances of collision detection. Every time an object enters the collision area, if the object is called "Bullet_Area2D" which is the name of the Area2D node of the bullet, then a value of 1 is removed from the health variable. When that variable reaches 0, then at this point the zombie just despawned, but that was later modified when adding the animations, so we will get to it later.

 

Player Damage & Invincibility Frames


Similarly to the zombie, when the Player's Area2D node intersects with one labelled "Zombie_Area2D" (which is obviously the zombie's) then the player loses some health. However, a variable known as "invincible" is also set to true. You might notice that the condition for taking damage from a zombie is that the colliding object is a zombie AND invincible is false. So, when invincible is set to true, the player is (surprise, surprise) invincible!

This leads us on to invincibility frames. They may not always be visible, but almost every game with enemies has them. This is for the same reason that most games give you an unfair or unrealistic advantage within the game; Being lenient with hit scans, increasing damage dealt when low on health, letting you run off an edge without immediately falling, and so on. This reason is that the primary focus of a game is to be fun and engaging. And being realistic or fair rarely delivers that experience. In fact, it can even make us feel like the game is unfair, and so to avoid this, players are buffed in ways that are subtle enough to not be noticed but impactful enough that it makes the game enjoyable.

And Van Helsing is no different. Without the invincibility frames, the player would likely lose all their health at once due to the constant collision with the zombie(s) that they cannot escape for a few milliseconds. While in (a fictitious) reality, this would accurately represent what happens when you're in a horde of zombies, it presents an unfair and irritating experience as a game, which is not our goal. As such, a small window of invincibility is created after impact that gives the player time to escape before taking damage again.

So how is it achieved? Well, using a Timer node. In Godot, this node sits dormant with a set value until it is called from a script. Upon activation, the timer counts down from the value until it reaches zero when it then runs a function in the connected script. This works well except for one small issue: if the Timer.start() function is called whilst the timer is already running, it will restart. So, I needed a way to control that line of code so that it only executed when the conditions were met (invincible = true) AND the timer is not already running. This is what the timer_active variable is. You will see many incarnations of it throughout the code, as I needed a new variable for each timer (and there are a fair few of them).

The way it works is that, upon starting the timer, timer_control is set to true so that the code cannot be run again whilst active and in the on_timer_timeout() function below, it is reset to false along with invincibility.



Reloading

Every time a bullet is fired, 1 is added to the "magazine" variable. When that variable hits 10 (10 bullets fired), the reload function initiates. This triggers a "cooldown" variable that stops bullets from being able to spawn and then starts a Timer node. Here, "timerfunc" is our timer control variable in the same way "timer_active" was for the invincibility frames. On timeout (which is the terminology used for when the timer reaches 0), cooldown and timerfunc are reset to false so the process can repeat, and magazine is returned to 0.

In this screenshot, there is a print function leftover from testing. This is something I need to work on in future projects, as there are a few of these dotted in the scripts that I forgot to clean up. Though, in an amusing twist, we later found Godot produced two exports due to this: 1 standard executable and 1 executable that launched Windows command console to print these on.

Well, this is long enough as it is so i will continue explaining my remaining involvement in the next post. 

Bye for now!
- JDM

Comments

Popular posts from this blog

Game Jam #2 - Van Helsing (PART 2) - The Bullets

  (Bullet sprite by Nicolas Katsis) This part is solely on how I implemented the bullets shown in the video in Part 1. There are two parts to this split across two scripts. The first is its behaviour and the second is the spawning of the bullet. First of all, it's behaviour.   The first thing that occurs on spawn is that the bullet assigns itself to a group of objects known as "P_Bullet". You will notice in all the snippets of code that many of the variables and groups for this object are listed as "P_ something ". This is because we initially considered the idea of giving the player two different guns that they could swap between: A pistol with a higher ammo count and longer range but weaker damage, and a shotgun with a much higher damage but fewer bullets and shorter range. The P_ was a reference to 'Pistol' bullets and S_ was a reference to 'Shotgun' bullets. Unfortunately, due to time constraints, the Shotgun was never introduced. For those u...

Demigod - CSGO - Update 1

The 'player' with a cylinder to identify its front face As part of this teaching blocks assignment for my Coding & Scripting for Games module (nicknamed CSGO...we don't talk about the O) I have to make a simple game or game system inside Unreal Engine 5. This is a solo project that everyone has to do individually but as the focus is on the code, things such as appearance and presentation are not important, lightening the workload. My idea for this project is simple: I intend to make a 3D platformer wherein the player has a dash and double jump ability which can be stringed together for impressive world traversal. At first, you may think that's too easy, UE5 already has most of that built-in...until I say that I intend to program it all myself. Why am I doing that? Because of how the built-in versions work. Jumping, for instance, uses the advanced physics engine which makes it momentum based. You need to run/sprint before you jump or else you will go nowhere. Not onl...

Game Jam #2 - Van Helsing (PART 1) - The Beginning

  Game Jam #2 began on 13th October and lasted 3 weeks. The goal this time was "Shoot-em up" and the teams had been both expanded to average 4 per group and randomly assorted as opposed to being grouped based on those around you. My team consisted of the following: - Programmer (me) - Programmer - Artist - Designer  Off the bat, we were able to come up with a very solid idea for our game: A side-scrolling platformer where the player can shoot 360 degrees to kill zombies. The player can only see inside a small aura of light around them and must rely on lampposts and other light sources as well as directional audio cues to navigate the level. The other programmer, just like my last partner, had never used a game engine prior to this course. As such, we settled on using Godot for this project. The reason we chose Godot is because its proprietary scripting language, known as GDscript, is pythonic. This means it is eerily similar to python, but enhanced and integrated enough that ...