From 13f95562a7ca3fa76646facdadd87ee11d4303be Mon Sep 17 00:00:00 2001 From: doctorbatmanwho-creator Date: Thu, 18 Jun 2026 20:27:14 -0400 Subject: [PATCH] Implemented demon enemy combat, enemy knockback, and directional player attacks - Added Demon enemy scene with detection, pursuit, attack, hurt, and death states - Configured Demon collision layers, detection area, and attack hitbox - Fixed Demon movement to pursue player horizontally and attack at close range - Allowed enemy/player overlap for melee combat encounters - Added enemy damage and death handling - Added knockback system for enemies when hit - Fixed player punch hitbox positioning based on facing direction - Corrected directional melee attacks so enemies can be hit from both left and right sides - Fixed collision mask issues affecting floors and enemy detection - Improved memory piece pickup interaction to support button-based collection - Continued testing and debugging combat interactions in Graveyard and Demon levels --- Scenes/Characters/Demon.tscn | 3 +-- Scenes/Characters/Player.tscn | 6 +++++- Scenes/Characters/Skeleton.tscn | 2 ++ Scenes/Levels/MainGame.tscn | 4 ++-- Scripts/demon.gd | 26 ++++++++++++++++++++++-- Scripts/player.gd | 36 +++++++++++++++++++++++++++++---- Scripts/skeleton.gd | 27 ++++++++++++++++++++++--- 7 files changed, 90 insertions(+), 14 deletions(-) diff --git a/Scenes/Characters/Demon.tscn b/Scenes/Characters/Demon.tscn index 4ef9d9e..dbf31cd 100644 --- a/Scenes/Characters/Demon.tscn +++ b/Scenes/Characters/Demon.tscn @@ -242,8 +242,7 @@ script = ExtResource("1_02sxe") [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] sprite_frames = SubResource("SpriteFrames_02sxe") -animation = &"flying" -frame_progress = 0.13023382 +animation = &"hurt" [node name="CollisionShape2D" type="CollisionShape2D" parent="."] position = Vector2(-2, 2) diff --git a/Scenes/Characters/Player.tscn b/Scenes/Characters/Player.tscn index f49cc2c..7c75976 100644 --- a/Scenes/Characters/Player.tscn +++ b/Scenes/Characters/Player.tscn @@ -693,14 +693,18 @@ animations = [{ [node name="CharacterBody2D" type="CharacterBody2D"] z_index = 10 position = Vector2(2, -1) +collision_mask = 3 script = ExtResource("1_0y7nr") metadata/_edit_group_ = true [node name="PunchHitbox" type="Area2D" parent="."] +visibility_layer = 2 +position = Vector2(50.5, -5) +collision_layer = 4 +collision_mask = 2 monitoring = false [node name="CollisionShape2D" type="CollisionShape2D" parent="PunchHitbox"] -position = Vector2(50.5, -5) shape = SubResource("RectangleShape2D_miouo") debug_color = Color(0.97765833, 0.1351085, 0.16903454, 0.41960785) diff --git a/Scenes/Characters/Skeleton.tscn b/Scenes/Characters/Skeleton.tscn index 1a90bc6..4dd4b22 100644 --- a/Scenes/Characters/Skeleton.tscn +++ b/Scenes/Characters/Skeleton.tscn @@ -368,6 +368,7 @@ size = Vector2(452, 33) [node name="Skeleton" type="CharacterBody2D"] z_index = 10 +collision_layer = 2 script = ExtResource("1_abfcy") [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] @@ -390,6 +391,7 @@ shape = SubResource("RectangleShape2D_yek4v") debug_color = Color(0.51556015, 0.56157154, 0.37343058, 0.41960785) [node name="AttackHitbox" type="Area2D" parent="."] +collision_layer = 8 [node name="CollisionShape2D" type="CollisionShape2D" parent="AttackHitbox"] position = Vector2(37, 0.5) diff --git a/Scenes/Levels/MainGame.tscn b/Scenes/Levels/MainGame.tscn index c664512..562d2e3 100644 --- a/Scenes/Levels/MainGame.tscn +++ b/Scenes/Levels/MainGame.tscn @@ -2,7 +2,7 @@ [ext_resource type="PackedScene" uid="uid://bu8e4iyw8pc03" path="res://Scenes/Characters/Player.tscn" id="1_d5ayw"] [ext_resource type="Script" uid="uid://bs4frobn6kxne" path="res://Scripts/scene_manager.gd" id="2_us1pb"] -[ext_resource type="PackedScene" uid="uid://bcray1583u4e6" path="res://Scenes/Levels/Level_2_demons.tscn" id="3_d5ayw"] +[ext_resource type="PackedScene" uid="uid://8n6472fqqmcc" path="res://Scenes/Levels/Level_3_graveyard.tscn" id="3_d5ayw"] [node name="MainGame" type="Node2D"] @@ -13,4 +13,4 @@ script = ExtResource("2_us1pb") [node name="CurrentLevel" type="Node2D" parent="."] -[node name="DemonRace" parent="CurrentLevel" instance=ExtResource("3_d5ayw")] +[node name="Graveyard" parent="CurrentLevel" instance=ExtResource("3_d5ayw")] diff --git a/Scripts/demon.gd b/Scripts/demon.gd index e1b3004..df3c23d 100644 --- a/Scripts/demon.gd +++ b/Scripts/demon.gd @@ -14,6 +14,7 @@ var is_dead := false var is_hurt := false var is_attacking := false var attack_cooldown := false +var knockback_velocity := Vector2.ZERO func _ready() -> void: health = max_health @@ -28,7 +29,18 @@ func _physics_process(_delta: float) -> void: if is_dead: return - if is_hurt or is_attacking: + if is_hurt: + velocity = knockback_velocity + + knockback_velocity = knockback_velocity.move_toward( + Vector2.ZERO, + 800 * _delta + ) + + move_and_slide() + return + + if is_attacking: velocity = Vector2.ZERO move_and_slide() return @@ -92,11 +104,20 @@ func take_damage(amount: int = 1) -> void: if health <= 0: die() + else: is_hurt = true - velocity = Vector2.ZERO + + if player: + var knockback_direction = sign(global_position.x - player.global_position.x) + knockback_velocity = Vector2(knockback_direction * 200, 0) + sprite.play("hurt") + await get_tree().create_timer(0.3).timeout + is_hurt = false + knockback_velocity = Vector2.ZERO + func die() -> void: if is_dead: return @@ -119,6 +140,7 @@ func _on_detection_body_exited(body: Node) -> void: func _on_animation_finished() -> void: if sprite.animation == "hurt": is_hurt = false + knockback_velocity = Vector2.ZERO if sprite.animation == "attack": is_attacking = false diff --git a/Scripts/player.gd b/Scripts/player.gd index f952c8f..359b492 100644 --- a/Scripts/player.gd +++ b/Scripts/player.gd @@ -13,7 +13,7 @@ const JUMP_VELOCITY = -400.0 @onready var child_graphic: AnimatedSprite2D = $ChildGraphic @onready var punch_hitbox: Area2D = $PunchHitbox var using_child_form := false - +var punch_hitbox_start_x := 0.0 enum FaceDirection{LEFT, RIGHT} var facing:FaceDirection = FaceDirection.RIGHT @@ -122,11 +122,38 @@ func handle_movement(_delta): else: velocity.x = move_toward(velocity.x, 0, SPEED) + if direction < 0: + facing = FaceDirection.LEFT + get_active_graphic().flip_h = true + punch_hitbox.position.x = -punch_hitbox_start_x + + if direction > 0: + facing = FaceDirection.RIGHT + get_active_graphic().flip_h = false + punch_hitbox.position.x = punch_hitbox_start_x + if current_state == State.PUNCH: velocity.x = 0 return +func update_punch_hitbox_position() -> void: + if facing == FaceDirection.LEFT: + punch_hitbox.position.x = -punch_hitbox_start_x + else: + punch_hitbox.position.x = punch_hitbox_start_x + + print("Facing: ", facing) + print("PunchHitbox X: ", punch_hitbox.position.x) + func handle_input(): + direction = Input.get_axis("ui_left", "ui_right") + + if direction < 0: + facing = FaceDirection.LEFT + + if direction > 0: + facing = FaceDirection.RIGHT + if Input.is_action_just_pressed("jump") and is_on_floor(): velocity.y = JUMP_VELOCITY current_state = State.JUMP @@ -134,7 +161,9 @@ func handle_input(): if Input.is_action_just_pressed("attack"): print("ATTACK PRESSED") + update_punch_hitbox_position() current_state = State.PUNCH + await get_tree().create_timer(0.25).timeout _do_punch_damage() if Input.is_action_just_pressed("shove") && pushEnabled: @@ -154,9 +183,6 @@ func handle_input(): %SceneManager.makeBullet(left_spawn.global_transform, -700) - # Get the input direction and handle the movement/deceleration. - direction = Input.get_axis("ui_left", "ui_right") - func handle_collisions(): for i in get_slide_collision_count(): var c = get_slide_collision(i) @@ -188,6 +214,7 @@ func _ready() -> void: _set_stair_collision(false) floor_max_angle = deg_to_rad(60) punch_hitbox.monitoring = false + punch_hitbox_start_x = abs(punch_hitbox.position.x) func set_camera_limits(left: int, top: int, right: int, bottom: int) -> void: camera.limit_left = left @@ -251,6 +278,7 @@ func _do_punch_damage() -> void: punch_hitbox.monitoring = true await get_tree().physics_frame + await get_tree().physics_frame var bodies = punch_hitbox.get_overlapping_bodies() print("Punch overlaps: ", bodies.size()) diff --git a/Scripts/skeleton.gd b/Scripts/skeleton.gd index 8214e9e..98a16dd 100644 --- a/Scripts/skeleton.gd +++ b/Scripts/skeleton.gd @@ -10,7 +10,7 @@ extends CharacterBody2D @export var memory_wardrobe: Node2D @onready var sprite: AnimatedSprite2D = $AnimatedSprite2D -@onready var detection_area: Area2D = $Area2D +@onready var detection_area: Area2D = $DetectionArea @onready var attack_hitbox = $AttackHitbox @@ -20,6 +20,7 @@ var is_dead := false var is_hurt := false var is_attacking := false var attack_cooldown := false +var knockback_velocity := Vector2.ZERO func _ready() -> void: health = max_health @@ -38,7 +39,18 @@ func _physics_process(delta: float) -> void: if not is_on_floor(): velocity.y += gravity * delta - if is_hurt or is_attacking: + if is_hurt: + velocity = knockback_velocity + + knockback_velocity = knockback_velocity.move_toward( + Vector2.ZERO, + 800 * delta + ) + + move_and_slide() + return + + if is_attacking: velocity.x = 0 move_and_slide() return @@ -105,9 +117,17 @@ func take_damage(amount: int = 1) -> void: die() else: is_hurt = true - velocity.x = 0 + + if player: + var knockback_direction = sign(global_position.x - player.global_position.x) + knockback_velocity = Vector2(knockback_direction * 125, 0) + sprite.play("hurt") + await get_tree().create_timer(0.3).timeout + is_hurt = false + knockback_velocity = Vector2.ZERO + func die() -> void: if is_dead: return @@ -130,6 +150,7 @@ func _on_detection_body_exited(body: Node) -> void: func _on_animation_finished() -> void: if sprite.animation == "hurt": is_hurt = false + knockback_velocity = Vector2.ZERO if sprite.animation == "attack": is_attacking = false