hitbox changes

main
Twirpytherobot 1 week ago
parent 10cc8720b7
commit 7d18de1621
  1. 6
      level/scenes/Player_Lilguy.tscn
  2. 4
      level/scenes/weapons/world_weapon_sword.tscn
  3. 25
      level/scripts/base_weapon.gd
  4. 42
      level/scripts/hit_box.gd
  5. 59
      level/scripts/hurt_box.gd
  6. 2
      level/scripts/lilguy_body.gd

@ -4,7 +4,7 @@
[ext_resource type="PackedScene" uid="uid://b22ou40sbkavj" path="res://assets/characters/player/LilguyRigged.glb" id="2_lilguy"]
[ext_resource type="Script" uid="uid://cf7jky1bcs560" path="res://level/scripts/lilguy_body.gd" id="3_body"]
[ext_resource type="Script" uid="uid://bj7yrijm7bppq" path="res://level/scripts/spring_arm_offset.gd" id="4_spring"]
[ext_resource type="Script" path="res://level/scripts/hurt_box.gd" id="5_hurtbox"]
[ext_resource type="Script" uid="uid://bj3uepduxvgju" path="res://level/scripts/hurt_box.gd" id="5_hurtbox"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_yxyay"]
radius = 0.35796
@ -110,7 +110,7 @@ bone_idx = 10
transform = Transform3D(-17.74905, -295.46814, -48.82108, 21.019196, -50.01525, 295.05362, -298.73593, 14.035805, 23.660797, 0.005859375, 0.39337158, 0.06616211)
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.066, 0.828, 0.01)
transform = Transform3D(2, 0, 0, 0, 2, 0, 0, 0, 2, -0.066, 1.647685, 0.01)
shape = SubResource("CapsuleShape3D_yxyay")
[node name="HurtBox" type="Area3D" parent="." node_paths=PackedStringArray("owner_entity")]
@ -120,7 +120,7 @@ script = ExtResource("5_hurtbox")
owner_entity = NodePath("..")
[node name="HurtBoxShape" type="CollisionShape3D" parent="HurtBox"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.066, 0.828, 0.01)
transform = Transform3D(1.9228287, 0, 0, 0, 1.4454772, 0, 0, 0, 1.4906956, -0.066, 2.0836046, 0.01)
shape = SubResource("CapsuleShape3D_hurtbox")
[node name="SpringArmOffset" type="Node3D" parent="." node_paths=PackedStringArray("_spring_arm")]

@ -1,6 +1,6 @@
[gd_scene load_steps=4 format=3]
[gd_scene load_steps=4 format=3 uid="uid://byxqw8bg5da2c"]
[ext_resource type="Script" path="res://level/scripts/world_weapon.gd" id="1"]
[ext_resource type="Script" uid="uid://ccnnd0y4jqiot" path="res://level/scripts/world_weapon.gd" id="1"]
[ext_resource type="Resource" path="res://level/resources/weapon_sword.tres" id="2"]
[sub_resource type="BoxShape3D" id="1"]

@ -90,6 +90,12 @@ func _on_hitbox_hit(target: Node, damage_amount: float, knockback_amount: float,
if not target or not owner_character:
return
# Flash the target's hurtbox red for visual feedback
if target is Node:
var hurtbox = target.find_child("HurtBox", true, false)
if hurtbox and hurtbox.has_method("flash_hit"):
hurtbox.flash_hit()
hit_connected.emit(target)
# Route damage through server
@ -145,7 +151,7 @@ func perform_attack() -> bool:
attack_performed.emit()
return true
## Activate the hitbox for attack detection using frame data timing
## Activate the hitbox for attack detection - active for entire animation
func _activate_hitbox():
if not _hitbox:
return
@ -153,21 +159,14 @@ func _activate_hitbox():
# Update owner reference in case it changed
_hitbox.owner_entity = owner_character
# STARTUP PHASE - Wait before activating hitbox (wind-up)
var startup = weapon_data.startup_time if weapon_data else 0.15
if startup > 0:
await get_tree().create_timer(startup).timeout
if not _hitbox or not is_instance_valid(_hitbox):
return
# ACTIVE PHASE - Hitbox is on, can deal damage
# Activate hitbox immediately for entire animation duration
_hitbox.activate()
var active = weapon_data.active_time if weapon_data else 0.2
await get_tree().create_timer(active).timeout
# Keep active for the full attack cooldown
var duration = weapon_data.attack_cooldown if weapon_data else 0.5
await get_tree().create_timer(duration).timeout
# RECOVERY PHASE - Hitbox off (recovery time is remaining cooldown)
# Deactivate when attack is complete
if _hitbox and is_instance_valid(_hitbox):
_hitbox.deactivate()

@ -20,14 +20,50 @@ var is_active: bool = false
var _hits_this_attack: Array[Node] = []
## Shape for queries (extracted from child CollisionShape3D)
var _query_shape: Shape3D = null
## Debug mesh for visualization
var _debug_mesh: MeshInstance3D = null
var _debug_material: StandardMaterial3D = null
func _ready():
# Find the collision shape for queries
for child in get_children():
if child is CollisionShape3D and child.shape:
_query_shape = child.shape
_create_debug_visualization(child)
break
func _create_debug_visualization(collision_shape: CollisionShape3D):
# Create a semi-transparent red mesh to visualize the hitbox
_debug_mesh = MeshInstance3D.new()
_debug_material = StandardMaterial3D.new()
_debug_material.albedo_color = Color(1.0, 0.0, 0.0, 0.4) # Red, semi-transparent
_debug_material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
_debug_material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
_debug_material.cull_mode = BaseMaterial3D.CULL_DISABLED # Visible from both sides
# Create mesh matching the collision shape
var mesh: Mesh = null
if collision_shape.shape is BoxShape3D:
var box_mesh = BoxMesh.new()
box_mesh.size = collision_shape.shape.size
mesh = box_mesh
elif collision_shape.shape is SphereShape3D:
var sphere_mesh = SphereMesh.new()
sphere_mesh.radius = collision_shape.shape.radius
sphere_mesh.height = collision_shape.shape.radius * 2
mesh = sphere_mesh
elif collision_shape.shape is CapsuleShape3D:
var capsule_mesh = CapsuleMesh.new()
capsule_mesh.radius = collision_shape.shape.radius
capsule_mesh.height = collision_shape.shape.height
mesh = capsule_mesh
if mesh:
_debug_mesh.mesh = mesh
_debug_mesh.material_override = _debug_material
# Don't set transform - it inherits from parent CollisionShape3D
collision_shape.add_child(_debug_mesh)
func _physics_process(_delta):
if not is_active:
return
@ -83,11 +119,17 @@ func _process_hit(hurtbox: HurtBox):
func activate():
is_active = true
_hits_this_attack.clear()
# Change to yellow when active
if _debug_material:
_debug_material.albedo_color = Color(1.0, 1.0, 0.0, 0.5) # Yellow, semi-transparent
## Deactivate hitbox (call when attack ends)
func deactivate():
is_active = false
_hits_this_attack.clear()
# Change back to red when inactive
if _debug_material:
_debug_material.albedo_color = Color(1.0, 0.0, 0.0, 0.4) # Red, semi-transparent
## Set damage stats (usually from weapon data)
func set_stats(new_damage: float, new_knockback: float):

@ -7,6 +7,11 @@ class_name HurtBox
## The entity that owns this hurtbox (should be a BaseUnit or similar)
@export var owner_entity: Node = null
## Debug mesh for visualization
var _debug_mesh: MeshInstance3D = null
var _debug_material: StandardMaterial3D = null
var _hit_flash_timer: float = 0.0
const HIT_FLASH_DURATION: float = 0.3 # seconds
func _ready():
# Auto-find owner if not set (traverse up to find BaseUnit)
@ -25,3 +30,57 @@ func _ready():
# Ensure we can be detected but don't detect others
monitorable = true
monitoring = false
# Add debug visualization
_create_debug_visualization()
func _process(delta):
# Handle hit flash timer
if _hit_flash_timer > 0.0:
_hit_flash_timer -= delta
if _hit_flash_timer <= 0.0:
# Flash finished, return to green
if _debug_material:
_debug_material.albedo_color = Color(0.0, 1.0, 0.0, 0.3) # Green
func _create_debug_visualization():
# Find the collision shape to visualize
for child in get_children():
if child is CollisionShape3D and child.shape:
# Create a semi-transparent green mesh to visualize the hurtbox
_debug_mesh = MeshInstance3D.new()
_debug_material = StandardMaterial3D.new()
_debug_material.albedo_color = Color(0.0, 1.0, 0.0, 0.3) # Green, semi-transparent
_debug_material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
_debug_material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
_debug_material.cull_mode = BaseMaterial3D.CULL_DISABLED # Visible from both sides
# Create mesh matching the collision shape
var mesh: Mesh = null
if child.shape is BoxShape3D:
var box_mesh = BoxMesh.new()
box_mesh.size = child.shape.size
mesh = box_mesh
elif child.shape is SphereShape3D:
var sphere_mesh = SphereMesh.new()
sphere_mesh.radius = child.shape.radius
sphere_mesh.height = child.shape.radius * 2
mesh = sphere_mesh
elif child.shape is CapsuleShape3D:
var capsule_mesh = CapsuleMesh.new()
capsule_mesh.radius = child.shape.radius
capsule_mesh.height = child.shape.height
mesh = capsule_mesh
if mesh:
_debug_mesh.mesh = mesh
_debug_mesh.material_override = _debug_material
# Don't set transform - it inherits from parent CollisionShape3D
child.add_child(_debug_mesh)
break
## Call this when the hurtbox is hit to flash red
func flash_hit():
_hit_flash_timer = HIT_FLASH_DURATION
if _debug_material:
_debug_material.albedo_color = Color(1.0, 0.0, 0.0, 0.5) # Red, semi-transparent

@ -62,6 +62,6 @@ func play_attack(anim_name: String = "Attack_OneHand") -> void:
animation_player.animation_set_next(anim_name, "")
else:
# Fallback to default if animation doesn't exist
push_warning("Animation '%s' not found, using Attack_OneHand" % anim_name)
#push_warning("Animation '%s' not found, using Attack_OneHand" % anim_name)
animation_player.play("Attack_OneHand", -1, 1.0)
animation_player.animation_set_next("Attack_OneHand", "")

Loading…
Cancel
Save