Godot Version
4.2 Stable
Question
Hello, guys. So, I’m developing a Top-Down 2D multiplayer game, I’m currently using a dedicated server to create the network.
My biggest problem right now is about “Physics Networking”, I’m facing a bad time with RigidBody2D, because it constantly gets out of sync with the another client since I’m relaying on the both clients to get all the physics.
I first thought in doing all the calcs in the Godot Server with the own engine, but after some googling, I found some ppl telling that it can turn into a expensive server with some delay.
So I’m a bit confunsed on what to do, if I should keep in the way of using clients to do all the physics, if I shouldn’t be so scared (bcuz of the costs of mantaining it or the scalability or capacity ) of doing it all the calcs in my own server.
My game is pretty simple, so I like the idea of an easy solution like relaying on the clients to do the calcs. If anyone has any good solution to keep the calcs with the clients and to solve unsynced glitches please tell me, I’ll leave some recordings of my game and some scripts.
P.S: I know that I’m getting these unsync bugs bcuz I’m not syncing the position, but only the velocity. When I try to manually set the RigidBody2D position I get unexpected physics behaviour, that’s why I’m only using velocity rn and not only position.
Video Demonstrations
First demo: https://streamable.com/4oer58
Second Demo:
Some Code
Some server code:
# world_state = {intPlayerId: {T: unixSystemTime, P: rigidBodyGlobalPosition, V: rigidBodyVelocity}}
@rpc("any_peer")
func ReceivePlayerState(player_state):
var player_id = multiplayer.get_remote_sender_id()
if players_states.has(player_id):
if players_states[player_id]["T"] < player_state["T"]:
players_states[player_id] = player_state
else:
players_states[player_id] = player_state
func SendWorldState(world_state):
rpc_id(0, 'ReceiveWorldState', world_state)
I have separate scenes for players, one for the main player and another for connected players.
Main Player code to Sync:
extends RigidBody2D
@export var _move_speed: float = 620
var player_state
func _ready():
pass
func _enter_tree():
set_multiplayer_authority(name.to_int())
func _physics_process(delta):
_move_speed = 620
move(delta)
set_player_state()
pass
func move(delta: float) -> void:
var _direction: Vector2 = Vector2(
Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
Input.get_action_strength("move_down") - Input.get_action_strength("move_up")
)
if _direction != Vector2.ZERO:
apply_central_impulse(_direction.normalized() * _move_speed * delta)
if Input.is_action_pressed('ability'):
player_border.texture = border_spritesheet['ability']
apply_central_impulse(Vector2(_direction.normalized()) * dash_power)
func set_player_state():
player_state = {"T": Time.get_unix_time_from_system(), "V": linear_velocity, "P": global_position}
Server.SendPlayerState(player_state)
pass
Code for the template_player scene ( other players that arent the main one ):
extends RigidBody2D
var client_player_state
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass
func _integrate_forces(state):
if client_player_state:
var t:Transform2D = state.transform
t.origin = global_position
state.set_transform(t)
state.linear_velocity = client_player_state['V']
func MovePlayer(player_state) -> void:
client_player_state = player_state