Godot Version
Godot 4.2.1
Question
Greetings everyone,
I’m currently developing a P2P multiplayer game in Godot utilizing WebRTC. I have successfully set up most of the multiplayer synchronization and authority. In my test scene, I have two connected peers and a ball (all of them being 2D RigidBodies), with the ball controlled by the main/host peer.
The issue I’m facing is occasional jittering of the ball’s position, which seems to be related to the correct_error
function. I got this script from a helpful user on this forum and adapted it for a RigidBody2D (special thanks to @pennyloafers). The script pulls the physics object on the main peer, gathers position, rotation, and velocities into an array, and syncs that to the client. The client receives the array and updates its local physics object in reverse, extracting from the array and placing it onto the physics server object.
I’m creating this topic because I’m somewhat confused about what steps I should take to address this issue. The solutions I’ve attempted so far haven’t produced satisfactory results. Should I implement interpolations in my script? What steps can I take to resolve this?
Demonstration
The larger screen represents the host, which operates normally without jittering. However, jittering and inconsistencies are noticeable in the smaller one.
My Script
BallSynchronizer.gd
extends MultiplayerSynchronizer
class_name PhysicsSynchronizer
@export var sync_bstate_array : Array = \
[0, Vector2.ZERO, Vector2.ZERO, Vector2.ZERO]
@onready var sync_object : RigidBody2D = get_node(root_path)
@onready var body_state : PhysicsDirectBodyState2D = \
PhysicsServer2D.body_get_direct_state( sync_object.get_rid() )
var frame : int = 0
var last_frame : int = 0
enum {
FRAME,
ORIGIN,
LIN_VEL,
ANG_VEL,
}
#copy state to array
func get_state( state, array ):
array[ORIGIN] = state.transform.origin
array[LIN_VEL] = state.linear_velocity
array[ANG_VEL] = state.angular_velocity
#copy array to state
func set_state( array, state ):
state.transform.origin = state.transform.origin.lerp(array[ORIGIN], 0.5)
state.linear_velocity = state.linear_velocity.lerp(array[LIN_VEL], 0.5)
state.angular_velocity = lerpf(state.angular_velocity, array[ANG_VEL], 0.5)
func get_physics_body_info():
# server copy for sync
get_state( body_state, sync_bstate_array )
func set_physics_body_info():
# client rpc set from server
set_state( sync_bstate_array, body_state )
func _physics_process(_delta):
if is_multiplayer_authority() and sync_object.visible:
frame += 1
sync_bstate_array[FRAME] = frame
get_physics_body_info()
# make sure to wire the "synchronized" signal to this function
func _on_synchronized():
correct_error()
# is this necessary?
if is_previous_frame():
return
set_physics_body_info()
# very basic network jitter reduction
func correct_error():
var diff :Vector2= body_state.transform.origin - sync_bstate_array[ORIGIN]
# correct minor error, but snap to incoming state if too far from reality
if diff.length() < 10:
sync_bstate_array[ORIGIN] = body_state.transform.origin.lerp(sync_bstate_array[ORIGIN], 0)
func is_previous_frame() -> bool:
if sync_bstate_array[FRAME] <= last_frame:
return true
else:
last_frame = sync_bstate_array[FRAME]
return false