pull/28/head
parent
0a09dc4beb
commit
78a6df0fdf
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
@ -1,8 +1,23 @@
|
||||
class_name HitBox extends Area3D
|
||||
class_name HitBox
|
||||
extends Area3D
|
||||
|
||||
func _init() -> void:
|
||||
collision_layer = 2
|
||||
collision_mask = 2
|
||||
## Konstanten statt magischer Zahlen für bessere Lesbarkeit/Wartbarkeit
|
||||
const COLLISION_LAYER: int = 2
|
||||
const COLLISION_MASK: int = 2
|
||||
const DEFAULT_DAMAGE: int = 0
|
||||
|
||||
func get_damage() -> int:
|
||||
return owner.damage
|
||||
|
||||
func _ready() -> void:
|
||||
# Initialisierung im _ready, wenn der Node sicher im Baum ist
|
||||
collision_layer = COLLISION_LAYER
|
||||
collision_mask = COLLISION_MASK
|
||||
|
||||
|
||||
## Liefert den Schaden des Owners, falls dieser eine entsprechende API anbietet.
|
||||
## Erwartet eine Methode `get_damage()` am Owner. Fällt sonst auf DEFAULT_DAMAGE zurück.
|
||||
func get_owner_damage() -> int:
|
||||
if owner == null:
|
||||
return DEFAULT_DAMAGE
|
||||
if owner.has_method("get_damage"):
|
||||
return int(owner.call("get_damage"))
|
||||
return DEFAULT_DAMAGE
|
||||
|
||||
@ -1,38 +1,37 @@
|
||||
class_name HurtBox extends Area3D
|
||||
class_name HurtBox
|
||||
extends Area3D
|
||||
|
||||
const COLLISION_LAYER: int = 0
|
||||
const COLLISION_MASK: int = 2
|
||||
const DEFAULT_COOLDOWN_S: float = 1.0
|
||||
var can_take_damage: bool = true
|
||||
var cooldown_time: float = 1.0 # Cooldown duration in seconds
|
||||
|
||||
func _init() -> void:
|
||||
collision_layer = 0
|
||||
collision_mask = 2
|
||||
@export var damage_cooldown_s: float = DEFAULT_COOLDOWN_S
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
connect("area_entered", Callable(self, "_on_area_entered"))
|
||||
collision_layer = COLLISION_LAYER
|
||||
collision_mask = COLLISION_MASK
|
||||
area_entered.connect(_on_area_entered)
|
||||
monitoring = true
|
||||
|
||||
|
||||
func _on_area_entered(hitbox) -> void:
|
||||
func _on_area_entered(other_area: Area3D) -> void:
|
||||
if not can_take_damage:
|
||||
return
|
||||
|
||||
if not hitbox is HitBox:
|
||||
print("Unexpected type:", hitbox)
|
||||
if not (other_area is HitBox):
|
||||
push_warning("Unerwarteter Typ: %s" % [other_area])
|
||||
return
|
||||
|
||||
var hitbox := other_area as HitBox
|
||||
if hitbox.owner == owner:
|
||||
print("Hitbox owner is the same as hurtbox owner, ignoring hit.")
|
||||
# Eigenen Treffer ignorieren
|
||||
return
|
||||
if owner != null and owner.has_method("take_damage"):
|
||||
owner.call("take_damage", hitbox.get_owner_damage())
|
||||
start_damage_cooldown()
|
||||
|
||||
if hitbox == null or not hitbox is HitBox:
|
||||
print("Unexpected or null hitbox:", hitbox)
|
||||
return
|
||||
|
||||
if owner.has_method("take_damage"):
|
||||
owner.call("take_damage", hitbox.get_damage())
|
||||
start_cooldown()
|
||||
|
||||
func start_cooldown() -> void:
|
||||
func start_damage_cooldown() -> void:
|
||||
can_take_damage = false
|
||||
await get_tree().create_timer(cooldown_time).timeout
|
||||
await get_tree().create_timer(damage_cooldown_s).timeout
|
||||
can_take_damage = true
|
||||
|
||||
@ -1,12 +1,32 @@
|
||||
class_name InteractionArea extends Area3D
|
||||
class_name InteractionArea
|
||||
extends Area3D
|
||||
|
||||
@export var action_name := "interact"
|
||||
const DEFAULT_ACTION: StringName = &"interact"
|
||||
@export var action_name: StringName = DEFAULT_ACTION
|
||||
|
||||
var interact: Callable = func():
|
||||
# Neuer klarer Name
|
||||
var on_interact: Callable = func() -> void:
|
||||
pass
|
||||
|
||||
# Rückwärtskompatibles Alias für bestehenden Code (z. B. interaction_area.interact = _on_interact)
|
||||
var interact: Callable:
|
||||
set(value):
|
||||
on_interact = value
|
||||
get:
|
||||
return on_interact
|
||||
|
||||
|
||||
func set_interact_callback(callback: Callable) -> void:
|
||||
on_interact = callback
|
||||
|
||||
|
||||
func _on_body_entered(_body: Node3D) -> void:
|
||||
InteractionManager.register_area(self)
|
||||
|
||||
|
||||
func _on_body_exited(_body: Node3D) -> void:
|
||||
InteractionManager.unregister_area(self)
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
InteractionManager.unregister_area(self)
|
||||
|
||||
@ -1,43 +1,67 @@
|
||||
extends Node2D
|
||||
|
||||
const ACTION_INTERACT := "interact"
|
||||
@onready var player: Player = get_tree().get_first_node_in_group("player")
|
||||
@onready var label: Label = $Label
|
||||
|
||||
var base_text: String
|
||||
var active_areas := []
|
||||
var can_interact := true
|
||||
var base_prompt_text: String = ""
|
||||
var areas_in_range: Array[InteractionArea] = []
|
||||
var can_interact: bool = true
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var interact_keys = InputMap.action_get_events("interact")
|
||||
base_text = interact_keys[0].as_text() + " to "
|
||||
print(base_text)
|
||||
base_prompt_text = _build_base_prompt_text()
|
||||
label.hide()
|
||||
|
||||
|
||||
func register_area(area: InteractionArea) -> void:
|
||||
active_areas.push_back(area)
|
||||
|
||||
areas_in_range.push_back(area)
|
||||
|
||||
|
||||
func unregister_area(area: InteractionArea) -> void:
|
||||
var index = active_areas.find(area)
|
||||
var index := areas_in_range.find(area)
|
||||
if index != -1:
|
||||
active_areas.remove_at(index)
|
||||
areas_in_range.remove_at(index)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if active_areas.size() > 0 and can_interact:
|
||||
active_areas.sort_custom(_sort_by_distance_to_player)
|
||||
var active_area = active_areas[0] as InteractionArea
|
||||
label.text = base_text + active_area.action_name
|
||||
if not can_interact:
|
||||
label.hide()
|
||||
return
|
||||
var nearest := _get_nearest_area()
|
||||
if nearest:
|
||||
label.text = "%s%s" % [base_prompt_text, nearest.action_name]
|
||||
label.show()
|
||||
else:
|
||||
label.hide()
|
||||
|
||||
func _sort_by_distance_to_player(area1: Area3D, area2: Area3D) -> bool:
|
||||
var area1_to_player = player.global_position.distance_to(area1.global_position)
|
||||
var area2_to_player = player.global_position.distance_to(area2.global_position)
|
||||
return area1_to_player < area2_to_player
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("interact") and can_interact:
|
||||
if active_areas.size() > 0:
|
||||
can_interact = false
|
||||
label.hide()
|
||||
await active_areas[0].interact.call()
|
||||
can_interact = true
|
||||
if not (can_interact and event.is_action_pressed(ACTION_INTERACT)):
|
||||
return
|
||||
var nearest := _get_nearest_area()
|
||||
if nearest:
|
||||
can_interact = false
|
||||
label.hide()
|
||||
await nearest.interact.call()
|
||||
can_interact = true
|
||||
|
||||
|
||||
func _get_nearest_area() -> InteractionArea:
|
||||
if areas_in_range.is_empty():
|
||||
return null
|
||||
areas_in_range.sort_custom(self._compare_by_distance_to_player)
|
||||
return areas_in_range[0]
|
||||
|
||||
|
||||
func _compare_by_distance_to_player(a: InteractionArea, b: InteractionArea) -> bool:
|
||||
var d1 := player.global_position.distance_to(a.global_position)
|
||||
var d2 := player.global_position.distance_to(b.global_position)
|
||||
return d1 < d2
|
||||
|
||||
|
||||
func _build_base_prompt_text() -> String:
|
||||
var events := InputMap.action_get_events(ACTION_INTERACT)
|
||||
if events.is_empty():
|
||||
return "Interact with "
|
||||
return "%s to " % [events[0].as_text()]
|
||||
|
||||
@ -1,24 +1,59 @@
|
||||
class_name ItemInteractable extends Item
|
||||
class_name ItemInteractable
|
||||
extends Item
|
||||
|
||||
@onready var interaction_area: InteractionArea = $InteractionArea
|
||||
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||
# Einheitliche Standardtexte/-anim-Namen (können in Subklassen überschrieben werden)
|
||||
const ACTION_OPEN: StringName = &"open"
|
||||
const ACTION_CLOSE: StringName = &"close"
|
||||
const ANIM_OPEN: StringName = &"open"
|
||||
const ANIM_CLOSE: StringName = &"close"
|
||||
|
||||
#func _ready() -> void:
|
||||
#state_changed.connect(Callable(self, "_on_state_changed"))
|
||||
#interaction_area.interact = Callable(self, "_on_interact")
|
||||
|
||||
#func _on_interact() -> void:
|
||||
#match state:
|
||||
#States.closed:
|
||||
#state = States.opened
|
||||
#interaction_area.action_name = "open"
|
||||
#States.opened:
|
||||
#state = States.closed
|
||||
#interaction_area.action_name = "close"
|
||||
#
|
||||
#func _on_state_changed(new_state: States) -> void:
|
||||
#match new_state:
|
||||
#States.opened:
|
||||
#animation_player.play("open")
|
||||
#States.closed:
|
||||
#animation_player.play("close")
|
||||
|
||||
func _ready() -> void:
|
||||
# Nur verbinden, wenn noch nicht verbunden (verhindert Doppelverbindungen in Subklassen)
|
||||
if not state_changed.is_connected(_on_state_changed):
|
||||
state_changed.connect(_on_state_changed)
|
||||
# Standardaktion initial setzen
|
||||
_update_action_name_for_state(state)
|
||||
|
||||
|
||||
func _on_interact() -> void:
|
||||
# Standardverhalten: zwischen opened/closed toggeln
|
||||
match state:
|
||||
States.closed:
|
||||
state = States.opened
|
||||
States.opened:
|
||||
state = States.closed
|
||||
_:
|
||||
pass
|
||||
_update_action_name_for_state(state)
|
||||
|
||||
|
||||
func _on_state_changed(new_state: States) -> void:
|
||||
_play_animation_for_state(new_state)
|
||||
_update_action_name_for_state(new_state)
|
||||
|
||||
|
||||
func _play_animation_for_state(new_state: States) -> void:
|
||||
if animation_player == null:
|
||||
return
|
||||
match new_state:
|
||||
States.opened:
|
||||
animation_player.play(ANIM_OPEN)
|
||||
States.closed:
|
||||
animation_player.play(ANIM_CLOSE)
|
||||
_:
|
||||
pass
|
||||
|
||||
|
||||
func _update_action_name_for_state(s: States) -> void:
|
||||
if interaction_area == null:
|
||||
return
|
||||
match s:
|
||||
States.closed:
|
||||
interaction_area.action_name = ACTION_OPEN
|
||||
States.opened:
|
||||
interaction_area.action_name = ACTION_CLOSE
|
||||
_:
|
||||
pass
|
||||
|
||||
Loading…
Reference in New Issue