feat: implement player movement controller and initial weapon framework including double barrel shotgun and explosive projectiles

This commit is contained in:
DottsGit
2026-06-06 21:09:40 -04:00
parent 54dfd342c2
commit 30dbf7a4cd
3 changed files with 37 additions and 15 deletions
+23 -3
View File
@@ -252,6 +252,13 @@ func apply_impulse(force: Vector3) -> void:
# Tiny upward bump helps move_and_slide detach from the floor
global_position.y += 0.1
@rpc("any_peer", "call_local", "reliable")
func server_apply_impulse(force: Vector3) -> void:
if not multiplayer.is_server(): return
var sender = multiplayer.get_remote_sender_id()
if sender != 1 and sender != str(name).to_int(): return
apply_impulse(force)
func take_damage(amount: float, _hit_pos: Vector3, _source: Node3D = null, impulse: Vector3 = Vector3.ZERO) -> void:
var attacker_id = 0
var weapon_name = "Killed"
@@ -454,6 +461,10 @@ func rpc_play_explosion(pos: Vector3, radius: float) -> void:
@rpc("any_peer", "call_local", "reliable")
func server_take_damage(amount: float, hit_pos: Vector3, attacker_id: int, weapon_name: String, impulse: Vector3) -> void:
if not multiplayer.is_server(): return
if impulse.length_squared() > 0.01:
apply_impulse(impulse)
# Broadcast damage event to all peers so the victim dies on all screens
rpc_take_damage.rpc(amount, hit_pos, attacker_id, weapon_name, impulse)
@@ -507,8 +518,17 @@ func rpc_take_damage(amount: float, hit_pos: Vector3, attacker_id: int, weapon_n
if aid != killer_id and now - recent_attackers[aid] <= 10.0:
assist_ids.append(aid)
var real_victim_name = "Player " + str(name)
if "player_name" in self and self.player_name != "":
real_victim_name = self.player_name
elif str(name).to_int() == 1:
real_victim_name = "Host"
if nm.has_method("register_kill"):
nm.register_kill.rpc(-1, killer_id, weapon_name, self.name, assist_ids)
var victim_id = str(name).to_int()
if victim_id == 0:
victim_id = 1 # Fallback to host if something is weird
nm.register_kill.rpc(victim_id, killer_id, weapon_name, real_victim_name, assist_ids)
func _show_damage_indicator(hit_pos: Vector3) -> void:
if not _damage_layer: return
@@ -953,8 +973,8 @@ func die(impulse: Vector3 = Vector3.ZERO) -> void:
death_screen.visible = true
set_process_input(true)
func _apply_ragdoll_velocity(ragdoll: Node3D, l_vel: Vector3, imp: Vector3) -> void:
if is_instance_valid(ragdoll):
func _apply_ragdoll_velocity(ragdoll, l_vel: Vector3, imp: Vector3) -> void:
if is_instance_valid(ragdoll) and ragdoll.has_method("apply_initial_velocities"):
ragdoll.apply_initial_velocities(l_vel, imp)
func _input(event: InputEvent) -> void:
+5 -6
View File
@@ -146,12 +146,11 @@ func _apply_impulse() -> void:
var push_dir = camera.global_transform.basis.z.normalized()
# Apply impulse to player velocity
player.velocity += push_dir * impulse_strength
# Small hack to ensure we aren't considered on floor if we shoot down
if push_dir.y > 0:
# Just slightly lift the player to break floor contact immediately
player.position.y += 0.05
var final_force = push_dir * impulse_strength
if multiplayer.has_multiplayer_peer() and multiplayer.multiplayer_peer is not OfflineMultiplayerPeer:
player.server_apply_impulse.rpc_id(1, final_force)
else:
player.apply_impulse(final_force)
func _play_muzzle_flash() -> void:
if muzzle_flash:
+9 -6
View File
@@ -191,16 +191,19 @@ func _explode(pos: Vector3) -> void:
# Add a tiny bit of upward bias to knockback so it lifts them
dir = (dir + Vector3(0, 0.5, 0)).normalized()
# Apply knockback if it has apply_impulse
if col.has_method("apply_impulse"):
col.apply_impulse(dir * final_knockback)
# Apply knockback if it has server_apply_impulse (for rocket jumping)
if col.has_method("server_apply_impulse") and col == owner_player:
if multiplayer.has_multiplayer_peer() and multiplayer.multiplayer_peer is not OfflineMultiplayerPeer:
col.server_apply_impulse.rpc_id(1, dir * final_knockback)
else:
col.apply_impulse(dir * final_knockback)
# Apply damage
# Apply damage (and knockback for other players via take_damage)
if col.has_method("take_damage"):
if col == owner_player and not can_self_damage:
# Skip self damage, but we still applied the knockback!
# Skip self damage (we already applied knockback above)
pass
elif owner_player and owner_player.multiplayer.is_server():
elif owner_player:
col.take_damage(final_damage, target_pos, owner_player, dir * final_knockback)
# Broadcast Visual Explosion Effect to other peers