make so I can change to this player3d cs script when you swap planes:

using Godot;
using System;

public partial class Player : CharacterBody3D
{
	public const uint MaxLifepoints = 200;

	[Export]
	public float Speed { get; private set; } = 5.0f;

	[Export]
	public float JumpVelocity { get; private set; } = 4.5f;

	[Export]
	private uint _lifepoints = MaxLifepoints;

	// Get the gravity from the project settings to be synced with RigidBody nodes.
	public float gravity = ProjectSettings.GetSetting("physics/3d/default_gravity").AsSingle();

	private GameManager _gameManager;
	private Timer _attackTimer;
	private Node3D _visual;
	private ProgressBar _playerLifebar;
	private AnimationTree _animationTree;

	public override void _Ready()
	{
		base._Ready();

		_gameManager = GetNode<GameManager>("/root/GameManager");
		_gameManager.Player = this;
		_playerLifebar = GetTree().CurrentScene.GetNode<ProgressBar>("HUD/PlayerLifeBar");
		_playerLifebar.MaxValue = MaxLifepoints;
		_playerLifebar.Value = _lifepoints;

		_attackTimer = GetNode<Timer>("AttackCooldown");
		_visual = GetNode<Node3D>("Visual");
		_animationTree = GetNode<AnimationTree>("AnimationTree");
	}

	public override void _Process(double delta)
	{
		base._Process(delta);

		_playerLifebar.Value = _lifepoints;
	}

	public override void _PhysicsProcess(double delta)
	{
		Vector3 velocity = Velocity;

		// Add the gravity.
		if (!IsOnFloor())
			velocity.Y -= gravity * (float)delta;

		// Handle Jump.
		//if (Input.IsActionJustPressed("ui_accept") && IsOnFloor())
		//    velocity.Y = JumpVelocity;

		// Get the input direction and handle the movement/deceleration.
		// As good practice, you should replace UI actions with custom gameplay actions.
		Vector2 inputDir = Input.GetVector("left", "right", "up", "down");
		Vector3 direction = (Transform.Basis * new Vector3(inputDir.X, 0, inputDir.Y)).Normalized();
		if (direction != Vector3.Zero)
		{
			velocity.X = direction.X * Speed;
			velocity.Z = direction.Z * Speed;
		}
		else
		{
			velocity.X = Mathf.MoveToward(Velocity.X, 0, Speed);
			velocity.Z = Mathf.MoveToward(Velocity.Z, 0, Speed);
		}

		Velocity = velocity;
		MoveAndSlide();

		velocity.Y = 0;
		_animationTree.Set("parameters/walking/blend_amount", velocity.LimitLength(1).Length());
		if (Mathf.IsZeroApprox(velocity.Length())) return;

		_visual.LookAt(Position + 10 * velocity, Vector3.Up, true);
		//var angle = 0;
		//var transform = _visual.Transform;
		//transform.Basis = new(Vector3.Up, angle);
		//_visual.Transform = transform;
	}

	public void OnAttackTimeOut()
	{
		_attackTimer.Start();

		var nearestEnemy = _gameManager.GetNearestEnemy();
		if (nearestEnemy == null) return;

		//nearestEnemy.TakeDamages();
	}

	public void TakeDamages(uint damages)
	{
		_lifepoints -= Math.Clamp(damages, 0, _lifepoints);
	}

	internal void Heal(uint damages)
	{
		_lifepoints = Math.Clamp(_lifepoints + damages, 0, MaxLifepoints);
	}
}



extends CharacterBody2D
class_name Player2D
enum State { IDLE, RUN, JUMP, ATTACK }
var state = State.IDLE
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 = stats.max_health
	player_base.set_health(stats.health)
	EventManager.bullets_amount = bullets_amount
	EventManager.update_bullet_ui.emit()
	

func _physics_process(delta):
	apply_gravity(delta)
	
	var input_vector = Input.get_axis("move_left","move_right")
	if input_vector != 0:
		apply_acceleration(input_vector, delta)
	else:
		apply_friction(delta)
	if Input.is_action_just_pressed("SwapPlane"):
		_on_swapPlane()
	if Input.is_action_just_pressed("jump") and is_on_floor():
		jump()
	
	if Input.is_action_just_pressed("shoot"):
		animator.play("Attacking")
		
		if bullets_amount:
			guns_animator.play("Shoot")
		
	
	move_and_slide()
	animate(input_vector)

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 apply_gravity(delta):
	if not is_on_floor():
		velocity.y += movement_data.gravity * movement_data.gravity_scale * delta

func process_gravity(delta):
	if not is_on_floor():
		velocity.y += movement_data.gravity * movement_data.gravity_scale * 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") and is_on_floor():
		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 is_on_floor():
			if input_vector != 0:
				animator.play("Run")
			else:
				animator.play("Idle")
		else:
			if velocity.y > 0:
					animator.play("Jump")
		# Check if the current animation is the attack animation


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 is_on_floor():
		if velocity.x != 0:
			animator.play("Run")
		else:
			animator.play("Idle")
	else:
		animator.play("Jump") if velocity.y < 0 else animator.play("Fall")

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); 
	get_tree().change_scene_to_file("res://demo/Scenes/main_scene.tscn")

# 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)