updates to week 5 and 6 documentation

This commit is contained in:
OddlyTimbot 2025-05-26 16:46:51 -04:00
parent 8a23abe2ea
commit 6df4178596
2 changed files with 125 additions and 13 deletions

View File

@ -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.

View File

@ -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
* 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()
```