Godot Version
Godot v4.3
Question
I have a Multiplayer 3D FPS game with bullet objects that move across the map and collide with walls, etc. The only problem is, they don’t collide with other players. I have a feeling this is due to me not implementing multiplayer correctly since the other players can’t see the bullets but I am not sure.
Here is the code for the bullet script:
extends Node3D
const SPEED = 40.
@onready var mesh = $MeshInstance3D
@onready var ray = $RayCast3D
@onready var particles = $GPUParticles3D
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
position += transform.basis * Vector3(0, 0, -SPEED) * delta
if ray.is_colliding():
if ray.get_collider().is_multiplayer_authority():
particles.emitting = true
mesh.visible = false
await get_tree().create_timer(1.0).timeout
queue_free()
func _on_timer_timeout() -> void:
queue_free()
Here is the player script
extends CharacterBody3D
signal health_changed(health_value)
@onready var camera = $Camera3D
@onready var pistol_anim = $Camera3D/Pistol/AnimationPlayer
@onready var muzzle_flash = $Camera3D/Pistol/MuzzleFlash
@onready var raycast = $Camera3D/RayCast3D
@onready var pistol = $Camera3D/Pistol
@onready var shotgun = $Camera3D/Shotgun
@onready var leftHand = $Camera3D/Pistol/LeftHand
@onready var shotgun_anim = $Camera3D/Shotgun/AnimationPlayer
@onready var gun_barrel = $Camera3D/Shotgun/RayCast3D
var bullet = load("res://bullet.tscn")
var instance
var health = 100
var atk = 25
const SPEED = 8
const JUMP_VELOCITY = 12
var gravity = 30
var friction = 11
var gun = "pistol"
func _enter_tree():
set_multiplayer_authority(str(name).to_int())
func _ready():
if not is_multiplayer_authority(): return
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
camera.current = true
func _unhandled_input(event):
if not is_multiplayer_authority(): return
if event is InputEventMouseMotion:
rotate_y(-event.relative.x * .005)
camera.rotate_x(-event.relative.y * .005)
camera.rotation.x = clamp(camera.rotation.x, -PI/2, PI/2)
if Input.is_action_just_pressed("shoot"):
if gun == "pistol":
if pistol_anim.current_animation != "shoot":
play_shoot_effects.rpc()
if raycast.is_colliding():
var hit_player = raycast.get_collider()
hit_player.receive_damage.rpc_id(hit_player.get_multiplayer_authority())
elif gun == "shotgun":
if shotgun_anim.current_animation != "shoot":
play_shoot_effects.rpc()
instance = bullet.instantiate()
instance.global_position = gun_barrel.position
instance.global_transform.basis = gun_barrel.transform.basis
add_child(instance)
if Input.is_action_just_pressed("pistol"):
gun = "pistol"
show_gun.rpc()
if Input.is_action_just_pressed("shotgun"):
gun = "shotgun"
show_gun.rpc()
func _physics_process(delta: float) -> void:
if not is_multiplayer_authority(): return
# Add the gravity.
if not is_on_floor():
velocity.y -= gravity * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# 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.get_vector("left", "right", "up", "down")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x -= velocity.x * (friction * delta)
velocity.z -= velocity.z * (friction * delta)
if pistol_anim.current_animation == "shoot":
pass
elif input_dir != Vector2.ZERO and is_on_floor():
pistol_anim.play("move")
else:
pistol_anim.play("idle")
move_and_slide()
@rpc("call_local")
func show_gun():
if gun == "pistol":
shotgun.hide()
pistol.show()
elif gun == "shotgun":
pistol.hide()
shotgun.show()
@rpc("call_local")
func play_shoot_effects():
if gun == "pistol":
pistol_anim.stop()
pistol_anim.play("shoot")
muzzle_flash.restart()
muzzle_flash.emitting = true
elif gun == "shotgun":
shotgun_anim.stop()
shotgun_anim.play("shoot")
@rpc("any_peer")
func receive_damage():
health -= atk
if health <= 0:
health = 100
position = Vector3.ZERO
health_changed.emit(health)
func _on_animation_player_animation_finished(anim_name: StringName) -> void:
if anim_name == "shoot":
pistol_anim.play("idle")
Here is the world script
extends Node
@onready var main_menu = $CanvasLayer/MainMenu
@onready var address_entry = $CanvasLayer/MainMenu/MarginContainer/VBoxContainer/AddressEntry
@onready var hud = $CanvasLayer/HUD
@onready var health_bar = $CanvasLayer/HUD/HealthBar
const Player = preload("res://player.tscn")
const PORT = 9999
var enet_peer = ENetMultiplayerPeer.new()
func _unhandled_input(_event):
if Input.is_action_just_pressed("quit"):
get_tree().quit()
func _on_host_button_pressed() -> void:
main_menu.hide()
hud.show()
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())
Thank you so much in advance!