Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6355c31a7c | ||
|
|
a6fc6acc12 | ||
|
|
7f4bc01dbe | ||
|
|
723d677a81 |
No files matched your search
@@ -1 +1,77 @@
|
|||||||
Please update with readme
|
Week 5 Challenge - Player Death Animation
|
||||||
|
|
||||||
|
First, we need to make a slight update to the logic in the game controller.
|
||||||
|
|
||||||
|
## Game Controller
|
||||||
|
|
||||||
|
This change ensures that our signal to kill the player can ONLY happen once, by checking that the health is above zero before issuing the signal.
|
||||||
|
|
||||||
|
```
|
||||||
|
func playerDamage():
|
||||||
|
#one can not kill what is dead....
|
||||||
|
if player.health >0:
|
||||||
|
player.health -= 20
|
||||||
|
#is the player dead?
|
||||||
|
if player.health <= 0:
|
||||||
|
#kill him
|
||||||
|
playerDeath.emit()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Scene Manager
|
||||||
|
|
||||||
|
In the scene_manager, we have created a connection that listens for the game controller issuing the player death command:
|
||||||
|
|
||||||
|
`GameController.playerDeath.connect(killPlayer)`
|
||||||
|
|
||||||
|
We must change the `killPlayer` function. It will tell the player to die, but will then start a timer rather than immediatly reloading the scene.
|
||||||
|
|
||||||
|
```
|
||||||
|
func killPlayer():
|
||||||
|
# tell player to die - starts death animation
|
||||||
|
player.killPlayer()
|
||||||
|
if timer.is_stopped():
|
||||||
|
timer.start(4)
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that we only start the timer *if it is not already running*. Otherwise if the scene_manager happens to hear more `playerDeath` signals from the GameController, it will keep restarting the timer.
|
||||||
|
|
||||||
|
The `resetWorld` function is connected to the `timeout` event of the timer. It looks like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
func resetWorld():
|
||||||
|
print("screne manager resetting world")
|
||||||
|
GameController.resetPlayer()
|
||||||
|
get_tree().reload_current_scene()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Player
|
||||||
|
|
||||||
|
Lastly, the player code needs to ensure that the user can not do anything when their death animation is playing.
|
||||||
|
|
||||||
|
A simple way to do this is to create a boolean that simply keeps track of whether they are alive or not.
|
||||||
|
|
||||||
|
`var living = true`
|
||||||
|
|
||||||
|
We can then update the `killPlayer` function to check if the player is currently living and update the variable before calling the death animation.
|
||||||
|
|
||||||
|
```
|
||||||
|
func killPlayer():
|
||||||
|
print("kill the player")
|
||||||
|
if living:
|
||||||
|
living = false
|
||||||
|
#play death animation
|
||||||
|
playerSprite.play("death")
|
||||||
|
```
|
||||||
|
|
||||||
|
With the `living` variable set to false, we simply check the variable before doing *anything* in the `_physics_process` function.
|
||||||
|
|
||||||
|
```
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
if living:
|
||||||
|
# Add the gravity.
|
||||||
|
if not is_on_floor():
|
||||||
|
velocity += get_gravity() * delta
|
||||||
|
.......and so forth....
|
||||||
|
```
|
||||||
|
|
||||||
|
When the timer ends and the scene reloads, all of these variables will be reset and the loop begins again.
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b2brlauvni08o"
|
||||||
|
path="res://.godot/imported/Player Hurt 48x48.png-a720e51cb19103e76b22ab6c1b81302d.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/graphics/player/hurt/Player Hurt 48x48.png"
|
||||||
|
dest_files=["res://.godot/imported/Player Hurt 48x48.png-a720e51cb19103e76b22ab6c1b81302d.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
[gd_scene load_steps=39 format=3 uid="uid://dbgc24hrbtvxm"]
|
[gd_scene load_steps=44 format=3 uid="uid://dbgc24hrbtvxm"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/player.gd" id="1_5qpif"]
|
[ext_resource type="Script" path="res://scripts/player.gd" id="1_5qpif"]
|
||||||
[ext_resource type="Texture2D" uid="uid://d6d3re6epsh4" path="res://assets/graphics/player/death/Player Death 64x64.png" id="2_t1yra"]
|
[ext_resource type="Texture2D" uid="uid://d6d3re6epsh4" path="res://assets/graphics/player/death/Player Death 64x64.png" id="2_t1yra"]
|
||||||
[ext_resource type="Texture2D" uid="uid://pdvgf3y1lquv" path="res://assets/graphics/player/idle/Player Idle 48x48.png" id="2_vcmr0"]
|
[ext_resource type="Texture2D" uid="uid://pdvgf3y1lquv" path="res://assets/graphics/player/idle/Player Idle 48x48.png" id="2_vcmr0"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cvh48exhs1ir1" path="res://assets/graphics/player/run/player run 48x48.png" id="3_a03rx"]
|
[ext_resource type="Texture2D" uid="uid://cvh48exhs1ir1" path="res://assets/graphics/player/run/player run 48x48.png" id="3_a03rx"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://b2brlauvni08o" path="res://assets/graphics/player/hurt/Player Hurt 48x48.png" id="3_a70o5"]
|
||||||
[ext_resource type="Texture2D" uid="uid://d0kfe5ms2vjbr" path="res://assets/graphics/player/jump/player jump 48x48.png" id="3_mvdmt"]
|
[ext_resource type="Texture2D" uid="uid://d0kfe5ms2vjbr" path="res://assets/graphics/player/jump/player jump 48x48.png" id="3_mvdmt"]
|
||||||
|
|
||||||
[sub_resource type="AtlasTexture" id="AtlasTexture_uru55"]
|
[sub_resource type="AtlasTexture" id="AtlasTexture_uru55"]
|
||||||
@@ -46,6 +47,22 @@ region = Rect2(384, 0, 48, 48)
|
|||||||
atlas = ExtResource("2_t1yra")
|
atlas = ExtResource("2_t1yra")
|
||||||
region = Rect2(432, 0, 48, 48)
|
region = Rect2(432, 0, 48, 48)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_me361"]
|
||||||
|
atlas = ExtResource("3_a70o5")
|
||||||
|
region = Rect2(0, 0, 48, 48)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_5yslj"]
|
||||||
|
atlas = ExtResource("3_a70o5")
|
||||||
|
region = Rect2(48, 0, 48, 48)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_l8y4s"]
|
||||||
|
atlas = ExtResource("3_a70o5")
|
||||||
|
region = Rect2(96, 0, 48, 48)
|
||||||
|
|
||||||
|
[sub_resource type="AtlasTexture" id="AtlasTexture_vc70i"]
|
||||||
|
atlas = ExtResource("3_a70o5")
|
||||||
|
region = Rect2(144, 0, 48, 48)
|
||||||
|
|
||||||
[sub_resource type="AtlasTexture" id="AtlasTexture_etdvv"]
|
[sub_resource type="AtlasTexture" id="AtlasTexture_etdvv"]
|
||||||
atlas = ExtResource("2_vcmr0")
|
atlas = ExtResource("2_vcmr0")
|
||||||
region = Rect2(0, 0, 48, 48)
|
region = Rect2(0, 0, 48, 48)
|
||||||
@@ -169,6 +186,23 @@ animations = [{
|
|||||||
}, {
|
}, {
|
||||||
"frames": [{
|
"frames": [{
|
||||||
"duration": 1.0,
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_me361")
|
||||||
|
}, {
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_5yslj")
|
||||||
|
}, {
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_l8y4s")
|
||||||
|
}, {
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": SubResource("AtlasTexture_vc70i")
|
||||||
|
}],
|
||||||
|
"loop": false,
|
||||||
|
"name": &"hurt",
|
||||||
|
"speed": 12.0
|
||||||
|
}, {
|
||||||
|
"frames": [{
|
||||||
|
"duration": 1.0,
|
||||||
"texture": SubResource("AtlasTexture_etdvv")
|
"texture": SubResource("AtlasTexture_etdvv")
|
||||||
}, {
|
}, {
|
||||||
"duration": 1.0,
|
"duration": 1.0,
|
||||||
@@ -256,7 +290,7 @@ metadata/_edit_group_ = true
|
|||||||
texture_filter = 1
|
texture_filter = 1
|
||||||
position = Vector2(0, -7)
|
position = Vector2(0, -7)
|
||||||
sprite_frames = SubResource("SpriteFrames_wlxdo")
|
sprite_frames = SubResource("SpriteFrames_wlxdo")
|
||||||
animation = &"death"
|
animation = &"hurt"
|
||||||
autoplay = "idle"
|
autoplay = "idle"
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
@@ -274,3 +308,5 @@ position = Vector2(12, -5)
|
|||||||
|
|
||||||
[node name="MarkerLeft" type="Node2D" parent="."]
|
[node name="MarkerLeft" type="Node2D" parent="."]
|
||||||
position = Vector2(-15, -5)
|
position = Vector2(-15, -5)
|
||||||
|
|
||||||
|
[connection signal="animation_finished" from="AnimatedSprite2D" to="." method="_on_animation_finished"]
|
||||||
@@ -4,6 +4,7 @@ var coinsCollected:int = 0
|
|||||||
var player:Resource
|
var player:Resource
|
||||||
|
|
||||||
signal playerDeath
|
signal playerDeath
|
||||||
|
signal playerHurt
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
print("Game controller is ready")
|
print("Game controller is ready")
|
||||||
@@ -18,10 +19,13 @@ func resetPlayer():
|
|||||||
player.health = player.max_health
|
player.health = player.max_health
|
||||||
|
|
||||||
func playerDamage():
|
func playerDamage():
|
||||||
player.health -= 20
|
#one can not kill what is dead....
|
||||||
print("Player health is : "+str(player.health) )
|
if player.health >0:
|
||||||
#is the player dead?
|
player.health -= 20
|
||||||
if player.health <= 0:
|
#is the player dead?
|
||||||
#kill him
|
if player.health <= 0:
|
||||||
playerDeath.emit()
|
#kill him
|
||||||
|
playerDeath.emit()
|
||||||
|
else:
|
||||||
|
playerHurt.emit()
|
||||||
|
|
||||||
@@ -6,6 +6,10 @@ const JUMP_VELOCITY = -400.0
|
|||||||
const PUSH_FORCE = 700
|
const PUSH_FORCE = 700
|
||||||
|
|
||||||
var faceLeft = false
|
var faceLeft = false
|
||||||
|
var living = true
|
||||||
|
|
||||||
|
signal playerDead
|
||||||
|
|
||||||
# can i push right or left
|
# can i push right or left
|
||||||
var pushLeftEnabled = false
|
var pushLeftEnabled = false
|
||||||
var pushRightEnabled = false
|
var pushRightEnabled = false
|
||||||
@@ -16,92 +20,101 @@ var pushRightEnabled = false
|
|||||||
@onready var playerSprite: AnimatedSprite2D = $AnimatedSprite2D
|
@onready var playerSprite: AnimatedSprite2D = $AnimatedSprite2D
|
||||||
|
|
||||||
var pushTarget
|
var pushTarget
|
||||||
|
var animPlaying = "idle"
|
||||||
|
|
||||||
var bullet = preload("res://scenes/bullet.tscn")
|
var bullet = preload("res://scenes/bullet.tscn")
|
||||||
|
|
||||||
func killPlayer():
|
func killPlayer():
|
||||||
print("kill the player")
|
if living:
|
||||||
#play death animation
|
living = false
|
||||||
playerSprite.play("death")
|
animPlaying = "death"
|
||||||
|
#play death animation
|
||||||
|
playerSprite.play("death")
|
||||||
|
|
||||||
|
func hurtPlayer():
|
||||||
|
animPlaying="hurt"
|
||||||
|
print("player should get hurt")
|
||||||
|
playerSprite.play("hurt")
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
# Add the gravity.
|
if living and not animPlaying=="hurt":
|
||||||
if not is_on_floor():
|
# Add the gravity.
|
||||||
velocity += get_gravity() * delta
|
if not is_on_floor():
|
||||||
|
velocity += get_gravity() * delta
|
||||||
|
|
||||||
# Handle jump.
|
# Handle jump.
|
||||||
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
|
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
|
||||||
velocity.y = JUMP_VELOCITY
|
velocity.y = JUMP_VELOCITY
|
||||||
|
|
||||||
if Input.is_action_just_pressed("Shove") && pushLeftEnabled && faceLeft:
|
if Input.is_action_just_pressed("Shove") && pushLeftEnabled && faceLeft:
|
||||||
print("shove a box on the left")
|
pushTarget.apply_central_impulse(Vector2(-1,0) * PUSH_FORCE * 1.5)
|
||||||
pushTarget.apply_central_impulse(Vector2(-1,0) * PUSH_FORCE * 1.5)
|
pushLeftEnabled = false
|
||||||
pushLeftEnabled = false
|
|
||||||
|
|
||||||
if Input.is_action_just_pressed("Shove") && pushRightEnabled && not faceLeft:
|
if Input.is_action_just_pressed("Shove") && pushRightEnabled && not faceLeft:
|
||||||
print("shove a box on the right")
|
pushTarget.apply_central_impulse(Vector2(1,0) * PUSH_FORCE * 1.5)
|
||||||
pushTarget.apply_central_impulse(Vector2(1,0) * PUSH_FORCE * 1.5)
|
pushRightEnabled=false
|
||||||
pushRightEnabled=false
|
|
||||||
|
|
||||||
if Input.is_action_just_pressed("shoot"):
|
if Input.is_action_just_pressed("shoot"):
|
||||||
|
if faceLeft:
|
||||||
|
# mybullet.setSpeed(-700)
|
||||||
|
#mybullet.transform = marker_left.global_transform
|
||||||
|
%SceneManager.placeBullet(-700, marker_left.global_transform)
|
||||||
|
else:
|
||||||
|
#mybullet.transform = marker_right.global_transform
|
||||||
|
%SceneManager.placeBullet(700, marker_right.global_transform)
|
||||||
|
|
||||||
|
# Get the input direction and handle the movement/deceleration.
|
||||||
|
# As good practice, you should replace UI actions with custom gameplay actions.
|
||||||
|
var direction := Input.get_axis("ui_left", "ui_right")
|
||||||
|
if direction <0:
|
||||||
|
faceLeft = true
|
||||||
|
playerSprite.flip_h = true
|
||||||
|
if direction >0:
|
||||||
|
faceLeft = false
|
||||||
|
playerSprite.flip_h = false
|
||||||
|
|
||||||
|
if direction:
|
||||||
if faceLeft:
|
velocity.x = direction * SPEED
|
||||||
print("shoot left")
|
|
||||||
# mybullet.setSpeed(-700)
|
|
||||||
#mybullet.transform = marker_left.global_transform
|
|
||||||
%SceneManager.placeBullet(-700, marker_left.global_transform)
|
|
||||||
else:
|
else:
|
||||||
print("shoot right")
|
velocity.x = move_toward(velocity.x, 0, SPEED)
|
||||||
#mybullet.transform = marker_right.global_transform
|
|
||||||
%SceneManager.placeBullet(700, marker_right.global_transform)
|
|
||||||
|
|
||||||
# Get the input direction and handle the movement/deceleration.
|
if is_on_floor():
|
||||||
# As good practice, you should replace UI actions with custom gameplay actions.
|
if direction == 0:
|
||||||
var direction := Input.get_axis("ui_left", "ui_right")
|
playerSprite.play("idle")
|
||||||
if direction <0:
|
else:
|
||||||
faceLeft = true
|
playerSprite.play("run")
|
||||||
playerSprite.flip_h = true
|
|
||||||
if direction >0:
|
|
||||||
faceLeft = false
|
|
||||||
playerSprite.flip_h = false
|
|
||||||
|
|
||||||
if direction:
|
|
||||||
velocity.x = direction * SPEED
|
|
||||||
else:
|
|
||||||
velocity.x = move_toward(velocity.x, 0, SPEED)
|
|
||||||
if is_on_floor():
|
|
||||||
if direction == 0:
|
|
||||||
playerSprite.play("idle")
|
|
||||||
else:
|
else:
|
||||||
playerSprite.play("run")
|
playerSprite.play("jump")
|
||||||
else:
|
|
||||||
playerSprite.play("jump")
|
|
||||||
|
|
||||||
move_and_slide()
|
move_and_slide()
|
||||||
for i in get_slide_collision_count():
|
for i in get_slide_collision_count():
|
||||||
var c = get_slide_collision(i)
|
var c = get_slide_collision(i)
|
||||||
if c.get_collider() is RigidBody2D:
|
if c.get_collider() is RigidBody2D:
|
||||||
c.get_collider().apply_central_impulse(-c.get_normal()* 100)
|
c.get_collider().apply_central_impulse(-c.get_normal()* 100)
|
||||||
|
|
||||||
if left_ray.is_colliding():
|
if left_ray.is_colliding():
|
||||||
print("left ray collision")
|
var collider = left_ray.get_collider()
|
||||||
var collider = left_ray.get_collider()
|
if collider is Node:
|
||||||
if collider is Node:
|
if collider.is_in_group("pushables"):
|
||||||
if collider.is_in_group("pushables"):
|
pushLeftEnabled = true
|
||||||
pushLeftEnabled = true
|
pushTarget = collider
|
||||||
pushTarget = collider
|
else:
|
||||||
else:
|
#do something else
|
||||||
#do something else
|
pushLeftEnabled = false
|
||||||
pushLeftEnabled = false
|
|
||||||
|
|
||||||
if right_ray.is_colliding():
|
if right_ray.is_colliding():
|
||||||
print("right ray collision")
|
var collider = right_ray.get_collider()
|
||||||
var collider = right_ray.get_collider()
|
if collider is Node:
|
||||||
if collider is Node:
|
if collider.is_in_group("pushables"):
|
||||||
if collider.is_in_group("pushables"):
|
pushRightEnabled = true
|
||||||
pushRightEnabled = true
|
pushTarget = collider
|
||||||
pushTarget = collider
|
else:
|
||||||
else:
|
pushRightEnabled = false
|
||||||
pushRightEnabled = false
|
|
||||||
|
|
||||||
|
func _on_animation_finished() -> void:
|
||||||
|
print(animPlaying + " finished playing.")
|
||||||
|
if animPlaying == "hurt":
|
||||||
|
animPlaying="idle"
|
||||||
|
if animPlaying=="death":
|
||||||
|
playerDead.emit()
|
||||||
@@ -28,6 +28,8 @@ func _ready() -> void:
|
|||||||
n.playerDamage.connect(GameController.playerDamage)
|
n.playerDamage.connect(GameController.playerDamage)
|
||||||
#GameController signals
|
#GameController signals
|
||||||
GameController.playerDeath.connect(killPlayer)
|
GameController.playerDeath.connect(killPlayer)
|
||||||
|
GameController.playerHurt.connect(hurtPlayer)
|
||||||
|
player.playerDead.connect(deadPlayer)
|
||||||
|
|
||||||
func boxTrap():
|
func boxTrap():
|
||||||
print("Trigger a box trap!")
|
print("Trigger a box trap!")
|
||||||
@@ -64,12 +66,15 @@ func crateFactory():
|
|||||||
return myCrate
|
return myCrate
|
||||||
|
|
||||||
func killPlayer():
|
func killPlayer():
|
||||||
print("kill the player now")
|
# tell player to die - starts death animation
|
||||||
player.killPlayer()
|
player.killPlayer()
|
||||||
timer.start(3)
|
func hurtPlayer():
|
||||||
|
player.hurtPlayer()
|
||||||
|
|
||||||
|
func deadPlayer():
|
||||||
|
if timer.is_stopped():
|
||||||
|
timer.start(1)
|
||||||
|
|
||||||
func resetWorld():
|
func resetWorld():
|
||||||
print("screne manager resetting world")
|
|
||||||
GameController.resetPlayer()
|
GameController.resetPlayer()
|
||||||
get_tree().reload_current_scene()
|
get_tree().reload_current_scene()
|
||||||
Reference in new issue
Block a user