Invalid get index 'global_position' (on base: 'null instance').

extends Sprite2D
class_name Player25D
enum State { IDLE, RUN, JUMP, ATTACK }
var state = State.IDLE
var velocity: Vector2 = Vector2.ZERO  # Declare velocity at the start of the class
var bullets_amount: int = 30
var attack_animation: String = "Attack1"
var player_base = PlayerBase.new()# Use PlayerBase’s set_health method¨

@export var movement_data : MovementData
@export var stats : Stats

# References
@onready var animator : AnimatedSprite2D = $AnimatedSprite2D
@onready var guns_animator : AnimationPlayer = $ShootingAnimationPlayer
@onready var hit_animator : AnimationPlayer = $HitAnimationPlayer
@onready var hand : Node2D = $Hand
@onready var pistol : Sprite2D = $Hand/Pivot/Pistol
@onready var pistol_bullet_marker : Marker2D = $Hand/Pivot/Pistol/PistolBulletMarker
@onready var attacking: bool = false
@export var camera: Camera2D

# Load Scenes
@onready var muzzle_load: PackedScene = preload("res://Scenes/Particles/muzzle.tscn")
@onready var bullet_load: PackedScene = preload("res://Scenes/Props/bullet.tscn")
@onready var death_particle_load: PackedScene = preload("res://Scenes/Particles/player_death_particle.tscn")

func _ready():
	stats.health = player_base.health
	player_base.set_health(stats.health)
	EventManager.bullets_amount = bullets_amount
	EventManager.update_bullet_ui.emit()
	

func _physics_process(delta):
	var input_vector = Input.get_axis("move_left", "move_right")
	process_movement_input(delta)
	process_actions()
	update_animation_state()  # This function was incorrectly named in the previous version.
func apply_acceleration(input_vector, delta):
	velocity.x = move_toward(velocity.x, movement_data.max_speed * input_vector, movement_data.acceleration * delta)

func apply_friction(delta):
	velocity.x = move_toward(velocity.x, 0, movement_data.friction * delta)

func process_movement_input(delta):
	var input_vector = Input.get_axis("move_left", "move_right")
	if input_vector != 0:
		velocity.x = move_toward(velocity.x, movement_data.max_speed * input_vector, movement_data.acceleration * delta)
	else:
		velocity.x = move_toward(velocity.x, 0, movement_data.friction * delta)

func process_actions():
	if Input.is_action_just_pressed("jump"):
		perform_jump()
	if Input.is_action_just_pressed("shoot"):
		perform_attack()

func animate(input_vector):
	var mouse_position : Vector2 = (get_global_mouse_position() - global_position).normalized()
	if mouse_position.x > 0 and animator.flip_h:
		animator.flip_h = false
	elif mouse_position.x < 0 and not animator.flip_h:
		animator.flip_h = true
	
	hand.rotation = mouse_position.angle()
	if hand.scale.y == 1 and mouse_position.x < 0:
		hand.scale.y = -1
	elif hand.scale.y == -1 and mouse_position.x > 0:
		hand.scale.y = 1
	
	if state != State.ATTACK:
		if input_vector != 0:
			animator.play("Run")
		else:
			animator.play("Idle")



func perform_jump():
	velocity.y = -movement_data.jump_strength
	AudioManager.play_sound(AudioManager.JUMP)

func perform_attack():
	if not bullets_amount: return
	state = State.ATTACK
	animator.play("Attacking")
	#guns_animator.play("Shoot")
	shoot()

func shoot():
	state = State.ATTACK
	attack_animation = "Attack" + str(randi_range(1, 2))
	animator.play(attack_animation)
	#$Hand/AttackArea/CollisionShape2D.disabled = false;
	await animator.animation_looped
	EventManager.update_bullet_ui.emit()
	var mouse_position : Vector2 = (get_global_mouse_position() - global_position).normalized()
	var muzzle = muzzle_load.instantiate()
	var bullet = bullet_load.instantiate()
	#pistol_bullet_marker.add_child(muzzle)
	bullet.global_position = pistol_bullet_marker.global_position
	bullet.target_vector = mouse_position
	bullet.rotation = mouse_position.angle()
	get_tree().current_scene.add_child(bullet)
	AudioManager.play_sound(AudioManager.SHOOT)

	#$Hand/AttackArea/CollisionShape2D.disabled = true;
	
	state = State.IDLE

func update_animation_state():
	if state == State.ATTACK:
		return
	
	if velocity.x != 0:
		animator.play("Run")
	else:
		animator.play("Idle")

func _on_hurtbox_area_entered(_area):
	if not _area.is_in_group("Bullet"):
		hit_animator.play("Hit")
		take_damage(1)  # If damage is to be variable, extract value from _area
		EventManager.frame_freeze.emit()

func die():
	AudioManager.play_sound(AudioManager.DEATH)
	animator.play("Died")
	spawn_death_particle()
	EventManager.player_died.emit()
	queue_free()

func spawn_death_particle():
	var death_particle = death_particle_load.instantiate()
	death_particle.global_position = global_position
	get_tree().current_scene.add_child(death_particle)

# Override PlayerBase method
func take_damage(damage: int) -> void:
	player_base.health -= damage  # Use the health property from PlayerBase
	if player_base.health <= 0:
		die()
	else:
		AudioManager.play_sound(AudioManager.HURT)
func _on_swapPlane():
	PlayerState.set_last_2d_position(global_position); 
	SceneChanger.change_to_2d(global_position) # Calls the singleton to change to 3D scene

# Implement the move method required by PlayerBase, the actual movement
# logic is in the _physics_process function above.
func move(input_dir: Vector2) -> void:
	# For Player2D, the move function is handled by process_movement_input,
	# so no additional logic is needed here.
	pass

# Implement the attack method required by PlayerBase. This is a placeholder
# and the actual logic for starting an attack is in the perform_attack function.
func attack() -> void:
	perform_attack()
	
	# Adjust the jump method to use jump_strength from PlayerBase 
func jump():
	velocity.y = -movement_data.jump_strength
	AudioManager.play_sound(AudioManager.JUMP)

func _on_health_changed(new_health: int) -> void:
	player_base.health = new_health  # Make sure to update it when health changes
	# Handle health change (e.g., update UI)