combine this script # Add these variables to your player script
var health_ui: Control
var is_invincible = false

# Add to _ready():
func _ready():
	add_to_group("player")
	collision_layer = 1
	collision_mask = 1 | 2
	
	if spin_hitbox:
		spin_hitbox.body_entered.connect(_on_spin_hitbox_body_entered)
		spin_hitbox.area_entered.connect(_on_spin_hitbox_area_entered)
		spin_hitbox.monitoring = false
	
	# Find health UI
	health_ui = get_tree().get_first_node_in_group("health_ui")

# Add this method to handle taking damage
func take_damage(damage_amount: int = 1, damage_source_position: Vector2 = Vector2.ZERO):
	if health_ui and not is_invincible:
		health_ui.take_damage()
		is_invincible = true
		
		# Apply knockback
		if damage_source_position != Vector2.ZERO:
			var knockback_direction = (global_position - damage_source_position).normalized()
			velocity = knockback_direction * 300 + Vector2(0, -200)

# Add this to check invincibility
func can_take_damage() -> bool:
	return not is_invincible and (not health_ui or not health_ui.is_invincible)

# Update the invincibility status
func _physics_process(delta):
	# Sync invincibility with health UI
	if health_ui:
		is_invincible = health_ui.is_invincible
	
	# ... rest of your physics process code


and this script 

extends CharacterBody2D

# Movement
const SPEED = 300.0
const JUMP_VELOCITY = -400.0
const ACCELERATION = 1500.0
const FRICTION = 1200.0
const AIR_ACCELERATION = 800.0
const AIR_FRICTION = 400.0

# Jump mechanics
const COYOTE_TIME = 0.1
const JUMP_BUFFER_TIME = 0.1

# Wall bounce
const WALL_BOUNCE_VELOCITY = Vector2(250, -350)  # X and Y velocity
const WALL_SLIDE_SPEED = 50.0
const WALL_BOUNCE_COOLDOWN = 0.2

# Flutter jump
const MAX_FLUTTER_TIME = 0.6
const FLUTTER_GRAVITY_SCALE = 0.2

# Ground pound
const GROUND_POUND_VELOCITY = 1200.0
const GROUND_POUND_COOLDOWN = 0.3
const GROUND_POUND_RAY_DISTANCE = 64.0

# Spin
const SPIN_DURATION = 0.5
const SPIN_COOLDOWN = 0.2
const SPIN_SPEED_BOOST = 1.2
const SPIN_DAMAGE = 1
const SPIN_KNOCKBACK_FORCE = 300.0

# Super jump
const SUPER_JUMP_VELOCITY = -600.0  # Higher than normal jump
const SUPER_JUMP_WINDOW = 0.3  # Time window after ground pound to perform super jump

# State
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
var facing_direction = 1

var coyote_timer = 0.0
var jump_buffer_timer = 0.0
var jump_count = 0
const MAX_JUMPS = 2
var was_on_floor = false

# Wall bounce
var wall_bounce_cooldown_timer = 0.0
var last_wall_normal = 0
var is_wall_bouncing = false

# Flutter
var is_fluttering = false
var flutter_time = 0.0
var flutter_used = false

# Ground pound
var is_ground_pounding = false
var ground_pound_cooldown_timer = 0.0

# Spin
var is_spinning = false
var spin_timer = 0.0
var spin_cooldown_timer = 0.0
var spin_hit_targets = []

# Super jump
var super_jump_timer = 0.0
var can_super_jump = false

# Nodes
@onready var animated_sprite = $AnimatedSprite2D
@onready var animation_player = $AnimationPlayer
@onready var spin_hitbox = $SpinHitbox

# Animation states
enum AnimationState { IDLE, RUN, JUMP, FALL, FLUTTER, GROUND_POUND, SPIN, WALL_SLIDE }
var current_animation_state = AnimationState.IDLE

func _ready():
	add_to_group("player")
	collision_layer = 1
	collision_mask = 1 | 2
	
	if spin_hitbox:
		spin_hitbox.body_entered.connect(_on_spin_hitbox_body_entered)
		spin_hitbox.area_entered.connect(_on_spin_hitbox_area_entered)
		spin_hitbox.monitoring = false

func _physics_process(delta):
	handle_gravity(delta)
	handle_jump_input(delta)
	handle_wall_bounce(delta)
	handle_spin(delta)
	handle_horizontal_movement(delta)
	handle_ground_pound(delta)
	move_and_slide()
	update_animations()
	update_state_tracking()

func handle_gravity(delta):
	if not is_on_floor():
		if is_ground_pounding:
			velocity.y = GROUND_POUND_VELOCITY
		elif is_on_wall() and velocity.y > 0 and not is_wall_bouncing:
			# Wall slide
			velocity.y = min(velocity.y, WALL_SLIDE_SPEED)
		elif is_fluttering:
			velocity.y += gravity * FLUTTER_GRAVITY_SCALE * delta
			flutter_time += delta
			if flutter_time >= MAX_FLUTTER_TIME or not Input.is_action_pressed("jump"):
				is_fluttering = false
		else:
			velocity.y += gravity * delta
	else:
		if not was_on_floor:
			trigger_landing_effects()
		
		jump_count = 0
		is_fluttering = false
		flutter_used = false
		is_wall_bouncing = false
		
		if is_ground_pounding:
			is_ground_pounding = false
			ground_pound_cooldown_timer = GROUND_POUND_COOLDOWN
			can_super_jump = true
			super_jump_timer = SUPER_JUMP_WINDOW
			trigger_ground_pound_effects()

func handle_jump_input(delta):
	update_jump_timers(delta)
	handle_super_jump_timer(delta)

	if Input.is_action_just_pressed("ui_accept") or Input.is_action_just_pressed("jump"):
		jump_buffer_timer = JUMP_BUFFER_TIME

	var can_jump = false
	var can_wall_bounce = false

	# Check for wall bounce opportunity
	if is_on_wall() and not is_on_floor() and wall_bounce_cooldown_timer <= 0:
		var wall_normal = get_wall_normal()
		var input_direction = Input.get_axis("ui_left", "ui_right")
		
		# Can wall bounce if pressing away from wall
		if (wall_normal.x > 0 and input_direction < 0) or (wall_normal.x < 0 and input_direction > 0):
			can_wall_bounce = true

	# Normal jump conditions
	if (is_on_floor() or coyote_timer > 0) and jump_buffer_timer > 0 and not is_ground_pounding:
		can_jump = true
		jump_count = 0
	elif jump_count < MAX_JUMPS - 1 and jump_buffer_timer > 0 and not is_on_floor() and not is_ground_pounding:
		can_jump = true

	# SUPER JUMP
	if can_super_jump and jump_buffer_timer > 0:
		velocity.y = SUPER_JUMP_VELOCITY
		can_super_jump = false
		super_jump_timer = 0.0
		jump_buffer_timer = 0.0
		return

	# Wall bounce or normal jump
	if can_wall_bounce and jump_buffer_timer > 0:
		perform_wall_bounce()
		jump_buffer_timer = 0.0
	elif can_jump:
		velocity.y = JUMP_VELOCITY
		jump_buffer_timer = 0.0
		coyote_timer = 0.0
		jump_count += 1

	# Flutter
	if not is_on_floor() and not is_fluttering and not flutter_used and not is_ground_pounding:
		if Input.is_action_pressed("jump") and velocity.y > 0:
			is_fluttering = true
			flutter_time = 0.0
			flutter_used = true

func handle_super_jump_timer(delta):
	if super_jump_timer > 0:
		super_jump_timer -= delta
		if super_jump_timer <= 0:
			can_super_jump = false

func handle_wall_bounce(delta):
	if wall_bounce_cooldown_timer > 0:
		wall_bounce_cooldown_timer -= delta
	
	if is_on_wall():
		last_wall_normal = get_wall_normal().x

func perform_wall_bounce():
	var wall_normal = get_wall_normal()
	
	velocity.x = WALL_BOUNCE_VELOCITY.x * wall_normal.x
	velocity.y = WALL_BOUNCE_VELOCITY.y
	
	is_wall_bouncing = true
	wall_bounce_cooldown_timer = WALL_BOUNCE_COOLDOWN
	jump_count = 1
	is_fluttering = false
	flutter_used = false
	
	facing_direction = sign(velocity.x)
	
	if animated_sprite:
		animated_sprite.play("wall_bounce")

func handle_spin(delta):
	if spin_cooldown_timer > 0:
		spin_cooldown_timer -= delta
	
	if is_spinning:
		spin_timer -= delta
		if spin_timer <= 0:
			end_spin()
	
	if Input.is_action_just_pressed("spin") and not is_spinning and spin_cooldown_timer <= 0 and not is_ground_pounding:
		start_spin()

func start_spin():
	is_spinning = true
	spin_timer = SPIN_DURATION
	spin_hit_targets.clear()
	
	if spin_hitbox:
		spin_hitbox.monitoring = true
	
	if not is_on_floor():
		velocity.y = min(velocity.y, -100)

func end_spin():
	is_spinning = false
	spin_cooldown_timer = SPIN_COOLDOWN
	
	if spin_hitbox:
		spin_hitbox.monitoring = false

func handle_horizontal_movement(delta):
	if is_ground_pounding:
		velocity.x = move_toward(velocity.x, 0, FRICTION * delta)
		return
	
	if is_wall_bouncing and abs(velocity.x) > SPEED * 0.5:
		return

	var direction = Input.get_axis("ui_left", "ui_right")
	if direction != 0:
		facing_direction = direction

	var accel = ACCELERATION if is_on_floor() else AIR_ACCELERATION
	var friction = FRICTION if is_on_floor() else AIR_FRICTION
	
	var target_speed = SPEED
	if is_spinning:
		target_speed *= SPIN_SPEED_BOOST

	if direction != 0:
		velocity.x = move_toward(velocity.x, direction * target_speed, accel * delta)
	else:
		velocity.x = move_toward(velocity.x, 0, friction * delta)

func update_jump_timers(delta):
	if is_on_floor():
		coyote_timer = COYOTE_TIME
	else:
		coyote_timer -= delta

	if jump_buffer_timer > 0:
		jump_buffer_timer -= delta

func handle_ground_pound(delta):
	if ground_pound_cooldown_timer > 0:
		ground_pound_cooldown_timer -= delta

	if not is_on_floor() and not is_ground_pounding and ground_pound_cooldown_timer <= 0:
		if Input.is_action_just_pressed("ground_pound"):
			is_ground_pounding = true
			is_fluttering = false
			flutter_used = true
			is_spinning = false
			is_wall_bouncing = false
			end_spin()
			velocity.y = GROUND_POUND_VELOCITY
			can_super_jump = true
			super_jump_timer = SUPER_JUMP_WINDOW

func update_state_tracking():
	was_on_floor = is_on_floor()
	if is_on_floor():
		is_wall_bouncing = false

func update_animations():
	if not animated_sprite:
		return

	var new_state = get_animation_state()
	if new_state != current_animation_state:
		current_animation_state = new_state
		play_animation_for_state(new_state)

	if not is_spinning:
		animated_sprite.flip_h = facing_direction < 0

func get_animation_state() -> AnimationState:
	if is_spinning:
		return AnimationState.SPIN
	if is_ground_pounding:
		return AnimationState.GROUND_POUND
	if is_on_wall() and not is_on_floor() and velocity.y > 0:
		return AnimationState.WALL_SLIDE
	if not is_on_floor():
		if is_fluttering:
			return AnimationState.FLUTTER
		elif velocity.y < -50:
			return AnimationState.JUMP
		elif velocity.y > 50:
			return AnimationState.FALL
	if abs(velocity.x) > 50:
		return AnimationState.RUN
	return AnimationState.IDLE

func play_animation_for_state(state: AnimationState):
	match state:
		AnimationState.IDLE:
			animated_sprite.play("idle")
		AnimationState.RUN:
			animated_sprite.play("run")
		AnimationState.JUMP:
			animated_sprite.play("jump")
		AnimationState.FALL:
			animated_sprite.play("fall")
		AnimationState.FLUTTER:
			animated_sprite.play("flutter")
		AnimationState.GROUND_POUND:
			animated_sprite.play("ground_pound")
		AnimationState.SPIN:
			animated_sprite.play("spin")
		AnimationState.WALL_SLIDE:
			if animated_sprite.sprite_frames.has_animation("wall_slide"):
				animated_sprite.play("wall_slide")
			else:
				animated_sprite.play("fall")

func _input(event):
	if event.is_action_released("ui_accept") or event.is_action_released("jump"):
		if velocity.y < 0:
			velocity.y *= 0.5

func _on_spin_hitbox_body_entered(body):
	if not is_spinning or body == self:
		return
	
	if body in spin_hit_targets:
		return
	
	spin_hit_targets.append(body)
	
	if body.has_method("take_damage"):
		body.take_damage(SPIN_DAMAGE, global_position)
	
	if body.has_method("break_part"):
		body.break_part()
	
	if body is CharacterBody2D or body is RigidBody2D:
		var knockback_dir = (body.global_position - global_position).normalized()
		if body.has_method("apply_knockback"):
			body.apply_knockback(knockback_dir * SPIN_KNOCKBACK_FORCE)
		elif body is RigidBody2D:
			body.apply_impulse(knockback_dir * SPIN_KNOCKBACK_FORCE)

func _on_spin_hitbox_area_entered(area):
	if not is_spinning:
		return
	
	if area.has_method("on_spin_hit"):
		area.on_spin_hit()

func trigger_landing_effects():
	var camera = get_viewport().get_camera_2d()
	if camera and camera.has_method("_on_player_landed"):
		camera._on_player_landed()

func trigger_ground_pound_effects():
	var camera = get_viewport().get_camera_2d()
	if camera and camera.has_method("_on_player_ground_pounded"):
		camera._on_player_ground_pounded()

	break_blocks_below()

func break_blocks_below():
	var space_state = get_world_2d().direct_space_state
	var from_pos = global_position
	var to_pos = global_position + Vector2(0, GROUND_POUND_RAY_DISTANCE)
	
	var ray_params = PhysicsRayQueryParameters2D.create(from_pos, to_pos)
	ray_params.exclude = [self]
	ray_params.collision_mask = 2
	
	var result = space_state.intersect_ray(ray_params)
	
	if result:
		var collider = result.collider
		if collider.has_method("break_part"):
			collider.break_part()

func is_player_ground_pounding() -> bool:
	return is_ground_pounding

func is_player_spinning() -> bool:
	return is_spinning


	if animated_sprite:
		var tween = create_tween().set_loops(1)
		tween.tween_property(animated_sprite, "scale", Vector2(1.2, 1.2), 0.1)
		tween.tween_property(animated_sprite, "scale", Vector2(1.0, 1.0), 0.1)