Colours and practise dummy
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
extends BaseEnemy
|
||||
class_name PracticeDummy
|
||||
|
||||
## A stationary practice dummy for testing combat
|
||||
## Cannot move or attack - just takes damage and shows health
|
||||
|
||||
## Visual mesh reference
|
||||
@onready var _mesh: MeshInstance3D = null
|
||||
## Health label above dummy
|
||||
@onready var _health_label: Label3D = null
|
||||
## Original material for hit flash effect
|
||||
var _original_material: Material = null
|
||||
## Hit flash effect
|
||||
var _hit_flash_timer: float = 0.0
|
||||
const HIT_FLASH_DURATION: float = 0.2
|
||||
|
||||
func _ready():
|
||||
super._ready()
|
||||
|
||||
# Practice dummy should not be aggressive
|
||||
is_aggressive = false
|
||||
|
||||
# Auto-find mesh and health label
|
||||
_mesh = get_node_or_null("Mesh")
|
||||
_health_label = get_node_or_null("HealthLabel")
|
||||
|
||||
# Store original material for flash effect
|
||||
if _mesh:
|
||||
_original_material = _mesh.get_surface_override_material(0)
|
||||
if not _original_material and _mesh.mesh:
|
||||
_original_material = _mesh.mesh.surface_get_material(0)
|
||||
|
||||
# Update initial health display
|
||||
_update_health_display()
|
||||
|
||||
# Connect health change to update display
|
||||
health_changed.connect(_on_health_display_changed)
|
||||
|
||||
func _process(delta):
|
||||
# Handle hit flash timer
|
||||
if _hit_flash_timer > 0:
|
||||
_hit_flash_timer -= delta
|
||||
if _hit_flash_timer <= 0:
|
||||
_reset_material()
|
||||
|
||||
func _physics_process(delta):
|
||||
# Don't call super._physics_process since we don't move
|
||||
# Just apply gravity
|
||||
if not is_on_floor():
|
||||
velocity.y -= ProjectSettings.get_setting("physics/3d/default_gravity") * delta
|
||||
move_and_slide()
|
||||
|
||||
## Update health display
|
||||
func _update_health_display():
|
||||
if _health_label:
|
||||
_health_label.text = "HP: %d/%d" % [int(current_health), int(max_health)]
|
||||
|
||||
func _on_health_display_changed(_old_health: float, _new_health: float):
|
||||
_update_health_display()
|
||||
|
||||
## Override hurt animation to flash red
|
||||
@rpc("any_peer", "call_local", "reliable")
|
||||
func _play_hurt_animation():
|
||||
if _mesh:
|
||||
_flash_red()
|
||||
|
||||
## Flash the dummy red when hit
|
||||
func _flash_red():
|
||||
if not _mesh:
|
||||
return
|
||||
|
||||
_hit_flash_timer = HIT_FLASH_DURATION
|
||||
|
||||
# Create red material
|
||||
var red_material = StandardMaterial3D.new()
|
||||
red_material.albedo_color = Color(1.5, 0.3, 0.3) # Bright red
|
||||
|
||||
# Copy properties from original if it exists
|
||||
if _original_material and _original_material is StandardMaterial3D:
|
||||
var orig = _original_material as StandardMaterial3D
|
||||
red_material.metallic = orig.metallic
|
||||
red_material.roughness = orig.roughness
|
||||
red_material.albedo_texture = orig.albedo_texture
|
||||
|
||||
_mesh.set_surface_override_material(0, red_material)
|
||||
|
||||
## Reset to original material
|
||||
func _reset_material():
|
||||
if _mesh and _original_material:
|
||||
_mesh.set_surface_override_material(0, _original_material.duplicate())
|
||||
|
||||
## Override death to just hide the mesh
|
||||
func _on_enemy_died(killer_id: int):
|
||||
super._on_enemy_died(killer_id)
|
||||
|
||||
# Hide mesh when dead
|
||||
if _mesh:
|
||||
_mesh.visible = false
|
||||
|
||||
print("[PracticeDummy] Killed by player ", killer_id, ". Respawning in ", respawn_delay, " seconds...")
|
||||
|
||||
## Override respawn to show mesh again
|
||||
func _on_enemy_respawned():
|
||||
super._on_enemy_respawned()
|
||||
|
||||
# Show mesh when respawned
|
||||
if _mesh:
|
||||
_mesh.visible = true
|
||||
_reset_material()
|
||||
|
||||
_update_health_display()
|
||||
print("[PracticeDummy] Respawned!")
|
||||
Reference in New Issue
Block a user