fix spider bat boss alittle

This commit is contained in:
2026-02-06 02:49:58 +01:00
parent 9b8d84357f
commit fa7e969363
86 changed files with 4319 additions and 763 deletions

View File

@@ -0,0 +1,172 @@
extends Area2D
# Web shot from boss: frame 568 in shade_spell_effects (105h x 79v). 8x8 collision.
# Flies to target; on hit player or arrival: animate 568->573.
# If arrived at point: stay 30s, fade out at end (net doesn't stick during fade).
# If hit player: player stuck 5s (frame 679 netted), fade last 0.3s; other player can cut net.
# Netted player cannot attack with main weapon.
var target_position: Vector2 = Vector2.ZERO
var speed: float = 140.0
var state: String = "flying" # flying | impact_anim | landed_net | hit_player
var impact_frame: int = 568
var impact_frame_end: int = 573
var landed_lifetime: float = 30.0
var landed_timer: float = 0.0
var fade_start: float = 4.0 # Start fade this many seconds before end
var fired_by_boss: Node = null
var hit_player: Node = null # When state == hit_player, the netted player
var netted_duration: float = 5.0
var netted_timer: float = 0.0
var netted_fade_start: float = 0.3
const TILE_SIZE: int = 16
const HFRAMES: int = 105
const VFRAMES: int = 79
@onready var sprite: Sprite2D = $Sprite2D
@onready var sfx_webbed: AudioStreamPlayer2D = $SfxWebbed
@onready var anim_timer: float = 0.0
var anim_frame: int = 568
func _ready() -> void:
# Collision: detect players (layer 1)
collision_layer = 0
collision_mask = 1
body_entered.connect(_on_body_entered)
anim_frame = impact_frame
if sprite:
sprite.hframes = HFRAMES
sprite.vframes = VFRAMES
sprite.frame = impact_frame
sprite.centered = true
func set_target(pos: Vector2) -> void:
target_position = pos
func set_fired_by_boss(boss: Node) -> void:
fired_by_boss = boss
func _process(delta: float) -> void:
if state == "flying":
var dir = (target_position - global_position).normalized()
var dist = global_position.distance_to(target_position)
if dist <= speed * delta:
global_position = target_position
_impact_at_point()
else:
global_position += dir * speed * delta
return
if state == "impact_anim":
anim_timer += delta
var frame_count = impact_frame_end - impact_frame + 1
var duration = 0.25
var t = clamp(anim_timer / duration, 0.0, 1.0)
var idx = impact_frame + int(t * (frame_count - 1))
if sprite:
sprite.frame = idx
if anim_timer >= duration:
state = "landed_net"
landed_timer = 0.0
collision_layer = 1 # Can be hit by other players to cut?
collision_mask = 1 # Detect players (for cutting / fade stick logic)
return
if state == "landed_net":
landed_timer += delta
# Fade during last fade_start seconds
if landed_timer >= landed_lifetime - fade_start:
var fade_t = (landed_timer - (landed_lifetime - fade_start)) / fade_start
if sprite:
sprite.modulate.a = 1.0 - fade_t
# During fade, net doesn't stick - no collision with player for stick
if landed_timer >= landed_lifetime:
queue_free()
return
if state == "hit_player":
netted_timer += delta
# Keep net at player position
if hit_player and is_instance_valid(hit_player):
global_position = hit_player.global_position
# Fade last 0.3s
if netted_timer >= netted_duration - netted_fade_start:
var fade_t = (netted_timer - (netted_duration - netted_fade_start)) / netted_fade_start
if sprite:
sprite.modulate.a = 1.0 - fade_t
if netted_timer >= netted_duration:
_release_netted_player()
queue_free()
else:
queue_free()
func _on_body_entered(body: Node2D) -> void:
if state == "flying":
if body.is_in_group("player"):
_impact_on_player(body)
return
# Reached target (or hit wall) - treat as impact at point
if global_position.distance_to(target_position) < 24.0:
_impact_at_point()
return
if state == "landed_net" and body.is_in_group("player"):
_impact_on_player(body)
func _impact_at_point() -> void:
state = "impact_anim"
anim_timer = 0.0
# Stop moving; play 568->573
collision_layer = 0
collision_mask = 0
# After anim, stay 30s then fade (handled in _process)
func _impact_on_player(player: Node2D) -> void:
if not player.is_in_group("player"):
return
# Already netted?
if "netted_by_web" in player and player.netted_by_web != null:
return
state = "hit_player"
hit_player = player
netted_timer = 0.0
if sfx_webbed:
sfx_webbed.play()
# Netted: cannot move? User said "player gets stuck" - so disable movement and main weapon
if player.has_method("_web_net_apply"):
player._web_net_apply(self)
else:
# Fallback: set a flag player script can check
player.set_meta("netted_by_web", self)
# Show net on player (frame 679) - player script will show overlay
if player.has_method("_web_net_show_netted_frame"):
player._web_net_show_netted_frame(true)
# Impact anim 568->573 briefly
anim_timer = 0.0
if sprite:
sprite.frame = impact_frame
# Layer 8 so player attack areas (punch/sword/axe mask 8) can hit and cut the net
collision_layer = 8
collision_mask = 0
func _release_netted_player() -> void:
if hit_player and is_instance_valid(hit_player):
if hit_player.has_method("_web_net_release"):
hit_player._web_net_release(self)
else:
hit_player.remove_meta("netted_by_web")
if hit_player.has_method("_web_net_show_netted_frame"):
hit_player._web_net_show_netted_frame(false)
hit_player = null
# Called when another player attacks this web (to cut the net)
func cut_by_attack(_from_player: Node2D) -> void:
if state == "hit_player":
_release_netted_player()
queue_free()