added blocking doors to paths.
This commit is contained in:
@@ -44,6 +44,11 @@ func _ready():
|
||||
|
||||
# Top-down physics
|
||||
motion_mode = MOTION_MODE_FLOATING
|
||||
|
||||
# CRITICAL: Set collision mask to include interactable objects (layer 2) and walls (layer 7)
|
||||
# This allows enemies to collide with interactable objects so they can path around them
|
||||
# Walls are on layer 7 (bit 6 = 64), not layer 4!
|
||||
collision_mask = 1 | 2 | 64 # Collide with players (layer 1), objects (layer 2), and walls (layer 7 = bit 6 = 64)
|
||||
|
||||
func _physics_process(delta):
|
||||
if is_dead:
|
||||
@@ -90,6 +95,9 @@ func _physics_process(delta):
|
||||
# Check collisions with players
|
||||
_check_player_collision()
|
||||
|
||||
# Check collisions with interactable objects
|
||||
_check_interactable_object_collision()
|
||||
|
||||
# Sync position and animation to clients (only server sends)
|
||||
if multiplayer.has_multiplayer_peer() and is_multiplayer_authority():
|
||||
# Get state value if enemy has a state variable (for bats/slimes)
|
||||
@@ -125,6 +133,60 @@ func _check_player_collision():
|
||||
if collider and collider.is_in_group("player"):
|
||||
_attack_player(collider)
|
||||
|
||||
func _check_interactable_object_collision():
|
||||
# Check collisions with interactable objects and handle pathfinding around them
|
||||
var blocked_objects = []
|
||||
|
||||
for i in get_slide_collision_count():
|
||||
var collision = get_slide_collision(i)
|
||||
var collider = collision.get_collider()
|
||||
|
||||
if collider and collider.is_in_group("interactable_object"):
|
||||
var obj = collider
|
||||
|
||||
# CRITICAL: Enemies cannot move objects that cannot be lifted
|
||||
# If object is not liftable, enemy should try to path around it
|
||||
if obj.has_method("can_be_lifted") and not obj.can_be_lifted():
|
||||
# Object cannot be lifted - store for pathfinding
|
||||
blocked_objects.append({"object": obj, "collision": collision})
|
||||
# If object is liftable but not currently being held, we can still try to push it
|
||||
# but enemies don't actively push liftable objects (only players do)
|
||||
elif obj.has_method("is_being_held") and obj.is_being_held():
|
||||
# Object is being held by someone - treat as obstacle
|
||||
blocked_objects.append({"object": obj, "collision": collision})
|
||||
|
||||
# Handle pathfinding around blocked objects
|
||||
if blocked_objects.size() > 0 and not is_knocked_back:
|
||||
var collision_normal = blocked_objects[0].collision.get_normal()
|
||||
var _obj_pos = blocked_objects[0].object.global_position
|
||||
|
||||
# Try to path around the object by moving perpendicular to collision normal
|
||||
# This creates a side-stepping behavior to go around obstacles
|
||||
var perpendicular = Vector2(-collision_normal.y, collision_normal.x) # Rotate 90 degrees
|
||||
|
||||
# Choose perpendicular direction that moves toward target (if we have one)
|
||||
if target_player and is_instance_valid(target_player):
|
||||
var to_target = (target_player.global_position - global_position).normalized()
|
||||
# If perpendicular dot product with target direction is negative, flip it
|
||||
if perpendicular.dot(to_target) < 0:
|
||||
perpendicular = -perpendicular
|
||||
|
||||
# Apply perpendicular movement (side-step around object)
|
||||
var side_step_velocity = perpendicular * move_speed * 0.7 # 70% of move speed for side-step
|
||||
velocity = velocity.lerp(side_step_velocity, 0.3) # Smoothly blend with existing velocity
|
||||
|
||||
# Also add some push-away from object to create clearance
|
||||
var push_away = collision_normal * move_speed * 0.3
|
||||
velocity = velocity + push_away
|
||||
|
||||
# Limit total velocity to move_speed
|
||||
if velocity.length() > move_speed:
|
||||
velocity = velocity.normalized() * move_speed
|
||||
|
||||
# For humanoid enemies, sometimes try to destroy the object
|
||||
if has_method("_try_attack_object") and randf() < 0.1: # 10% chance per frame when blocked
|
||||
call("_try_attack_object", blocked_objects[0].object)
|
||||
|
||||
func _attack_player(player):
|
||||
# Attack cooldown
|
||||
if attack_timer > 0:
|
||||
@@ -199,6 +261,11 @@ func take_damage(amount: float, from_position: Vector2):
|
||||
# Flash red (even if dying, show the hit)
|
||||
_flash_damage()
|
||||
|
||||
# Show damage number (red, using dmg_numbers.png font) above enemy
|
||||
# Only show if damage > 0
|
||||
if amount > 0:
|
||||
_show_damage_number(amount, from_position)
|
||||
|
||||
# Sync damage visual to clients
|
||||
# Use game_world to route damage visual sync instead of direct RPC to avoid node path issues
|
||||
if multiplayer.has_multiplayer_peer() and is_inside_tree():
|
||||
@@ -221,6 +288,44 @@ func rpc_take_damage(amount: float, from_position: Vector2):
|
||||
if is_multiplayer_authority():
|
||||
take_damage(amount, from_position)
|
||||
|
||||
func _show_damage_number(amount: float, from_position: Vector2):
|
||||
# Show damage number (red, using dmg_numbers.png font) above enemy
|
||||
# Only show if damage > 0
|
||||
if amount <= 0:
|
||||
return
|
||||
|
||||
var damage_number_scene = preload("res://scenes/damage_number.tscn")
|
||||
if not damage_number_scene:
|
||||
return
|
||||
|
||||
var damage_label = damage_number_scene.instantiate()
|
||||
if not damage_label:
|
||||
return
|
||||
|
||||
# Set damage text and red color
|
||||
damage_label.label = str(int(amount))
|
||||
damage_label.color = Color.RED
|
||||
|
||||
# Calculate direction from attacker (slight upward variation)
|
||||
var direction_from_attacker = (global_position - from_position).normalized()
|
||||
# Add slight upward bias
|
||||
direction_from_attacker = direction_from_attacker.lerp(Vector2(0, -1), 0.5).normalized()
|
||||
damage_label.direction = direction_from_attacker
|
||||
|
||||
# Position above enemy's head
|
||||
var game_world = get_tree().get_first_node_in_group("game_world")
|
||||
if game_world:
|
||||
var entities_node = game_world.get_node_or_null("Entities")
|
||||
if entities_node:
|
||||
entities_node.add_child(damage_label)
|
||||
damage_label.global_position = global_position + Vector2(0, -16) # Above enemy head
|
||||
else:
|
||||
get_tree().current_scene.add_child(damage_label)
|
||||
damage_label.global_position = global_position + Vector2(0, -16)
|
||||
else:
|
||||
get_tree().current_scene.add_child(damage_label)
|
||||
damage_label.global_position = global_position + Vector2(0, -16)
|
||||
|
||||
func _flash_damage():
|
||||
# Flash red visual effect
|
||||
if sprite:
|
||||
|
||||
Reference in New Issue
Block a user