PIXEL
PIXEL

Reputation: 13

Player freezes in position when swapped in for another player

I have character code:

extends CharacterBody3D
@onready var camera_mount = $camera_mount
@onready var animation_player = $visuals/mixamo_base/AnimationPlayer
@onready var visuals = $visuals
@onready var camera_3d = $camera_mount/Camera3D

@export var is_current:bool = true
@export var is_main = true
@export var SPEED = 5.0
@export var JUMP_VELOCITY = 4.5
@export var SENSIVITY = 0.05
var walk_speed = 3.0
var run_speed = 5.0
var is_running = false
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")

func _ready() -> void:
    if is_main:
        Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

func _input(event):
    if is_main:
        if event is InputEventMouseMotion:
            rotate_y(deg_to_rad(-event.relative.x*SENSIVITY))
            visuals.rotate_y(deg_to_rad(event.relative.x*SENSIVITY))
            camera_mount.rotate_x(deg_to_rad(-event.relative.y*SENSIVITY))
            

        
func _physics_process(delta):
    if is_main:
        camera_3d.current = is_current

        if not is_on_floor():
            velocity.y -= gravity * delta
        if Input.is_action_pressed("run"):
            SPEED = run_speed
            is_running = true
        else:
            is_running = false
            SPEED = walk_speed
            

        if Input.is_action_just_pressed("ui_accept") and is_on_floor():
            velocity.y = JUMP_VELOCITY
            
        if Input.is_action_just_pressed("ui_cancel"):
            Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)


        var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
        
        var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
        if direction:
            if animation_player.current_animation != "walking" && is_running == false:
                animation_player.play("walking")
                
            if animation_player.current_animation != "running" && is_running:
                animation_player.play("running")
            
                
            visuals.look_at(position+direction)
                
            velocity.x = direction.x * SPEED
            velocity.z = direction.z * SPEED
        else:
            if animation_player.current_animation != "idle":
                animation_player.play("idle")
                
            velocity.x = move_toward(velocity.x, 0, SPEED)
            velocity.z = move_toward(velocity.z, 0, SPEED)
            
        camera_mount.rotation.x = clamp(camera_mount.rotation.x, 
            deg_to_rad(-90), 
            deg_to_rad(70)
        )

        move_and_slide()

And the script responsible for changing the character in the game using a button:

extends Node3D

@onready var player_1 = $"../Player1"
@onready var player_2 = $"../Player2"

func _physics_process(_delta):
    if Input.is_action_just_pressed("switch_player"):
        if player_1.is_main:
            player_1.is_main = false
            player_2.is_main = true
            player_2.is_current = true
            player_1.animation_player.play("idle")
        else:
            player_1.is_main = true
            player_2.is_main = false
            player_1.is_current = true
            player_2.animation_player.play("idle")

The problem is that if you change the player while the one you were playing for before is in the air, then he freezes in this position. How can I make it so that as soon as I change a player, the one I played for before falls to the ground, i.e. began to succumb to the laws of physics?

Upvotes: 1

Views: 56

Answers (1)

M. R. M.
M. R. M.

Reputation: 653

I've made something similar in concept so I might have an idea on what went wrong. You need to transfer property values from the old player to the new one. That way it'll seem like player_2 picks up exactly where player_1 left off.

Something like this:

extends Node3D

@onready var player_1 = $"../Player1"
@onready var player_2 = $"../Player2"

const TRANSFER_PROPERTIES = ["velocity", "is_running", "walk_speed"] # add whatever variable names you need

func transfer_values(from, to):
    
    to.set_physics_process(false) # avoid running the _physics_process while variables are being transfered
    from.set_physics_process(false)
    
    for prop in TRANSFER_PROPERTIES:
        to[prop] = from[prop]
        
    to.set_physics_process(true)
    from.set_physics_process(true)

func _physics_process(_delta):
    if Input.is_action_just_pressed("switch_player"):
        if player_1.is_main:
            transfer_values(player_1, player_2)
            player_1.is_main = false
            player_2.is_main = true
            player_2.is_current = true
            player_1.animation_player.play("idle")
        else:
            transfer_values(player_2, player_1)
            player_1.is_main = true
            player_2.is_main = false
            player_1.is_current = true
            player_2.animation_player.play("idle")

Some references that might help you out in the future if things get more complex:
get_script()
get_script_property_list()

Upvotes: 0

Related Questions