From 6df41785969cd30845c3fbec14be82ea86ab0641 Mon Sep 17 00:00:00 2001 From: OddlyTimbot Date: Mon, 26 May 2025 16:46:51 -0400 Subject: [PATCH] updates to week 5 and 6 documentation --- week5/README.md | 14 ++++++ week6/README.md | 124 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 125 insertions(+), 13 deletions(-) diff --git a/week5/README.md b/week5/README.md index e1ebe9b..b03814c 100644 --- a/week5/README.md +++ b/week5/README.md @@ -17,6 +17,20 @@ When we have reassigned the game controller to an autoload, it can be accessed b Likewise the game controller should not directly reference any other class in the display list, since it is not longer a member of the display list. Instead, it should send out a signal that members of the display list can subscribe to. +## Autoload Singletons + +The scene system in Godot is great for building multiple levels of a game and being able to run each one of them individually during development. However it does have a limitation. + +When a scene is reloaded, or another scene is loaded in its place, all information is lost. This can be problematic for gameplay, because it means that variables storing information such as player health, number of enemies, etc. are lost when the scene is reloaded. + +One answer to this is the use of an Autoload resource. + +An autoload resource is one that can be specified in the project settings. It will be loaded ahead of all other resources, and can be given a name that can be referenced throughout the game by any other code. Data in this autoloaded resource will persist across scene changes. + +An autoload script is a good place to put any persistent game logic and data, as well as any helper methods that may be useful to a wide variety of nodes in your game. + +It is possible that an autoload script can get quite cluttered with information, so a good combination is to use an autoload script and data objects together. + ### Example - Updating timer Now that the game controller is persistent, it does not reload when the level timer completes. As a result, the level loads over and over again because it thinks the time has run out. diff --git a/week6/README.md b/week6/README.md index c810cb9..4bd0f87 100644 --- a/week6/README.md +++ b/week6/README.md @@ -14,19 +14,7 @@ Lessons: * Create a resource based on the script for the player, and the enemy * Learn to load resources -## Autoload Singletons -The scene system in Godot is great for building multiple levels of a game and being able to run each one of them individually during development. However it does have a limitation. - -When a scene is reloaded, or another scene is loaded in its place, all information is lost. This can be problematic for gameplay, because it means that variables storing information such as player health, number of enemies, etc. are lost when the scene is reloaded. - -One answer to this is the use of an Autoload resource. - -An autoload resource is one that can be specified in the project settings. It will be loaded ahead of all other resources, and can be given a name that can be referenced throughout the game by any other code. Data in this autoloaded resource will persist across scene changes. - -An autoload script is a good place to put any persistent game logic and data, as well as any helper methods that may be useful to a wide variety of nodes in your game. - -It is possible that an autoload script can get quite cluttered with information, so a good combination is to use an autoload script and data objects together. Lessons: @@ -41,4 +29,114 @@ Our goals for UI: * Create a Canvas Layer to float the UI over the viewport * Create a Control node to contain our UI nodes * Create Container nodes (vbox and hbox) -* Use a MarginContainer node to wrap our UI nodes \ No newline at end of file +* Use a MarginContainer node to wrap our UI nodes + +Exercise 1: Use a custom resource to track the player health. + +First create a script to use as the basis for the custom resource. + +``` +class_name CharacterStats extends Resource + +@export var max_health:int = 100 +@export var starting_health:int = 100 +@export var health:int = 100 + +@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. + +In `gamecontroller` load in the player resource at the `ready` function. + +`player = load("res://scripts/res/playerStats.tres")` + +This will be used for all the data related to the player. + +1. In the `reset` function, return the player to full health. + +`playerHealth = player.max_health` + +2. In the player damage function, have the player's health get removed based on the melee attack strength of the enemy. + +`playerHealth -= slime.meleeDamage` + +### Update our Bad Guy + +We should update our slime so they don't run away from the player! + +``` +func _process(delta: float) -> void: + if not right_down_cast.is_colliding(): + direction = -1 + sprite.flip_h = true + if right_side_cast.is_colliding(): + if not right_side_cast.get_collider() is Player: + direction = -1 + sprite.flip_h = true + + if not left_down_cast.is_colliding(): + direction = 1 + sprite.flip_h = false + if left_side_cast.is_colliding(): + if not left_side_cast.get_collider() is Player: + direction = 1 + sprite.flip_h = false + position.x += direction * speed * delta +``` + +### Damage and Death Animations + +Time to update the character so they have a little life when they die. As a reminder, the `GameController` emits two custom signals - one for player damage, and another for player death. + +The `SceneManager` has wired up those signals to make their way to the player. + +Lets update the player controller to add on hurt and death animations. + +First we should add two additional states to our state machine. + +`enum State{IDLE, RUN, JUMP, FALLING, MELEE, HURT, DEATH}` + +Now we can update the handlers for the signals coming from the game controller. + +``` +func _player_damage(): + print("Player taking damage!") + current_state = State.HURT +``` +``` +func _player_death(): + print("Player dead!!") + current_state = State.DEATH +``` + +Then we can update the state animations to play the hurt or death animations. In the `update_animations` function: + +``` +State.HURT: + player_graphic.play("hurt") +State.DEATH: + player_graphic.play("death") +``` + +Lastly we can update our listener function that knows when animations have completed. In `_on_animation_finished`: + +``` +State.HURT: + 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. + +In `_physics_process`: + +``` +if current_state != State.HURT and current_state != State.DEATH: + handle_input() +``` + + +