Godot Version
4.4.stable
Question
`Only the host of the game is able to grab the objects. Whenever the client/joiner attempts to pick the object, it jitters back and forward, when letting go it reverts to the normal position before i grabbed the object. Essentially only the host has control.
The grabbing script:
class_name InventoryAndGrabbing
@onready var player = $".."
@onready var interaction = $"../Camera/rigidGrip"
@onready var hand = $"../Camera/distance"
var picked_object: RigidBody3D = null
var gravitatePower: float = 120.0
var hand_distance: float = 1.0
var hand_min_distance: float = 1.0
var hand_max_distance: float = 2.0
var hand_distance_speed: float = 0.5
var previous_error := Vector3.ZERO
const P = 80.0 # Proportional gain
const I = 2.0 # Integral gain
const D = 12.0 # Derivative gain
var integral := Vector3.ZERO
func _ready():
hand.position = Vector3(0.0, 0.0, -hand_distance)
func _input(event):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
hand_distance = clamp(hand_distance + hand_distance_speed, hand_min_distance, hand_max_distance)
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
hand_distance = clamp(hand_distance - hand_distance_speed, hand_min_distance, hand_max_distance)
hand.position = Vector3(0.0, 0.0, -hand_distance)
if event.is_action_pressed("left click") and picked_object == null:
pick_object()
if event.is_action_released("left click") and picked_object != null:
drop_object()
func _physics_process(delta):
if picked_object != null:
var a = picked_object.global_transform.origin
var b = hand.global_transform.origin
var error = b - a
var mass_factor = 1.0 / picked_object.mass
integral += error * delta
var derivative = (error - previous_error) / delta
previous_error = error
var force = (P * error + I * integral + D * derivative) * mass_factor
# Velocity damping in lateral directions
var current_vel = picked_object.linear_velocity
var lateral_vel = current_vel - current_vel.project(error.normalized())
picked_object.apply_central_impulse(-lateral_vel * mass_factor * delta * 60)
# Apply main force while preserving vertical velocity for gravity
var current_vertical_velocity = picked_object.linear_velocity.y
picked_object.apply_central_force(force)
picked_object.linear_velocity.y = current_vertical_velocity
func pick_object():
var collider = interaction.get_collider()
if collider != null and collider is RigidBody3D:
picked_object = collider
picked_object.angular_damp = 2.0 + (4.0 / picked_object.mass)
picked_object.contact_monitor = true
picked_object.max_contacts_reported = 1
picked_object.set_use_continuous_collision_detection(true)
func drop_object():
if picked_object != null:
picked_object.set_use_continuous_collision_detection(false)
picked_object.angular_damp = 0.5
picked_object = null
integral = Vector3.ZERO
previous_error = Vector3.ZERO
The multiplayer logic:
var enet_peer = ENetMultiplayerPeer.new()
@export var player_scene : PackedScene
func _on_host_button_pressed():
var host_ip = get_local_ip()
print("Hosting on IP: ", host_ip)
var port_input_text = $CanvasLayer/PortInput.text.strip_edges()
if port_input_text == "" or port_input_text.to_int() <= 0:
print("Please insert a valid port number before hosting.")
return
var port = port_input_text.to_int()
enet_peer.create_server(port)
multiplayer.multiplayer_peer = enet_peer
multiplayer.peer_connected.connect(add_player)
multiplayer.peer_disconnected.connect(remove_player)
add_player(multiplayer.get_unique_id())
upnp_setup(port)
$CanvasLayer.hide()
func _on_join_button_pressed():
var ip = $CanvasLayer/IPInput.text.strip_edges()
if ip.is_empty():
print("Please enter an IP address.")
return
var port_input_text = $CanvasLayer/joinPortInput.text.strip_edges()
if port_input_text == "" or port_input_text.to_int() <= 0:
print("Please insert a valid port number before joining.")
return
var port = port_input_text.to_int()
enet_peer.create_client(ip, port)
multiplayer.multiplayer_peer = enet_peer
$CanvasLayer.hide()
func add_player(peer_id):
var player = player_scene.instantiate()
player.name = str(peer_id)
add_child(player)
func remove_player(peer_id):
var player = get_node_or_null(str(peer_id))
if player:
player.queue_free()
func get_local_ip():
var addresses = IP.get_local_addresses()
for address in addresses:
if address.begins_with("192.168.") or address.begins_with("10.") or address.begins_with("172."):
return address
return "IP not found"
func upnp_setup(port):
var upnp = UPNP.new()
var discover_result = upnp.discover()
assert(discover_result == UPNP.UPNP_RESULT_SUCCESS, "UPNP Discover Failed! Error %s" % discover_result)
assert(upnp.get_gateway() and upnp.get_gateway().is_valid_gateway(), "UPNP Invalid Gateway!")
var map_result = upnp.add_port_mapping(port)
assert(map_result == UPNP.UPNP_RESULT_SUCCESS, "UPNP Port Mapping Failed! Error %s" % map_result)
print("Success! Join Address: %s" % upnp.query_external_address())
func _unhandled_input(event):
if Input.is_action_just_pressed("quit"):
get_tree().quit()
func _on_toggle_ip_button_pressed():
var ip_label = $CanvasLayer/LocalIPLabel
ip_label.visible = !ip_label.visible
if ip_label.visible:
ip_label.text = "Local IP: " + get_local_ip()```