Base Weapons
Place in world, pick up and drop working on multiplayer
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
extends RigidBody3D
|
||||
class_name WorldWeapon
|
||||
|
||||
## Weapon as a physics object in the world
|
||||
## Can be picked up by players
|
||||
## Spawned when a weapon is dropped or placed in the level
|
||||
|
||||
@export var weapon_data: WeaponData
|
||||
|
||||
var _mesh_instance: Node3D = null
|
||||
var _collision_shape: CollisionShape3D = null
|
||||
var _pickup_area: Area3D = null
|
||||
var _is_being_picked_up: bool = false
|
||||
|
||||
func _ready():
|
||||
# Set collision layer to "weapon" (layer 3 = bit 4)
|
||||
collision_layer = 4
|
||||
collision_mask = 2 # Collide with world
|
||||
|
||||
# Set up physics
|
||||
if weapon_data:
|
||||
mass = weapon_data.weight
|
||||
|
||||
# Spawn mesh
|
||||
if weapon_data and weapon_data.mesh_scene:
|
||||
_spawn_mesh()
|
||||
|
||||
# Create collision shape if not exists
|
||||
_setup_collision()
|
||||
|
||||
# Create pickup area
|
||||
_setup_pickup_area()
|
||||
|
||||
# Only server manages pickup logic
|
||||
if multiplayer.is_server():
|
||||
_pickup_area.body_entered.connect(_on_body_entered_pickup_area)
|
||||
|
||||
func _spawn_mesh():
|
||||
# Remove old mesh if exists
|
||||
if _mesh_instance:
|
||||
_mesh_instance.queue_free()
|
||||
|
||||
# Instantiate mesh
|
||||
_mesh_instance = weapon_data.mesh_scene.instantiate()
|
||||
add_child(_mesh_instance)
|
||||
|
||||
func _setup_collision():
|
||||
# Check if we already have a collision shape
|
||||
for child in get_children():
|
||||
if child is CollisionShape3D:
|
||||
_collision_shape = child
|
||||
return
|
||||
|
||||
# Create a basic box collision if none exists
|
||||
_collision_shape = CollisionShape3D.new()
|
||||
var box_shape = BoxShape3D.new()
|
||||
box_shape.size = Vector3(0.5, 0.5, 1.5) # Approximate weapon size
|
||||
_collision_shape.shape = box_shape
|
||||
add_child(_collision_shape)
|
||||
|
||||
func _setup_pickup_area():
|
||||
# Create Area3D for pickup detection
|
||||
_pickup_area = Area3D.new()
|
||||
_pickup_area.name = "PickupArea"
|
||||
_pickup_area.collision_layer = 4 # Layer 3 (weapon layer) so player can detect it
|
||||
_pickup_area.collision_mask = 1 # Detect players
|
||||
add_child(_pickup_area)
|
||||
|
||||
# Create sphere collision for pickup range
|
||||
var pickup_collision = CollisionShape3D.new()
|
||||
var sphere = SphereShape3D.new()
|
||||
sphere.radius = weapon_data.pickup_radius if weapon_data else 1.5
|
||||
pickup_collision.shape = sphere
|
||||
_pickup_area.add_child(pickup_collision)
|
||||
|
||||
func _on_body_entered_pickup_area(body: Node3D):
|
||||
if _is_being_picked_up:
|
||||
return
|
||||
|
||||
# Check if it's a player trying to pick up
|
||||
if body is Character and body.is_multiplayer_authority():
|
||||
# Let the player handle the pickup
|
||||
# The player will call try_pickup() via RPC
|
||||
pass
|
||||
|
||||
## Called by player to attempt pickup
|
||||
@rpc("any_peer", "reliable")
|
||||
func try_pickup(player_id: int):
|
||||
# Only server validates pickup
|
||||
if not multiplayer.is_server():
|
||||
return
|
||||
|
||||
if _is_being_picked_up:
|
||||
return
|
||||
|
||||
# Find the player
|
||||
var level = get_tree().get_current_scene()
|
||||
if not level or not level.has_node("PlayersContainer"):
|
||||
return
|
||||
|
||||
var players_container = level.get_node("PlayersContainer")
|
||||
if not players_container.has_node(str(player_id)):
|
||||
return
|
||||
|
||||
var player = players_container.get_node(str(player_id))
|
||||
if not player is Character:
|
||||
return
|
||||
|
||||
# Check distance
|
||||
var distance = global_position.distance_to(player.global_position)
|
||||
if distance > (weapon_data.pickup_radius if weapon_data else 1.5):
|
||||
return
|
||||
|
||||
_is_being_picked_up = true
|
||||
|
||||
# Get the resource path
|
||||
var resource_path = weapon_data.resource_path
|
||||
if resource_path == "":
|
||||
push_error("WeaponData has no resource path!")
|
||||
return
|
||||
|
||||
# Tell the player to equip this weapon (on all clients)
|
||||
player.rpc("equip_weapon_from_world", resource_path)
|
||||
|
||||
# Remove this world weapon from all clients
|
||||
rpc("_remove_from_all_clients")
|
||||
|
||||
## Remove weapon from all clients
|
||||
@rpc("any_peer", "call_local", "reliable")
|
||||
func _remove_from_all_clients():
|
||||
queue_free()
|
||||
|
||||
## Set weapon data and refresh
|
||||
func set_weapon_data(data: WeaponData):
|
||||
weapon_data = data
|
||||
if is_inside_tree():
|
||||
_spawn_mesh()
|
||||
if weapon_data:
|
||||
mass = weapon_data.weight
|
||||
Reference in New Issue
Block a user