From 78b038c405ccba339e7ef9b9b998219bd136d3cb Mon Sep 17 00:00:00 2001 From: OddlyTimbot Date: Mon, 26 May 2025 17:33:42 -0400 Subject: [PATCH] added documentation on how to damage enemies --- week6/README.md | 83 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 6 deletions(-) diff --git a/week6/README.md b/week6/README.md index 4bd0f87..898bb6b 100644 --- a/week6/README.md +++ b/week6/README.md @@ -31,11 +31,14 @@ Our goals for UI: * Create Container nodes (vbox and hbox) * Use a MarginContainer node to wrap our UI nodes +## Custom Resources + Exercise 1: Use a custom resource to track the player health. -First create a script to use as the basis for the custom resource. +First create a script to use as the basis for the custom resource. This script will include any relevant data we might want to keep track of for characters in our game. ``` + class_name CharacterStats extends Resource @export var max_health:int = 100 @@ -44,14 +47,18 @@ class_name CharacterStats extends Resource @export var meleeDamage:int = 10 @export var rangeDamage:int = 8 -``` -Second, create a custom resource that extends CharacterStats. Assign health and damage values as you wish. +``` +Once the base class is created, custom resources are used to fill in specifics. In this case we can create custom resources for the player and the slime bad guys. + +Create a custom resource called `playerstats` that extends `CharacterStats`. Assign health and damage values as you wish through the Godot UI. In `gamecontroller` load in the player resource at the `ready` function. `player = load("res://scripts/res/playerStats.tres")` +You can also load in the slime resource if you have created that. + This will be used for all the data related to the player. 1. In the `reset` function, return the player to full health. @@ -124,9 +131,9 @@ Lastly we can update our listener function that knows when animations have compl ``` State.HURT: - current_state = State.IDLE - State.DEATH: - deathComplete.emit() + current_state = State.IDLE +State.DEATH: + deathComplete.emit() ``` The only other thing to do in the player code is to ensure that the player can not keep moving around while they are stunned or dying. This is pretty straightforward. We can do it by simply ignoring user input while they are being damaged. @@ -138,5 +145,69 @@ if current_state != State.HURT and current_state != State.DEATH: handle_input() ``` +## Creating a UI + +A good UI is a reflection of all the data in the game controller, and we have some good data to work with now. This includes: + +* Number of coins collected +* Player health +* Number of crates remaining +* Time remaining +* Level number + +With the way we have set our architecture, getting this information to the UI is simply a matter of wiring up listeners in the `SceneManager`. + +As an example, we could start with the time remaining. + +The process to hook this up looks like this: + +1. Create a custom signal in the Gamecontroller +2. Create a handler function in the UI +3. In the SceneManager, connect the custom signal to the handler. +4. Send out the custom signal in the Gamecontroller + +## Damaging Bad Guys (or anything) + +While we have only one player character, we have many bad guys. + +As our player runs around, they will damage various enemies at various times. How can the Gamecontroller keep track of it all? + +The answer is to use a collection called a Dictionary. + +This function is added to the Gamecontroller: + +``` +func addEnemyToLevel(enemy): + #assign a health using the enemy as a key + var enemyStat = { + "health": slime.health, + "damage": slime.meleeDamage + } + enemiesDict[enemy] = enemyStat +``` + +At the SceneManager, we call this function to assign every bad guy into the dictionary. + +``` +if enemies: + for obj in enemies.get_children(): + if obj is Slime: + obj.playerDamageSignal.connect(Gamecontroller._on_player_damage) + Gamecontroller.addEnemyToLevel(obj) +``` + +Now we can update our function in the Gamecontroller that knows when a bullet makes contact. + +``` +func bulletDamage(body, bullet): + print("Game controller knows about bullet hit") + if body is Slime: + enemiesDict[body]["health"] -= player.rangeDamage + if enemiesDict[body]["health"] <=0: + destroySignal.emit(body) + enemiesDict.erase(body) +``` + +With this set up, we can now track the health of individual bad guys in the level, and we can damage them based on the attack strength of our player!