multiplayer

This commit is contained in:
Rendo 2025-11-22 01:07:18 +05:00
commit 0dc6247f91
22 changed files with 298 additions and 14 deletions

View file

@ -1,7 +1,7 @@
[gd_scene load_steps=5 format=3 uid="uid://cqrh2cc7m2i7f"] [gd_scene load_steps=5 format=3 uid="uid://cqrh2cc7m2i7f"]
[ext_resource type="Environment" uid="uid://d0cfgtx2yxw13" path="res://environments/prototype_environment.tres" id="1_i6jab"] [ext_resource type="Environment" uid="uid://d0cfgtx2yxw13" path="res://environments/prototype_environment.tres" id="1_i6jab"]
[ext_resource type="PackedScene" uid="uid://dpsr6ug3pkb40" path="res://scenes/player.tscn" id="2_ajphm"] [ext_resource type="Script" uid="uid://ypgm3aplt78m" path="res://scripts/multiplayer/player_spawner.gd" id="4_pi0y7"]
[ext_resource type="Material" uid="uid://bx3f5vx71ynh5" path="res://materials/OrangeMat.tres" id="4_y6i55"] [ext_resource type="Material" uid="uid://bx3f5vx71ynh5" path="res://materials/OrangeMat.tres" id="4_y6i55"]
[ext_resource type="Material" uid="uid://mlha6r17v2en" path="res://materials/Bluemat.tres" id="5_bno23"] [ext_resource type="Material" uid="uid://mlha6r17v2en" path="res://materials/Bluemat.tres" id="5_bno23"]
@ -14,11 +14,6 @@ shadow_enabled = true
[node name="WorldEnvironment" type="WorldEnvironment" parent="."] [node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = ExtResource("1_i6jab") environment = ExtResource("1_i6jab")
[node name="Player" parent="." instance=ExtResource("2_ajphm")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.073462, 1.5000002, -0.5869317)
SPEED = 10.0
TOGGLE_CROUCH = false
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="."] [node name="CSGCombiner3D" type="CSGCombiner3D" parent="."]
use_collision = true use_collision = true
@ -40,3 +35,11 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.49652505, 4.840562)
polygon = PackedVector2Array(0, 0, -0.061755046, 1.5814729, 2, 0) polygon = PackedVector2Array(0, 0, -0.061755046, 1.5814729, 2, 0)
depth = 2.45 depth = 2.45
material = ExtResource("5_bno23") material = ExtResource("5_bno23")
[node name="Spawner" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5862943, 0)
script = ExtResource("4_pi0y7")
[node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="."]
_spawnable_scenes = PackedStringArray("uid://dpsr6ug3pkb40")
spawn_path = NodePath("..")

View file

@ -11,13 +11,14 @@ config_version=5
[application] [application]
config/name="Chelimbalo" config/name="Chelimbalo"
run/main_scene="uid://cqrh2cc7m2i7f" run/main_scene="uid://cbtp4rvg66ba1"
config/features=PackedStringArray("4.5", "Forward Plus") config/features=PackedStringArray("4.5", "Forward Plus")
config/icon="res://icon.svg" config/icon="res://icon.svg"
[autoload] [autoload]
PlayerGlobal="*res://scripts/player/player_global.gd" PlayerGlobal="*res://scripts/player/player_global.gd"
Lobby="*res://scripts/multiplayer/lobby.gd"
[input] [input]

60
scenes/main_menu.tscn Normal file
View file

@ -0,0 +1,60 @@
[gd_scene load_steps=4 format=3 uid="uid://cbtp4rvg66ba1"]
[ext_resource type="Script" uid="uid://bsyuos803g7qf" path="res://scripts/gui/main_menu_gui.gd" id="1_l6cm7"]
[ext_resource type="Script" uid="uid://cl3hhmw5666sj" path="res://scripts/gui/lobby/players_display.gd" id="2_ekxnf"]
[ext_resource type="Script" uid="uid://2uyxkfmbbims" path="res://scripts/gui/lobby/lobby_buttons.gd" id="3_bqqt6"]
[node name="MainMenu" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_l6cm7")
[node name="MainMenu" type="PanelContainer" parent="."]
layout_mode = 0
offset_right = 40.0
offset_bottom = 40.0
[node name="VBoxContainer" type="VBoxContainer" parent="MainMenu"]
layout_mode = 2
[node name="HostButton" type="Button" parent="MainMenu/VBoxContainer"]
layout_mode = 2
text = "HOST"
[node name="ConnectButton" type="Button" parent="MainMenu/VBoxContainer"]
layout_mode = 2
text = "CONNECT"
[node name="Lobby" type="PanelContainer" parent="."]
visible = false
layout_mode = 0
offset_right = 305.0
offset_bottom = 242.0
[node name="VBoxContainer" type="VBoxContainer" parent="Lobby"]
layout_mode = 2
[node name="Players" type="HBoxContainer" parent="Lobby/VBoxContainer"]
layout_mode = 2
script = ExtResource("2_ekxnf")
[node name="Buttons" type="HBoxContainer" parent="Lobby/VBoxContainer"]
layout_mode = 2
script = ExtResource("3_bqqt6")
[node name="LeaveButton" type="Button" parent="Lobby/VBoxContainer/Buttons"]
layout_mode = 2
text = "Leave"
[node name="StartButton" type="Button" parent="Lobby/VBoxContainer/Buttons"]
layout_mode = 2
text = "Start"
[connection signal="pressed" from="MainMenu/VBoxContainer/HostButton" to="." method="_on_host_button_pressed"]
[connection signal="pressed" from="MainMenu/VBoxContainer/ConnectButton" to="." method="_on_connect_button_pressed"]
[connection signal="pressed" from="Lobby/VBoxContainer/Buttons/LeaveButton" to="Lobby/VBoxContainer/Buttons" method="_on_leave_button_pressed"]
[connection signal="pressed" from="Lobby/VBoxContainer/Buttons/StartButton" to="Lobby/VBoxContainer/Buttons" method="_on_start_button_pressed"]

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=10 format=3 uid="uid://dpsr6ug3pkb40"] [gd_scene load_steps=11 format=3 uid="uid://dpsr6ug3pkb40"]
[ext_resource type="Script" uid="uid://3dphlay25fih" path="res://scripts/player/player.gd" id="1_g2els"] [ext_resource type="Script" uid="uid://3dphlay25fih" path="res://scripts/player/player.gd" id="1_g2els"]
[ext_resource type="Script" uid="uid://dalwlndejfdhm" path="res://scripts/player/crosshair.gd" id="3_dqkch"] [ext_resource type="Script" uid="uid://dalwlndejfdhm" path="res://scripts/player/crosshair.gd" id="3_dqkch"]
@ -95,6 +95,21 @@ _data = {
} }
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_g2els"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_g2els"]
height = 1.2958984
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_qhqgy"]
properties/0/path = NodePath(".:position")
properties/0/spawn = true
properties/0/replication_mode = 1
properties/1/path = NodePath(".:rotation")
properties/1/spawn = true
properties/1/replication_mode = 1
properties/2/path = NodePath("Camera3D:rotation")
properties/2/spawn = true
properties/2/replication_mode = 1
properties/3/path = NodePath(".:crouched")
properties/3/spawn = true
properties/3/replication_mode = 1
[node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("animation_player", "stand_up_area")] [node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("animation_player", "stand_up_area")]
collision_layer = 2 collision_layer = 2
@ -122,7 +137,7 @@ libraries = {
collision_layer = 0 collision_layer = 0
[node name="CollisionShape3D" type="CollisionShape3D" parent="StandArea"] [node name="CollisionShape3D" type="CollisionShape3D" parent="StandArea"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.3520508, 0)
shape = SubResource("CapsuleShape3D_g2els") shape = SubResource("CapsuleShape3D_g2els")
debug_color = Color(0.9878064, 0, 0.31407458, 0.41960785) debug_color = Color(0.9878064, 0, 0.31407458, 0.41960785)
debug_fill = false debug_fill = false
@ -152,3 +167,6 @@ script = ExtResource("3_dqkch")
crosses_width = 2.0 crosses_width = 2.0
crosses_length = 6.0 crosses_length = 6.0
crosses_offset = 3.0 crosses_offset = 3.0
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
replication_config = SubResource("SceneReplicationConfig_qhqgy")

View file

@ -1,3 +1,49 @@
[gd_scene format=3 uid="uid://cheu6vds21er7"] [gd_scene load_steps=8 format=3 uid="uid://cheu6vds21er7"]
[node name="Smoke" type="RigidBody3D"] [ext_resource type="Script" uid="uid://t5jjqwnkxgvo" path="res://scripts/smoke_grenade.gd" id="1_acmqr"]
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_acmqr"]
bounce = 0.5
[sub_resource type="CapsuleMesh" id="CapsuleMesh_vb5ru"]
radius = 0.1
height = 0.5
[sub_resource type="FastNoiseLite" id="FastNoiseLite_acmqr"]
frequency = 0.1141
[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_rx0m8"]
width = 128
height = 128
depth = 128
noise = SubResource("FastNoiseLite_acmqr")
[sub_resource type="FogMaterial" id="FogMaterial_rx0m8"]
resource_local_to_scene = true
density = 8.0
density_texture = SubResource("NoiseTexture3D_rx0m8")
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_acmqr"]
radius = 0.1
height = 0.5
[node name="Smoke" type="RigidBody3D" node_paths=PackedStringArray("fog")]
physics_material_override = SubResource("PhysicsMaterial_acmqr")
contact_monitor = true
max_contacts_reported = 1
script = ExtResource("1_acmqr")
radius = 10.0
fog = NodePath("FogVolume")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("CapsuleMesh_vb5ru")
[node name="FogVolume" type="FogVolume" parent="."]
size = Vector3(0, 0, 0)
shape = 0
material = SubResource("FogMaterial_rx0m8")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("CapsuleShape3D_acmqr")
[connection signal="body_entered" from="." to="." method="_on_body_entered"]

View file

@ -0,0 +1,13 @@
extends Node
func _ready() -> void:
Lobby.lobby_joined.connect(on_lobby_joined)
func _on_leave_button_pressed() -> void:
Lobby.leave()
func _on_start_button_pressed() -> void:
Lobby.start_game.rpc()
func on_lobby_joined() -> void:
$StartButton.hide()

View file

@ -0,0 +1 @@
uid://2uyxkfmbbims

View file

@ -0,0 +1,28 @@
extends Node
func _ready() -> void:
multiplayer.peer_connected.connect(on_peer_connected)
multiplayer.peer_disconnected.connect(on_peer_disconnected)
Lobby.lobby_created.emit(add_self)
Lobby.lobby_joined.emit(add_self)
Lobby.lobby_closed.emit(clear)
func on_peer_connected(id: int) -> void:
var label = Label.new()
label.text = str(id)
label.name = str(id)
add_child(label,true)
func on_peer_disconnected(id: int) -> void:
get_node(str(id)).queue_free()
func add_self() -> void:
var label = Label.new()
label.text = str(multiplayer.get_unique_id())
label.name = str(multiplayer.get_unique_id())
add_child(label,true)
func clear() -> void:
for child in get_children():
child.queue_free()

View file

@ -0,0 +1 @@
uid://cl3hhmw5666sj

View file

@ -0,0 +1,14 @@
extends Node
func _on_host_button_pressed() -> void:
Lobby.host()
$MainMenu.hide()
$Lobby.show()
func _on_connect_button_pressed() -> void:
Lobby.join("localhost")
$MainMenu.hide()
$Lobby.show()

View file

@ -0,0 +1 @@
uid://bsyuos803g7qf

View file

@ -0,0 +1,7 @@
extends Node
func _ready() -> void:
if not multiplayer.is_server():
return
Lobby.add_loaded_player(multiplayer.get_unique_id())

View file

@ -0,0 +1 @@
uid://bdxy621fthtrv

View file

@ -0,0 +1,29 @@
extends Node
const MAX_PLAYERS: int = 10
const PORT: int = 7777
signal lobby_created
signal lobby_joined
signal lobby_closed
func host() -> void:
var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()
peer.create_server(PORT,MAX_PLAYERS)
multiplayer.multiplayer_peer = peer
lobby_created.emit()
func join(ip: String) -> void:
var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()
peer.create_client(ip,PORT)
multiplayer.multiplayer_peer = peer
lobby_joined.emit()
func leave() -> void:
multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new()
lobby_closed.emit()
@rpc("authority","call_local","reliable")
func start_game() -> void:
get_tree().change_scene_to_file("res://levels/prototype_scene.tscn")

View file

@ -0,0 +1 @@
uid://c5sfxrl7hky6p

View file

@ -0,0 +1,15 @@
extends Node3D
func _ready() -> void:
if not multiplayer.is_server():
return
spawn_player(multiplayer.get_unique_id())
for i in multiplayer.get_peers():
spawn_player(i)
func spawn_player(id) -> void:
var player: PackedScene = load("res://scenes/player.tscn")
var inst = player.instantiate()
inst.name = str(id)
get_tree().current_scene.add_child.call_deferred(inst,true)

View file

@ -0,0 +1 @@
uid://ypgm3aplt78m

View file

@ -14,7 +14,7 @@ extends Control
@export var crosses_color: Color = Color.WHITE @export var crosses_color: Color = Color.WHITE
func _draw() -> void: func _draw() -> void:
draw_circle(Vector2(0,0),dot_radius,dot_color,true,outline_width) draw_circle(Vector2(0,0),dot_radius,dot_color,false,outline_width)
for i in range(0,4): for i in range(0,4):
var direction: Vector2 = Vector2.RIGHT.rotated(i*PI/2) var direction: Vector2 = Vector2.RIGHT.rotated(i*PI/2)
var offset_position: Vector2 = direction * crosses_offset var offset_position: Vector2 = direction * crosses_offset

View file

@ -10,7 +10,7 @@ extends CharacterBody3D
@export var TOGGLE_CROUCH: bool = true @export var TOGGLE_CROUCH: bool = true
@export var WALK_MODIFIER: float = 0.5 @export var WALK_MODIFIER: float = 0.5
var crouched: bool = false: @export var crouched: bool = false:
set(value): set(value):
if value != crouched and stand_up_area.has_overlapping_bodies() == false: if value != crouched and stand_up_area.has_overlapping_bodies() == false:
crouched = value crouched = value
@ -22,11 +22,18 @@ var crouched: bool = false:
var potential_crouched: bool = crouched var potential_crouched: bool = crouched
func _enter_tree() -> void:
set_multiplayer_authority(str(name).to_int())
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
if not is_multiplayer_authority():
return
if potential_crouched != crouched: if potential_crouched != crouched:
crouched = potential_crouched crouched = potential_crouched
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
if not is_multiplayer_authority():
return
# Add the gravity. # Add the gravity.
if not is_on_floor(): if not is_on_floor():
velocity += get_gravity() * delta velocity += get_gravity() * delta
@ -55,6 +62,8 @@ func update_crouch():
animation_player.play("Crouch",-1,-1/CROUCH_TIME,true) animation_player.play("Crouch",-1,-1/CROUCH_TIME,true)
func _input(event: InputEvent) -> void: func _input(event: InputEvent) -> void:
if not is_multiplayer_authority():
return
if event.is_action_pressed("plr_crouch"): if event.is_action_pressed("plr_crouch"):
if TOGGLE_CROUCH: if TOGGLE_CROUCH:
crouched = not crouched crouched = not crouched
@ -62,3 +71,7 @@ func _input(event: InputEvent) -> void:
crouched = true crouched = true
elif event.is_action_released("plr_crouch") and TOGGLE_CROUCH == false: elif event.is_action_released("plr_crouch") and TOGGLE_CROUCH == false:
crouched = false crouched = false
if event.is_action_pressed("plr_drop"):
var grenade = preload("res://scenes/smoke.tscn").instantiate()
get_tree().current_scene.add_child(grenade)
grenade.global_position = global_position + Vector3.UP * 0.5

View file

@ -4,11 +4,19 @@ const COLLINEAR = 1.5707963267948966
@export var SENSITIVITY = 0.02 @export var SENSITIVITY = 0.02
func _enter_tree() -> void:
set_multiplayer_authority(get_parent().name.to_int())
func _ready() -> void: func _ready() -> void:
# Move to level controller when possible # Move to level controller when possible
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED #Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
if not is_multiplayer_authority():
return
current = true
func _input(event: InputEvent) -> void: func _input(event: InputEvent) -> void:
if not is_multiplayer_authority():
return
if event is InputEventMouseMotion: if event is InputEventMouseMotion:
get_parent().rotate_y(-event.relative.x * SENSITIVITY) get_parent().rotate_y(-event.relative.x * SENSITIVITY)
rotate_x(-event.relative.y * SENSITIVITY) rotate_x(-event.relative.y * SENSITIVITY)

22
scripts/smoke_grenade.gd Normal file
View file

@ -0,0 +1,22 @@
extends RigidBody3D
@export var radius: float
@export var fog: FogVolume
var bounce_count: int = 0
func _on_body_entered(_body: Node) -> void:
if bounce_count > 2:
return
bounce_count += 1
if bounce_count == 2:
smoke()
func smoke():
var tween = create_tween().set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_EXPO)
tween.tween_property(fog,"size",Vector3(radius,radius,radius),1.0)
tween.tween_interval(10)
tween.tween_property(fog.material,"density",0,1.0)
tween.tween_callback(queue_free)

View file

@ -0,0 +1 @@
uid://t5jjqwnkxgvo