replace with multiplayer-coop files
This commit is contained in:
232
src/scripts/enemy_slime.gd
Normal file
232
src/scripts/enemy_slime.gd
Normal file
@@ -0,0 +1,232 @@
|
||||
extends "res://scripts/enemy_base.gd"
|
||||
|
||||
# Slime Enemy - Bounces around, can do minor jumps
|
||||
|
||||
enum SlimeState { IDLE, MOVING, JUMPING, DAMAGED, DYING }
|
||||
var state: SlimeState = SlimeState.IDLE
|
||||
var state_timer: float = 0.0
|
||||
|
||||
var idle_duration: float = 1.0
|
||||
var move_duration: float = 2.0
|
||||
var jump_chance: float = 0.3 # 30% chance to jump instead of walk
|
||||
var detection_range: float = 70.0 # Range to detect players (much smaller)
|
||||
|
||||
# Jump mechanics
|
||||
var is_jumping: bool = false
|
||||
var jump_anim_frames = [2, 3, 4, 5, 7, 2] # Jump animation sequence
|
||||
var jump_anim_index: int = 0
|
||||
|
||||
# Animation frames
|
||||
const FRAME_IDLE = 0
|
||||
const FRAMES_MOVE = [0, 1, 2] # Slow move
|
||||
const FRAMES_DAMAGE = [8, 9]
|
||||
const FRAMES_DEATH = [8, 9, 10, 11, 12, 13, 14]
|
||||
|
||||
func _ready():
|
||||
super._ready()
|
||||
|
||||
max_health = 20.0
|
||||
current_health = max_health
|
||||
move_speed = 35.0 # Slow normally (reduced from 60)
|
||||
damage = 6.0
|
||||
|
||||
state_timer = idle_duration
|
||||
|
||||
# Slime is small - adjust collision
|
||||
if collision_shape and collision_shape.shape:
|
||||
collision_shape.shape.radius = 6.0 # 12x12 effective size
|
||||
|
||||
func _physics_process(delta):
|
||||
# Always update animation (even when dead, and on clients)
|
||||
_update_animation(delta)
|
||||
|
||||
# Call parent physics process (handles dead state, authority checks, etc.)
|
||||
super._physics_process(delta)
|
||||
|
||||
func _ai_behavior(delta):
|
||||
# Update state timer
|
||||
state_timer -= delta
|
||||
|
||||
# Find nearest player within detection range
|
||||
target_player = _find_nearest_player_in_range(detection_range)
|
||||
|
||||
# State machine
|
||||
match state:
|
||||
SlimeState.IDLE:
|
||||
_idle_behavior(delta)
|
||||
SlimeState.MOVING:
|
||||
_moving_behavior(delta)
|
||||
SlimeState.JUMPING:
|
||||
_jumping_behavior(delta)
|
||||
SlimeState.DAMAGED:
|
||||
_damaged_behavior(delta)
|
||||
SlimeState.DYING:
|
||||
return # Do nothing while dying
|
||||
|
||||
# Animation is updated in _physics_process (always, even on clients)
|
||||
|
||||
func _idle_behavior(_delta):
|
||||
velocity = Vector2.ZERO
|
||||
anim_frame = FRAME_IDLE
|
||||
|
||||
# Check if player is nearby
|
||||
if target_player:
|
||||
var dist = global_position.distance_to(target_player.global_position)
|
||||
if dist < detection_range:
|
||||
# Start moving or jumping
|
||||
if randf() < jump_chance:
|
||||
_start_jump()
|
||||
else:
|
||||
state = SlimeState.MOVING
|
||||
state_timer = move_duration
|
||||
return
|
||||
|
||||
# Switch to moving/jumping after idle duration
|
||||
if state_timer <= 0:
|
||||
if randf() < jump_chance:
|
||||
_start_jump()
|
||||
else:
|
||||
state = SlimeState.MOVING
|
||||
state_timer = move_duration
|
||||
|
||||
func _moving_behavior(_delta):
|
||||
# Move slowly towards player
|
||||
if target_player and is_instance_valid(target_player):
|
||||
var direction = (target_player.global_position - global_position).normalized()
|
||||
velocity = direction * move_speed
|
||||
else:
|
||||
# Wander randomly
|
||||
if randf() < 0.02:
|
||||
var random_dir = Vector2(randf() - 0.5, randf() - 0.5).normalized()
|
||||
velocity = random_dir * move_speed
|
||||
|
||||
# Randomly jump while moving
|
||||
if state_timer > 0.5 and randf() < 0.01:
|
||||
_start_jump()
|
||||
return
|
||||
|
||||
# Switch back to idle after move duration
|
||||
if state_timer <= 0:
|
||||
state = SlimeState.IDLE
|
||||
state_timer = idle_duration
|
||||
|
||||
func _start_jump():
|
||||
state = SlimeState.JUMPING
|
||||
is_jumping = true
|
||||
jump_anim_index = 0
|
||||
state_timer = 0.6 # Jump duration
|
||||
anim_time = 0.0
|
||||
|
||||
# Jump towards player if nearby
|
||||
if target_player and is_instance_valid(target_player):
|
||||
var direction = (target_player.global_position - global_position).normalized()
|
||||
velocity = direction * (move_speed * 1.8) # Faster during jump
|
||||
else:
|
||||
# Random jump direction
|
||||
var random_dir = Vector2(randf() - 0.5, randf() - 0.5).normalized()
|
||||
velocity = random_dir * (move_speed * 1.8)
|
||||
|
||||
func _jumping_behavior(_delta):
|
||||
# Continue moving in jump direction
|
||||
# Animation is handled in _update_animation
|
||||
|
||||
# End jump
|
||||
if state_timer <= 0:
|
||||
is_jumping = false
|
||||
state = SlimeState.MOVING
|
||||
state_timer = move_duration
|
||||
|
||||
func _damaged_behavior(_delta):
|
||||
velocity = Vector2.ZERO
|
||||
|
||||
# Stay in damaged state briefly
|
||||
if state_timer <= 0:
|
||||
state = SlimeState.IDLE
|
||||
state_timer = idle_duration
|
||||
|
||||
func _update_animation(delta):
|
||||
if state == SlimeState.DYING or state == SlimeState.DAMAGED:
|
||||
return # Animation handled elsewhere
|
||||
|
||||
if state == SlimeState.IDLE:
|
||||
anim_frame = FRAME_IDLE
|
||||
elif state == SlimeState.JUMPING:
|
||||
# Animate jump sequence
|
||||
anim_time += delta
|
||||
if anim_time >= 0.1: # Fast jump animation
|
||||
anim_time = 0.0
|
||||
jump_anim_index += 1
|
||||
if jump_anim_index < jump_anim_frames.size():
|
||||
anim_frame = jump_anim_frames[jump_anim_index]
|
||||
elif state == SlimeState.MOVING:
|
||||
# Animate slow move (frames 0, 1, 2)
|
||||
anim_time += delta
|
||||
if anim_time >= anim_speed:
|
||||
anim_time = 0.0
|
||||
var move_index = FRAMES_MOVE.find(anim_frame)
|
||||
if move_index == -1:
|
||||
move_index = 0
|
||||
else:
|
||||
move_index = (move_index + 1) % FRAMES_MOVE.size()
|
||||
anim_frame = FRAMES_MOVE[move_index]
|
||||
|
||||
# Set sprite frame (slime looks same in all directions)
|
||||
if sprite:
|
||||
sprite.frame = anim_frame
|
||||
|
||||
func _on_take_damage():
|
||||
# Play damage animation
|
||||
state = SlimeState.DAMAGED
|
||||
state_timer = 0.3
|
||||
anim_time = 0.0
|
||||
|
||||
# Animate damage frames
|
||||
_play_damage_anim()
|
||||
|
||||
func _play_damage_anim():
|
||||
for frame in FRAMES_DAMAGE:
|
||||
anim_frame = frame
|
||||
if sprite:
|
||||
sprite.frame = frame
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
|
||||
func _die():
|
||||
if is_dead:
|
||||
return
|
||||
|
||||
# Remove collision layer so they don't collide with players, but still collide with walls
|
||||
set_collision_layer_value(2, false) # Remove from enemy collision layer (layer 2)
|
||||
|
||||
# Set state before calling parent _die()
|
||||
state = SlimeState.DYING
|
||||
velocity = Vector2.ZERO
|
||||
|
||||
# Call parent _die() which handles death sync and _play_death_animation()
|
||||
super._die()
|
||||
|
||||
func _update_client_visuals():
|
||||
# Update visuals on clients based on synced state
|
||||
super._update_client_visuals()
|
||||
|
||||
# Update animation based on synced state
|
||||
_update_animation(0.0) # Update animation immediately when state changes
|
||||
|
||||
# Update sprite frame (slime looks same in all directions, no direction mapping)
|
||||
if sprite:
|
||||
sprite.frame = anim_frame
|
||||
|
||||
func _play_death_animation():
|
||||
# Play death animation sequence
|
||||
for frame in FRAMES_DEATH:
|
||||
anim_frame = frame
|
||||
if sprite:
|
||||
sprite.frame = frame
|
||||
await get_tree().create_timer(0.15).timeout
|
||||
|
||||
# Fade out
|
||||
if sprite:
|
||||
var fade_tween = create_tween()
|
||||
fade_tween.tween_property(sprite, "modulate:a", 0.0, 0.3)
|
||||
await fade_tween.finished
|
||||
|
||||
queue_free()
|
||||
Reference in New Issue
Block a user