Look through mouse in multiplayer

Godot Version

4.4.stable

Question

I’m making a game where the player aims with the mouse, a person can move everybody’s gun. I can’t find any way to fix it

#player.gd
extends CharacterBody2D
class_name Player2

@onready var dashduration = $dashduration
@onready var dashcooldown = $dashcooldown
@export var normal_speed = 300.0
@export var dash_speed = 600.0
var speed = normal_speed
var is_dashing = false
var max_health = 100
var dash_available = true
@export var health : int
signal player_death
var player_dead = false
@export var scale_player : float
@onready var arm_left = $Player/Skeleton/Skeleton2D/hip/chest/arm_left
@onready var arm_right = $Player/Skeleton/Skeleton2D/hip/chest/arm_right
@onready var marker2d_arm : Marker2D = $Player/Skeleton/Skeleton2D/hip/chest/arm_right/hand_right/Marker2D
@onready var skeleton : Skeleton2D = $Player/Skeleton/Skeleton2D
@onready var gun_handle_marker2d : Marker2D = $Gun/GunHandle
@onready var gun : Node2D = $Gun
var flip_h : bool = false
@onready var polygons : Node2D = $Player/polygons
@onready var gun_damage = $Gun.damage

func _ready():
	polygons.visible = true
	$Gun/Sprite2D.visible = true
	$CollisionShape2D.disabled = false

	if is_multiplayer_authority():
		var camera = Camera2D.new()
		add_child(camera)
		camera.make_current()

func _process(delta: float) -> void:
	if is_multiplayer_authority():
		var mouse_position = get_global_mouse_position()
		rpc_id(1, "update_mouse_position", mouse_position)

@rpc
func update_mouse_position(mouse_position: Vector2) -> void:
	arm_right.look_at(mouse_position)
	arm_right.rotation_degrees = wrap(arm_right.rotation_degrees, 0, 360)
	arm_right.rotation_degrees += 180
	left_arm_rotation()
	update_gun_position()

func _physics_process(delta: float) -> void:
	if is_multiplayer_authority():
		if health == 0 and player_dead == false:
			player_dead = true
			polygons.visible = false
			$Gun/Sprite2D.visible = false
			$CollisionShape2D.disabled = true
			health_label()
			score.enemy_score += 1
			emit_signal("player_death")
		elif health == 0 and player_dead == true:
			pass
		else:
			var direction_x := Input.get_axis("ui_left", "ui_right")
			if direction_x:
				velocity.x = direction_x * speed
			else:
				velocity.x = move_toward(velocity.x, 0, speed)
			
			var direction_y := Input.get_axis("ui_up", "ui_down")
			if direction_y:
				velocity.y = direction_y * speed
			else:
				velocity.y = move_toward(velocity.y, 0, speed)
				
			move_and_slide()
			
			if Input.is_action_just_pressed("wedashing") and dash_available == true and not is_dashing:
				start_wedashing()
				
			health_label()
			arm_rotation()

func start_wedashing():
	is_dashing = true
	dash_available = false
	speed = dash_speed
	dashcooldown.start()
	dashduration.start()
	
func _on_dashduration_timeout() -> void:
	is_dashing = false
	speed = normal_speed

func _on_dashcooldown_timeout() -> void:
	dash_available = true

func _on_area_2d_area_entered(area: Area2D) -> void:
	if area.is_in_group("bullets"):
		health -= area.damage

func left_arm_rotation():
	arm_left.global_position = arm_right.global_position
	arm_left.rotation_degrees = arm_right.rotation_degrees + 5

func update_gun_position():
	gun.global_position = marker2d_arm.global_position
	gun.rotation_degrees = marker2d_arm.global_rotation_degrees

func arm_rotation():
	if is_multiplayer_authority():
		arm_right.look_at(get_global_mouse_position())
		arm_right.rotation_degrees = wrap(arm_right.rotation_degrees, 0, 360)
		arm_right.rotation_degrees += 180
		left_arm_rotation()
		update_gun_position()

func _on_gun_left() -> void:
	$Player.scale.x = -1
	flip_h = true

func _on_gun_right() -> void:
	$Player.scale.x = 1
	flip_h = false

func health_label():
	$CanvasLayer/Label.text = "<3: " + str(health) + "/" + str(max_health)

func _enter_tree():
	set_multiplayer_authority(name.to_int())

I haven’t messed around with multiplayer in godot yet but I did find this, https://www.reddit.com/r/godot/s/l7VHsg21Fw

Just to get the problem correct, the issue is, that you move both weapons instead of just your own?

I already saw this, it fixed the player movement but not the mouse thing

Yes, that’s the problem

extends Node
@onready var main = $Menu/Main
@onready var vs1 = $Menu/vs1
@onready var menu = $Menu

const port = 9999
const Player = preload("res://player_2.tscn")
var enet_peer = ENetMultiplayerPeer.new()


func _ready() -> void:
	main.visible = true
	vs1.visible = false
	multiplayer.peer_connected.connect($MultiplayerSpawner.spawn)

	$MultiplayerSpawner.spawn(multiplayer.get_unique_id())

 	  
func _process(delta: float) -> void:
	pass

func _on_button_pressed() -> void:
	main.visible = false
	vs1.visible = true

func _on_button_2_pressed() -> void:
	get_tree().change_scene_to_file("res://test_world_2.tscn")

func _on_host_pressed() -> void:
	menu.hide()
	
	enet_peer.create_server(port)
	multiplayer.multiplayer_peer = enet_peer
	multiplayer.peer_connected.connect(_add_player)
	_add_player()

func _on_join_pressed() -> void:
	menu.hide()
	
	enet_peer.create_client("localhost", port)
	multiplayer.multiplayer_peer = enet_peer

func _on_bot_pressed() -> void:
	menu.hide()

func _add_player(id = 1):
	var player = Player.instantiate()
	player.name = str(id)
	call_deferred("add_child", player)

You are always calling the rpc to the host (id 1), and not locally. You are using 3.x style of rpc call, it’s better to use update_mouse_position.rpc_id(1, mouse_position). Make sure to read up on RPCs

Could you instead use a mulitplayer synchronizer node to capture the arm rotation? It seems like you must be using a synchronizer node for the movement.

1 Like

I’m already using a synchronizer for the arm

Then you do not need to RPC the rotation, the syncrhonizer will take care of it.

Okay, I removed it. But that doesn’t fix my problem

Can you share how you updated your code? Has the problem changed at all?

It didn’t change at all

extends CharacterBody2D
class_name Player2

@onready var dashduration = $dashduration
@onready var dashcooldown = $dashcooldown
@export var normal_speed = 300.0
@export var dash_speed = 600.0
var speed = normal_speed
var is_dashing = false
var max_health = 100
var dash_available = true
@export var health : int
signal player_death
var player_dead = false
@export var scale_player : float
@onready var arm_left = $Player/Skeleton/Skeleton2D/hip/chest/arm_left
@onready var arm_right = $Player/Skeleton/Skeleton2D/hip/chest/arm_right
@onready var marker2d_arm : Marker2D = $Player/Skeleton/Skeleton2D/hip/chest/arm_right/hand_right/Marker2D
@onready var skeleton : Skeleton2D = $Player/Skeleton/Skeleton2D
@onready var gun_handle_marker2d : Marker2D = $Gun/GunHandle
@onready var gun : Node2D = $Gun
var flip_h : bool = false
@onready var polygons : Node2D = $Player/polygons
@onready var gun_damage = $Gun.damage

func _ready():
	polygons.visible = true
	$Gun/Sprite2D.visible = true
	$CollisionShape2D.disabled = false

	if is_multiplayer_authority():
		var camera = Camera2D.new()
		add_child(camera)
		camera.make_current()
	

func _physics_process(delta: float) -> void:
	if is_multiplayer_authority():
		if health == 0 and player_dead == false:
			player_dead = true
			polygons.visible = false
			$Gun/Sprite2D.visible = false
			$CollisionShape2D.disabled = true
			health_label()
			score.enemy_score += 1
			emit_signal("player_death")
		elif health == 0 and player_dead == true:
			pass
		else:
			if is_multiplayer_authority():
				var direction_x := Input.get_axis("ui_left", "ui_right")
				if direction_x:
					velocity.x = direction_x * speed

				else:
					velocity.x = move_toward(velocity.x, 0, speed)
				var direction_y := Input.get_axis("ui_up", "ui_down")
				if direction_y:
					velocity.y = direction_y * speed
				else:
					velocity.y = move_toward(velocity.y, 0, speed)
					
				move_and_slide()
				
				if Input.is_action_just_pressed("wedashing") and dash_available == true and not is_dashing:
					start_wedashing()
					
				health_label()
	arm_rotation()
func start_wedashing():
	is_dashing = true
	dash_available = false
	speed = dash_speed
	dashcooldown.start()
	dashduration.start()
	
func _on_dashduration_timeout() -> void:
	is_dashing = false
	speed = normal_speed

func _on_dashcooldown_timeout() -> void:
	dash_available = true

func _on_area_2d_area_entered(area: Area2D) -> void:
	if area.is_in_group("bullets"):
		health -= area.damage

func left_arm_rotation():
	arm_left.global_position = arm_right.global_position
	arm_left.rotation_degrees = arm_right.rotation_degrees + 5

func update_gun_position():
	if is_multiplayer_authority():
		gun.global_position = marker2d_arm.global_position
		gun.rotation_degrees = marker2d_arm.global_rotation_degrees
		

func arm_rotation():
	if is_multiplayer_authority():
		arm_right.look_at(get_local_mouse_position())
		arm_right.rotation_degrees = wrap(arm_right.rotation_degrees, 0, 360)
		arm_right.rotation_degrees += 180
		left_arm_rotation()
		update_gun_position()

func _on_gun_left() -> void:
	$Player.scale.x = -1
	#rotation_degrees = 180
	flip_h = true

func _on_gun_right() -> void:
	$Player.scale.x = 1
	#rotation_degrees = 0
	flip_h = false

func health_label():
	$CanvasLayer/Label.text = "<3: " + str(health) + "/" + str(max_health)

func _enter_tree():
	set_multiplayer_authority(name.to_int())

you arm rotation is un-indented so it runs regardless of is_multiplayer_authority(), it may be easier to disable process functions on non-authority clients.

func _ready():
	polygons.visible = true
	$Gun/Sprite2D.visible = true
	$CollisionShape2D.disabled = false

	if is_multiplayer_authority():
		var camera = Camera2D.new()
		add_child(camera)
		camera.make_current()
	set_physics_process(is_multiplayer_authority())

func _physics_process(delta: float) -> void:
	if health == 0 and player_dead == false:
		player_dead = true

ah and it has it’s own authority check, strange. The movement is still working correctly? just the rotation fails?

1 Like

I tried what you said, movement works fine but rotation fails