foxssake / netfox

Addons for building multiplayer games with Godot
https://foxssake.github.io/netfox/
MIT License
341 stars 14 forks source link

Multiplayer Moving Platform #223

Closed andrewmunro closed 3 weeks ago

andrewmunro commented 4 months ago

Hey, cool library!

I've been playing about with it and got some players running around really easily. Would you happen to have any examples of how you could create moving platforms that the player can walk around on? I'm thinking for things like vehicles, e,g a boat or a space ship.

I've tried creating a basic static body that moves around, then updating the player's velocity based on the platform's velocity, but unfortunately the player just slides off. This seems to work without networking, but I can't seem to get it to work with my RollbackSynchronizer.

Any thoughts?

albertok commented 4 months ago

Hey @andrewmunro

Could you post what your player rollback_tick code looks like and what state properties you have configured in the RollbackSynchronizer Node for that player?

As far as I know if player is a CharacterBody type node it should just work. The fact you mention that it works without networking makes me think the client is doing movement changes outside the rollback_tick function.

andrewmunro commented 4 months ago

Heya, appreciate the help! Ok so I got it working, it turns out I was calculating my velocity slightly wrong using move_and_collide, the fix was to no longer multiply by NetworkTime.physics_factor, which seems to only be a problem for move_and_slide()

It does now move with the platform it's standing on, although there's a slight delay for remote players when the platform starts moving (see gif below), I assume this is because of the interpolation delay. Not sure the best way to get around this, here's my code if you have any suggestions or improvements.

func _rollback_tick(delta, _tick, _is_fresh):
    # Add the gravity.
    if not is_on_floor():
        velocity.y -= gravity * delta

    # Handle jump.
    if input.movement.y > 0 and is_on_floor():
        velocity.y = jump_velocity * input.movement.y

    pitch_pivot.rotation.x = input.pitch
    yaw_pivot.rotation.y = input.yaw

    # Handle movement
    var input_dir = input.movement
    var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.z)).normalized()
    if direction:
        velocity.x = direction.x * speed
        velocity.z = direction.z * speed
    else:
        velocity.x = move_toward(velocity.x, 0, speed)
        velocity.z = move_toward(velocity.z, 0, speed)

    # move with parent vehicle
    if raycast.is_colliding():
        var parent = raycast.get_collider()
        if parent.is_in_group("vehicles"):
            velocity += parent.velocity

    velocity *= NetworkTime.physics_factor
    move_and_slide()
    velocity /= NetworkTime.physics_factor
extends StaticBody3D

@export_group("Settings")
@export var speed = 5.0

@onready var input = $Input
@export var velocity = Vector3.ZERO

func _rollback_tick(delta, _tick, _is_fresh):
    # Get the input direction and handle the movement/deceleration.
    # As good practice, you should replace UI actions with custom gameplay actions.
    var input_dir = input.movement
    var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.z)).normalized()
    if direction:
        velocity.x = direction.x * speed
        velocity.z = direction.z * speed
    else:
        velocity.x = move_toward(velocity.x, 0, speed)
        velocity.z = move_toward(velocity.z, 0, speed)

    # velocity *= NetworkTime.physics_factor
    move_and_collide(velocity * delta)
    # velocity /= NetworkTime.physics_factor

In the boat, I'm syncing the velocity and global_transform in both the RollbackSyncronizer and TickInterpolator. In the player, I'm syncing just the global_transform in both the RollbackSyncronizer and TickInterpolator.

raft2

I have a hosted version available here: https://island.mun.sh/.

andrewmunro commented 4 months ago

Ok I'm back after doing some more experimenting. I've decided to scrap syncing and applying boat velocity to the player because I was having all sorts of issues with sliding due to the physics calculations.

Instead I'm attempting to try make the player a child of the boat. I can't use reparent(), because this seems to break the Synchronizer. I've created a container node for the player and I'm setting this transform to the boat's transform in each rollback_tick.

This almost works, I no longer have any sliding issues. Instead, I'm having lots of really bad interpolation issues, I think because I'm explicitly setting the parent's position rather than interpolating it. Here's what I have so far, any suggestions would be much appreciated 🙈

Player:

image image image

Raft (Boat):

image image

albertok commented 4 months ago

@andrewmunro

Few things to try, I'm not sure if they will help:

  1. Move the 'move with vehicle' code to be before applying user input
  2. Sync the velocity in the Players RollbackSynchronizer state, it might make the interpolation more predicatable
elementbound commented 3 weeks ago

Hey @andrewmunro,

Closing this ticket as it has been a while since the last comment. Nonetheless, feel free to open another issue, referring to this one! And thanks @albertok for the help!