0
\$\begingroup\$

I am new to game development and Godot. The code is gathered from multiple tutorials and now i am stuck. It almost seems to work but my problem is the respawn mechanism. Maybe someone can have a look at my code.

extends CharacterBody3D

# onready variables
@onready var collision_shape = $CollisionShape3D 
@onready var head = $Head
@onready var weaponcamera = $Head/MainCamera/SubViewportContainer/SubViewport/WeaponCamera
@onready var maincamera = $Head/MainCamera

# variables
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
var speed = 3.0  
var jump_speed = 4.0
var mouse_sensitivity = 0.002  
var vertical_angle = 0.0 
var is_running = false
var is_paused = false
var health = 100

var target_position: Vector3

func _ready():
    
    # display our name
    name = str(get_multiplayer_authority())
    $Name.text = str(name)
    
    if is_multiplayer_authority():
        Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
    else:
        weaponcamera.current = false
        maincamera.current = false
    
    var spawnarea = get_tree().root.get_node("Main/Area3D")
    if spawnarea:
        position = spawnarea.get_random_position_within_area()
    
func _process(delta):
    if is_multiplayer_authority():
        get_input()
        maincamera.global_transform = head.global_transform
        weaponcamera.global_transform = head.global_transform

func _physics_process(delta):
    if is_multiplayer_authority():
        velocity.y += -gravity * delta
        rpc("remote_set_position", global_position)
        rpc("remote_set_rotation", global_rotation)
        move_and_slide()
    else:
        # interpolate towards target_position
        global_position = global_position.lerp(target_position, 10 * delta)
        
func get_input():
    if !is_multiplayer_authority():
        return
    
    # mouse capture
    if Input.is_action_just_pressed("escape"):
        if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
            Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
            is_paused = true
        else:
            Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
            is_paused = false
        
    if is_paused: return
        
    # movement
    var input = Input.get_vector("move_left", "move_right", "move_forward", "move_backward")
    var movement_dir = transform.basis * Vector3(input.x, 0, input.y)
    var speed_t = speed
    if Input.is_action_pressed("left_shift"):
        speed_t *= 2
    velocity.x = movement_dir.x * speed_t
    velocity.z = movement_dir.z * speed_t

    # shoot
    if Input.is_action_just_pressed("shoot"):
        shoot()
    
    # jumping
    if Input.is_action_pressed("jump") and is_on_floor():
        velocity.y = jump_speed

# mouse input
func _unhandled_input(event):
    
    if not is_multiplayer_authority():
        return
        
    if is_paused:
        return
        
    if event is InputEventMouseMotion:
        # Horizontale Charakterrotation (um die y-Achse)
        rotate_y(-event.relative.x * mouse_sensitivity)
        # Vertikale Kamerarotation (um die x-Achse des SpringArm3D)
        vertical_angle -= event.relative.y * mouse_sensitivity
        vertical_angle = clamp(vertical_angle, -PI / 2, PI / 2)  # Begrenzung der vertikalen Rotation auf +-90°
        head.rotation.x = vertical_angle
    
func shoot():
    var space = get_world_3d().direct_space_state
    var center = get_viewport().get_size()/2
    var raystartposition = maincamera.project_ray_origin(center)
    var rayendposition = raystartposition + maincamera.project_ray_normal(center) * 100
    var query = PhysicsRayQueryParameters3D.create(raystartposition, rayendposition)
    var collision = space.intersect_ray(query)
    
    if collision:

        if collision.collider.has_method("take_damage"):
            collision.collider.take_damage(10)

        rpc("_shoot", raystartposition, collision)


# Gets called from remote player 
func take_damage(amount):
    health -= amount
    if health <= 0:
        var area = get_tree().root.get_node("Main/Area3D")
        if area:
            var random_position = area.get_random_position_within_area()
            position = random_position
            print(str(position))
        health = 100
    $Message.text = str(health)
    rpc("sync_health", health) 

# Gets called by take_damage
@rpc ("any_peer")
func sync_health(new_health):
    health = new_health
    $Message.text = str(health)
    
# Gets called by shoot()
@rpc
func _shoot(root, target):
    # omitted
    pass
    
@rpc 
func remote_set_position(authority_position):
    target_position = authority_position
    
@rpc 
func remote_set_rotation(authority_rotation):
    global_rotation = authority_rotation

@rpc ("any_peer")
func send_message(message):
    print(message)

The respawn-code is in the function take_damage but the player always get back to its previous position after respawn. Can you help me to find the problem please that would be very nice.

\$\endgroup\$
3
  • \$\begingroup\$ Where would you like the player to respawn instead? \$\endgroup\$ Commented Jan 13 at 17:34
  • \$\begingroup\$ I want him to spawn at a random position inside an area3d in the function take_damage. var random_position = area.get_random_position_within_area() The generation of the position worked before i implemented the health/damage code so it should be fine. Also at the player who shot i can see that the character indeed pops up in the area3d but immediately gets repositioned to the last position before the respawn. But the other players see nothing of that, it just stays where it was. I think its not allowed to link a github repository, is it? Because somebody could reproduce it better. \$\endgroup\$ Commented Jan 13 at 17:45
  • 1
    \$\begingroup\$ It's not forbidden to link an external repository, but your question should be fully-documented and understandable even if a user does not click the external links. \$\endgroup\$ Commented Jan 13 at 18:42

1 Answer 1

1
\$\begingroup\$

Make your take_damage function an rpc callable by everyone but only execute it in the authority instance.

@rpc ("any_peer")
func take_damage(damage):
    if not is_multiplayer_authority():
        return

When you reposition your player (respawn) additionally call the RPC to set the new position in all instances instead of only your own instance.

rpc("remote_set_position", random_position)

Finally in your shoot function call take_damage as an RPC

collision.collider.take_damage.rpc(10)
\$\endgroup\$
2
  • \$\begingroup\$ Hello and thank you for your answer but my problem is the respawning and not the health. When the Player rewspawns the player who shot him can see the respawn but after a second or so the Player who was shot is at the same Position like befor the Respawn. \$\endgroup\$ Commented Jan 15 at 15:15
  • \$\begingroup\$ In take_damage you wrote: var random_position = area.get_random_position_within_area() position = random_position The line: collision.collider.take_damage.rpc(10) will additionally set the position on any remote-instance of the player by using an RPC call. godotengine.org/article/multiplayer-changes-godot-4-0-report-2 \$\endgroup\$ Commented Jan 16 at 9:28

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.