0

I'm trying to make an ordinary multiplayer FPS. I use a second Camera3D and a SubViewport to avoid player's gun clipping into the wall: enter image description here

Both cameras' cull masks set up the way that everything works fine until the other player hasn't connected.

As another player connects to a host, every player get an extra gun rendered on their screen: enter image description here Apparently it's happening because every new connection instantiates a new player, hence there's another viewport in the world which adds up everything it has to render to players' screens. Also if I remove the whole SubViewportContainer, guns don't render in the wrong places anymore, only in other players' hands, but now they're clipping into the walls.

Here's my world script that handles connections:

extends Node

@onready var main_menu = $CanvasLayer/Menu
@onready var address_entry = $CanvasLayer/Menu/MarginContainer/VBoxContainer/AddressEntry

const Player = preload("res://scenes/Player.tscn")
const PORT = 8899
var enet_peer = ENetMultiplayerPeer.new()

func _unhandled_input(event):
    if Input.is_action_just_pressed("exit"):
        get_tree().quit()


func _on_host_pressed():
    main_menu.hide()
    
    enet_peer.create_server(PORT)
    multiplayer.multiplayer_peer = enet_peer
    multiplayer.peer_connected.connect(add_player)
    
    add_player(multiplayer.get_unique_id())


func _on_join_pressed():
    main_menu.hide()
    
    enet_peer.create_client(address_entry.text, PORT)
    multiplayer.multiplayer_peer = enet_peer


func add_player(peer_id):
    var player = Player.instantiate()
    player.name = str(peer_id)
    add_child(player)

This seems like a common task but still I couldn't manage to find any Godot 4 solution on the Internet.

I have tried to change pistol's model meshes' VisualInstance3D layer while instantiating a new player on a new connection, but this doesn't really make any sense as every players' guns VisualInstance3D layers are the same anyway. And since the model isn't made very well and has many meshes it just hurts to see the code:

func add_player(peer_id):
    var player = Player.instantiate()
    var glock_body = player.get_node("Camera/Camera3D/toy_glock_lowpoly_w_bevel/glock_body")
    var glock_slide = player.get_node("Camera/Camera3D/toy_glock_lowpoly_w_bevel/glock_slide")
    var glock_barrel = player.get_node("Camera/Camera3D/toy_glock_lowpoly_w_bevel/glock_barrel")
    var glock_trigger = player.get_node("Camera/Camera3D/toy_glock_lowpoly_w_bevel/glock_trigger")
    var glock_magazine = player.get_node("Camera/Camera3D/toy_glock_lowpoly_w_bevel/glock_magazine")
    var glock_ammo_shell = player.get_node("Camera/Camera3D/toy_glock_lowpoly_w_bevel/glock_ammo_shell")
    glock_body.set_layer_mask(3)
    glock_slide.set_layer_mask(3) 
    glock_barrel.set_layer_mask(3)
    glock_trigger.set_layer_mask(3)
    glock_magazine.set_layer_mask(3)
    glock_ammo_shell.set_layer_mask(3)
    
    player.name = str(peer_id)
    add_child(player)

1 Answers1

0

Disclaimer: At the time of writing, I only very limited knowledge of Godot's built-in multiplayer solution.

My understanding of the issue is that when the other players spawn they also have a SubViewportContainer and so on. Thus, the solution is to not make that a part of the player scene.

These approaches come to mind:

  • Have it as part of the parent scene, and use _process to copy the location of the Camera3D of the local player character.
  • Make it another scene, and only instance it for the local player character (via editable children).
Theraot
  • 31,890
  • 5
  • 57
  • 86