From 7842e15c6c5ceefb10c004937064b6917a8db598 Mon Sep 17 00:00:00 2001 From: Felipe M Date: Sat, 30 Jan 2021 22:58:28 +0100 Subject: [PATCH] Lessons: Player health, damage, stats, resources --- metroidvania/ResourceLoader.gd | 4 ++ metroidvania/Scenes/Enemies/Enemy.gd | 6 +- metroidvania/Scenes/Enemies/Enemy.tscn | 10 +++- metroidvania/Scenes/Enemies/EnemyStats.gd | 13 ++++ metroidvania/Scenes/Enemies/EnemyStats.tscn | 6 ++ metroidvania/Scenes/Enemies/WalkingEnemy.tscn | 15 ++++- metroidvania/Scenes/Player/Player.gd | 18 ++++++ metroidvania/Scenes/Player/Player.tscn | 59 ++++++++++++++++--- .../Scenes/Player/PlayerCollider.tres | 4 ++ metroidvania/Scenes/Player/PlayerStats.gd | 13 ++++ metroidvania/Scenes/Player/PlayetStats.tres | 6 ++ metroidvania/Scenes/World/World.tscn | 7 +-- metroidvania/project.godot | 10 +++- 13 files changed, 153 insertions(+), 18 deletions(-) create mode 100644 metroidvania/ResourceLoader.gd create mode 100644 metroidvania/Scenes/Enemies/EnemyStats.gd create mode 100644 metroidvania/Scenes/Enemies/EnemyStats.tscn create mode 100644 metroidvania/Scenes/Player/PlayerCollider.tres create mode 100644 metroidvania/Scenes/Player/PlayerStats.gd create mode 100644 metroidvania/Scenes/Player/PlayetStats.tres diff --git a/metroidvania/ResourceLoader.gd b/metroidvania/ResourceLoader.gd new file mode 100644 index 0000000..fa14999 --- /dev/null +++ b/metroidvania/ResourceLoader.gd @@ -0,0 +1,4 @@ +extends Node + +# warning-ignore-all:unused_class_variables +var PlayerStats = preload("res://Scenes/Player/PlayetStats.tres") diff --git a/metroidvania/Scenes/Enemies/Enemy.gd b/metroidvania/Scenes/Enemies/Enemy.gd index 17218aa..5866d03 100644 --- a/metroidvania/Scenes/Enemies/Enemy.gd +++ b/metroidvania/Scenes/Enemies/Enemy.gd @@ -2,8 +2,12 @@ extends KinematicBody2D export (int) var MAX_SPEED = 15 +onready var stats = $EnemyStats + var motion = Vector2.ZERO +func _on_Hurtbox_hit(damage): + stats.health -= damage -func _on_Hurtbox_hit(_damage): +func _on_EnemyStats_enemy_died(): queue_free() diff --git a/metroidvania/Scenes/Enemies/Enemy.tscn b/metroidvania/Scenes/Enemies/Enemy.tscn index 1a2d466..7b7219a 100644 --- a/metroidvania/Scenes/Enemies/Enemy.tscn +++ b/metroidvania/Scenes/Enemies/Enemy.tscn @@ -1,7 +1,9 @@ -[gd_scene load_steps=3 format=2] +[gd_scene load_steps=5 format=2] [ext_resource path="res://Scenes/Enemies/Enemy.gd" type="Script" id=1] [ext_resource path="res://Scenes/Objects/Hurtbox.tscn" type="PackedScene" id=2] +[ext_resource path="res://Scenes/Enemies/EnemyStats.tscn" type="PackedScene" id=3] +[ext_resource path="res://Scenes/Objects/Hitbox.tscn" type="PackedScene" id=4] [node name="Enemy" type="KinematicBody2D"] collision_layer = 0 @@ -16,4 +18,10 @@ script = ExtResource( 1 ) [node name="Hurtbox" parent="." instance=ExtResource( 2 )] collision_mask = 8 + +[node name="Hitbox" parent="." instance=ExtResource( 4 )] +collision_mask = 4 + +[node name="EnemyStats" parent="." instance=ExtResource( 3 )] [connection signal="hit" from="Hurtbox" to="." method="_on_Hurtbox_hit"] +[connection signal="enemy_died" from="EnemyStats" to="." method="_on_EnemyStats_enemy_died"] diff --git a/metroidvania/Scenes/Enemies/EnemyStats.gd b/metroidvania/Scenes/Enemies/EnemyStats.gd new file mode 100644 index 0000000..2ff19f3 --- /dev/null +++ b/metroidvania/Scenes/Enemies/EnemyStats.gd @@ -0,0 +1,13 @@ +extends Node + +signal enemy_died + +export (int) var max_health = 1 + +# Needs to be onready to use the max_health variable +onready var health = max_health setget set_health + +func set_health(value): + health = clamp(value, 0, max_health) + if health == 0: + emit_signal("enemy_died") diff --git a/metroidvania/Scenes/Enemies/EnemyStats.tscn b/metroidvania/Scenes/Enemies/EnemyStats.tscn new file mode 100644 index 0000000..c60f0e6 --- /dev/null +++ b/metroidvania/Scenes/Enemies/EnemyStats.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://Scenes/Enemies/EnemyStats.gd" type="Script" id=1] + +[node name="EnemyStats" type="Node"] +script = ExtResource( 1 ) diff --git a/metroidvania/Scenes/Enemies/WalkingEnemy.tscn b/metroidvania/Scenes/Enemies/WalkingEnemy.tscn index 4bde810..baf52b3 100644 --- a/metroidvania/Scenes/Enemies/WalkingEnemy.tscn +++ b/metroidvania/Scenes/Enemies/WalkingEnemy.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=7 format=2] +[gd_scene load_steps=8 format=2] [ext_resource path="res://Scenes/Enemies/WalkingEnemy.gd" type="Script" id=1] [ext_resource path="res://Assets/Enemies/WalkingEnemy.png" type="Texture" id=2] @@ -26,9 +26,11 @@ tracks/0/keys = { [sub_resource type="RectangleShape2D" id=3] extents = Vector2( 7, 6 ) +[sub_resource type="RectangleShape2D" id=4] +extents = Vector2( 8, 6 ) + [node name="WalkingEnemy" instance=ExtResource( 3 )] script = ExtResource( 1 ) -MAX_SPEED = 15 [node name="Sprite" parent="." index="0"] position = Vector2( 0, -9 ) @@ -76,4 +78,13 @@ collision_mask = 0 position = Vector2( 0, -7 ) shape = SubResource( 3 ) +[node name="Collider" parent="Hitbox" index="0"] +position = Vector2( 0, -8 ) +shape = SubResource( 4 ) + +[node name="EnemyStats" parent="." index="9"] +max_health = 3 + [editable path="Hurtbox"] + +[editable path="Hitbox"] diff --git a/metroidvania/Scenes/Player/Player.gd b/metroidvania/Scenes/Player/Player.gd index 0c19342..56dbdb6 100644 --- a/metroidvania/Scenes/Player/Player.gd +++ b/metroidvania/Scenes/Player/Player.gd @@ -4,6 +4,8 @@ const DustEffect = preload("res://Scenes/Effects/DustEffect.tscn") const PlayerBullet = preload("res://Scenes/Player/PlayerBullet.tscn") const JumpEffect = preload("res://Scenes/Effects/JumpEffect.tscn") +var PlayerStats = ResourceLoader.PlayerStats + export (int) var acceleration = 512 export (int) var max_speed = 64 export (float) var friction = 0.25 @@ -12,6 +14,7 @@ export (int) var jump_force = 128 export (int) var max_slope = 46 export (int) var bullet_speed = 250 +var invincible = false setget set_invincible var motion = Vector2.ZERO var snap_vector = Vector2.ZERO var just_jumped= false @@ -22,8 +25,15 @@ onready var coyoteJumpTimer = $CoyoteJumpTimer onready var playerGun = $Sprite/PlayerGun onready var muzzle = $Sprite/PlayerGun/Sprite/Muzzle onready var fireBulletTimer = $FireBulletTimer +onready var blinkAnimator = $BlinkAnimator +func set_invincible(value): + invincible = value + +func _ready(): + PlayerStats.connect("player_died", self, "_on_died") + func _physics_process(delta): just_jumped = false var input_vector = get_input_vector() @@ -125,3 +135,11 @@ func move(): if is_on_floor() and get_floor_velocity().length() == 0 and abs(motion.x) < 1: position.x = last_position.x +func _on_Hurtbox_hit(damage): + if not invincible: + PlayerStats.health -= damage + blinkAnimator.play("Blink") + + +func _on_died(): + queue_free() diff --git a/metroidvania/Scenes/Player/Player.tscn b/metroidvania/Scenes/Player/Player.tscn index 2ffd76d..9cfacd8 100644 --- a/metroidvania/Scenes/Player/Player.tscn +++ b/metroidvania/Scenes/Player/Player.tscn @@ -1,14 +1,11 @@ -[gd_scene load_steps=9 format=2] +[gd_scene load_steps=11 format=2] [ext_resource path="res://Assets/Player/Player.png" type="Texture" id=1] [ext_resource path="res://Scenes/Player/Player.gd" type="Script" id=2] [ext_resource path="res://DebugKinematicBody2D.tscn" type="PackedScene" id=3] [ext_resource path="res://Scenes/Player/PlayerGun.tscn" type="PackedScene" id=4] - - - -[sub_resource type="RectangleShape2D" id=1] -extents = Vector2( 4, 7 ) +[ext_resource path="res://Scenes/Objects/Hurtbox.tscn" type="PackedScene" id=5] +[ext_resource path="res://Scenes/Player/PlayerCollider.tres" type="Shape2D" id=6] [sub_resource type="Animation" id=2] resource_name = "Idle" @@ -77,6 +74,39 @@ tracks/1/keys = { } ] } +[sub_resource type="Animation" id=5] +resource_name = "Blink" +length = 0.9 +tracks/0/type = "value" +tracks/0/path = NodePath("Sprite:visible") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/keys = { +"times": PoolRealArray( 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 ), +"transitions": PoolRealArray( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), +"update": 1, +"values": [ false, true, false, true, false, true, false, true, false, true ] +} +tracks/1/type = "method" +tracks/1/path = NodePath(".") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/keys = { +"times": PoolRealArray( 0, 0.9 ), +"transitions": PoolRealArray( 1, 1 ), +"values": [ { +"args": [ true ], +"method": "set_invincible" +}, { +"args": [ false ], +"method": "set_invincible" +} ] +} + [node name="Player" type="KinematicBody2D"] collision_mask = 2 script = ExtResource( 2 ) @@ -93,13 +123,16 @@ position = Vector2( 1, 3 ) [node name="Collision" type="CollisionShape2D" parent="."] position = Vector2( 0, -7 ) -shape = SubResource( 1 ) +shape = ExtResource( 6 ) [node name="Animation" type="AnimationPlayer" parent="."] anims/Idle = SubResource( 2 ) anims/Jump = SubResource( 3 ) anims/Run = SubResource( 4 ) +[node name="BlinkAnimator" type="AnimationPlayer" parent="."] +anims/Blink = SubResource( 5 ) + [node name="Debug" parent="." instance=ExtResource( 3 )] visible = false @@ -115,3 +148,15 @@ one_shot = true [node name="FireBulletTimer" type="Timer" parent="."] wait_time = 0.3 one_shot = true + +[node name="Hurtbox" parent="." instance=ExtResource( 5 )] +collision_layer = 4 + +[node name="Collider" parent="Hurtbox" index="0"] +position = Vector2( 0, -7 ) +shape = ExtResource( 6 ) + +[node name="InvincibleTimer" type="Timer" parent="."] +[connection signal="hit" from="Hurtbox" to="." method="_on_Hurtbox_hit"] + +[editable path="Hurtbox"] diff --git a/metroidvania/Scenes/Player/PlayerCollider.tres b/metroidvania/Scenes/Player/PlayerCollider.tres new file mode 100644 index 0000000..d7e085a --- /dev/null +++ b/metroidvania/Scenes/Player/PlayerCollider.tres @@ -0,0 +1,4 @@ +[gd_resource type="RectangleShape2D" format=2] + +[resource] +extents = Vector2( 4, 7 ) diff --git a/metroidvania/Scenes/Player/PlayerStats.gd b/metroidvania/Scenes/Player/PlayerStats.gd new file mode 100644 index 0000000..abd6917 --- /dev/null +++ b/metroidvania/Scenes/Player/PlayerStats.gd @@ -0,0 +1,13 @@ +extends Resource +class_name PlayerStats + +var max_health = 4 +var health = max_health setget set_health + +signal player_died + +func set_health(value): + health = clamp(value, 0, max_health) + + if health == 0: + emit_signal("player_died") diff --git a/metroidvania/Scenes/Player/PlayetStats.tres b/metroidvania/Scenes/Player/PlayetStats.tres new file mode 100644 index 0000000..88e1f78 --- /dev/null +++ b/metroidvania/Scenes/Player/PlayetStats.tres @@ -0,0 +1,6 @@ +[gd_resource type="Resource" load_steps=2 format=2] + +[ext_resource path="res://Scenes/Player/PlayerStats.gd" type="Script" id=1] + +[resource] +script = ExtResource( 1 ) diff --git a/metroidvania/Scenes/World/World.tscn b/metroidvania/Scenes/World/World.tscn index d3db9c4..14a01ac 100644 --- a/metroidvania/Scenes/World/World.tscn +++ b/metroidvania/Scenes/World/World.tscn @@ -30,12 +30,9 @@ position = Vector2( 64, 128 ) position = Vector2( 32, 160 ) [node name="WalkingEnemy2" parent="." instance=ExtResource( 5 )] -position = Vector2( 144, 208 ) +position = Vector2( 160, 208 ) [node name="WalkingEnemy3" parent="." instance=ExtResource( 5 )] -position = Vector2( 208, 96 ) - -[node name="WalkingEnemy4" parent="." instance=ExtResource( 5 )] -position = Vector2( 320, 128 ) +position = Vector2( 448, 80 ) [editable path="Player"] diff --git a/metroidvania/project.godot b/metroidvania/project.godot index 42d369b..dc7374e 100644 --- a/metroidvania/project.godot +++ b/metroidvania/project.godot @@ -8,9 +8,14 @@ config_version=4 -_global_script_classes=[ ] +_global_script_classes=[ { +"base": "Resource", +"class": "PlayerStats", +"language": "GDScript", +"path": "res://Scenes/Player/PlayerStats.gd" +} ] _global_script_class_icons={ - +"PlayerStats": "" } [application] @@ -22,6 +27,7 @@ config/icon="res://icon.png" [autoload] Utils="*res://Utils.gd" +ResourceLoader="*res://ResourceLoader.gd" [display]