First Commit
Base multiplayer example with obster
This commit is contained in:
@@ -0,0 +1,348 @@
|
||||
[gd_scene load_steps=17 format=3 uid="uid://dugaivbj1o66n"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://d0dgljwwl463n" path="res://level/scripts/level.gd" id="1_e1sh7"]
|
||||
[ext_resource type="PackedScene" uid="uid://cffjduipbb3s5" path="res://level/scenes/player.tscn" id="1_uvcbi"]
|
||||
[ext_resource type="FontFile" uid="uid://diapabmalpcrj" path="res://assets/fonts/Kurland.ttf" id="3_icc4p"]
|
||||
|
||||
[sub_resource type="PlaneMesh" id="PlaneMesh_r5xs5"]
|
||||
size = Vector2(90, 90)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_o02aj"]
|
||||
albedo_color = Color(0, 0.321569, 0.172549, 1)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_x3h1o"]
|
||||
size = Vector3(90, 0.05, 90)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_lc35d"]
|
||||
albedo_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_8pl0k"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_f43m5"]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_womqi"]
|
||||
albedo_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_taagp"]
|
||||
albedo_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_q5fs2"]
|
||||
size = Vector3(25, 1, 1.5)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_fs7ud"]
|
||||
albedo_color = Color(0, 0, 0, 1)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_epsao"]
|
||||
size = Vector3(25, 1, 1.5)
|
||||
|
||||
[sub_resource type="Environment" id="Environment_qb4jd"]
|
||||
fog_enabled = true
|
||||
|
||||
[sub_resource type="StyleBoxLine" id="StyleBoxLine_npnbc"]
|
||||
color = Color(0, 0, 0, 0)
|
||||
|
||||
[node name="Level" type="Node3D"]
|
||||
script = ExtResource("1_e1sh7")
|
||||
player_scene = ExtResource("1_uvcbi")
|
||||
|
||||
[node name="Environment" type="Node3D" parent="."]
|
||||
|
||||
[node name="Floor" type="StaticBody3D" parent="Environment"]
|
||||
collision_layer = 2
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Environment/Floor"]
|
||||
mesh = SubResource("PlaneMesh_r5xs5")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_o02aj")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Environment/Floor"]
|
||||
shape = SubResource("BoxShape3D_x3h1o")
|
||||
|
||||
[node name="Box_1" type="StaticBody3D" parent="Environment"]
|
||||
collision_layer = 2
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Environment/Box_1"]
|
||||
transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, 2.91206, 0.456, 6.91607)
|
||||
material_override = SubResource("StandardMaterial3D_lc35d")
|
||||
mesh = SubResource("BoxMesh_8pl0k")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Environment/Box_1"]
|
||||
transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, 2.91167, 0.456274, 6.91607)
|
||||
shape = SubResource("BoxShape3D_f43m5")
|
||||
|
||||
[node name="Box_2" type="StaticBody3D" parent="Environment"]
|
||||
collision_layer = 2
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Environment/Box_2"]
|
||||
transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, 2.91206, 2.456, 9.916)
|
||||
mesh = SubResource("BoxMesh_8pl0k")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_womqi")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Environment/Box_2"]
|
||||
transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, 2.91167, 2.456, 9.916)
|
||||
shape = SubResource("BoxShape3D_f43m5")
|
||||
|
||||
[node name="Box_3" type="StaticBody3D" parent="Environment"]
|
||||
collision_layer = 2
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Environment/Box_3"]
|
||||
transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, 2.91206, 4.456, 12.916)
|
||||
mesh = SubResource("BoxMesh_8pl0k")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_taagp")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Environment/Box_3"]
|
||||
transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, 2.91167, 4.456, 12.916)
|
||||
shape = SubResource("BoxShape3D_f43m5")
|
||||
|
||||
[node name="Box_4" type="StaticBody3D" parent="Environment"]
|
||||
transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, 0, 0, 0)
|
||||
collision_layer = 2
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Environment/Box_4"]
|
||||
transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, -3.52997, 5.947, 17.398)
|
||||
layers = 2
|
||||
mesh = SubResource("BoxMesh_q5fs2")
|
||||
surface_material_override/0 = SubResource("StandardMaterial3D_fs7ud")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Environment/Box_4"]
|
||||
transform = Transform3D(0.9, 0, 0, 0, 0.9, 0, 0, 0, 0.9, -3.52997, 5.947, 17.398)
|
||||
shape = SubResource("BoxShape3D_epsao")
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="Environment"]
|
||||
environment = SubResource("Environment_qb4jd")
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Environment"]
|
||||
transform = Transform3D(1, 0, 0, 0, -0.5, 0.866025, 0, -0.866025, -0.5, 0, 4, 0)
|
||||
shadow_enabled = true
|
||||
shadow_blur = 0.5
|
||||
|
||||
[node name="Menu" type="Control" parent="."]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="Menu"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
color = Color(0.0901961, 0.0901961, 0.0901961, 1)
|
||||
|
||||
[node name="MainContainer" type="VBoxContainer" parent="Menu"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 14
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 0.5
|
||||
offset_top = -257.0
|
||||
offset_bottom = 257.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 50
|
||||
alignment = 1
|
||||
|
||||
[node name="Label" type="Label" parent="Menu/MainContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 6
|
||||
size_flags_vertical = 0
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
theme_override_font_sizes/font_size = 70
|
||||
text = "Multiplayer Template"
|
||||
|
||||
[node name="MainMenu" type="VBoxContainer" parent="Menu/MainContainer"]
|
||||
layout_direction = 1
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
theme_override_constants/separation = 20
|
||||
alignment = 1
|
||||
|
||||
[node name="HSeparator1" type="HSeparator" parent="Menu/MainContainer/MainMenu"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 10
|
||||
theme_override_styles/separator = SubResource("StyleBoxLine_npnbc")
|
||||
|
||||
[node name="Option1" type="HBoxContainer" parent="Menu/MainContainer/MainMenu"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
alignment = 1
|
||||
|
||||
[node name="Label" type="Label" parent="Menu/MainContainer/MainMenu/Option1"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
theme_override_font_sizes/font_size = 35
|
||||
text = "Nickname : "
|
||||
|
||||
[node name="NickInput" type="LineEdit" parent="Menu/MainContainer/MainMenu/Option1"]
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
theme_override_font_sizes/font_size = 35
|
||||
placeholder_text = "YourNick"
|
||||
max_length = 20
|
||||
expand_to_text_length = true
|
||||
|
||||
[node name="Option2" type="HBoxContainer" parent="Menu/MainContainer/MainMenu"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 4
|
||||
alignment = 1
|
||||
|
||||
[node name="Label" type="Label" parent="Menu/MainContainer/MainMenu/Option2"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
theme_override_font_sizes/font_size = 35
|
||||
text = "Player Skin : "
|
||||
|
||||
[node name="SkinInput" type="LineEdit" parent="Menu/MainContainer/MainMenu/Option2"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
theme_override_font_sizes/font_size = 35
|
||||
placeholder_text = "blue"
|
||||
alignment = 1
|
||||
expand_to_text_length = true
|
||||
|
||||
[node name="Option3" type="HBoxContainer" parent="Menu/MainContainer/MainMenu"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
alignment = 1
|
||||
|
||||
[node name="Label" type="Label" parent="Menu/MainContainer/MainMenu/Option3"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
theme_override_font_sizes/font_size = 35
|
||||
text = "IP Address : "
|
||||
|
||||
[node name="AddressInput" type="LineEdit" parent="Menu/MainContainer/MainMenu/Option3"]
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
theme_override_font_sizes/font_size = 35
|
||||
placeholder_text = "127.0.0.1"
|
||||
alignment = 1
|
||||
expand_to_text_length = true
|
||||
|
||||
[node name="HSeparator2" type="HSeparator" parent="Menu/MainContainer/MainMenu"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 30
|
||||
theme_override_styles/separator = SubResource("StyleBoxLine_npnbc")
|
||||
|
||||
[node name="Buttons" type="HBoxContainer" parent="Menu/MainContainer/MainMenu"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 30
|
||||
alignment = 1
|
||||
|
||||
[node name="Host" type="Button" parent="Menu/MainContainer/MainMenu/Buttons"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_hover_color = Color(0, 0.52549, 0, 1)
|
||||
theme_override_colors/font_pressed_color = Color(0, 0.52549, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
theme_override_font_sizes/font_size = 35
|
||||
text = "HOST"
|
||||
flat = true
|
||||
|
||||
[node name="Join" type="Button" parent="Menu/MainContainer/MainMenu/Buttons"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_hover_color = Color(0, 0.525257, 0, 1)
|
||||
theme_override_colors/font_pressed_color = Color(0, 0.52549, 0, 1)
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
theme_override_font_sizes/font_size = 35
|
||||
text = "JOIN"
|
||||
flat = true
|
||||
|
||||
[node name="Option4" type="HBoxContainer" parent="Menu/MainContainer/MainMenu"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
alignment = 1
|
||||
|
||||
[node name="Quit" type="Button" parent="Menu/MainContainer/MainMenu/Option4"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_hover_color = Color(0.858807, 4.71681e-06, 1.15514e-06, 0.862745)
|
||||
theme_override_colors/font_pressed_color = Color(0.858824, 0, 0, 0.862745)
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
theme_override_font_sizes/font_size = 35
|
||||
text = "QUIT"
|
||||
flat = true
|
||||
|
||||
[node name="MultiplayerChat" type="Control" parent="."]
|
||||
visible = false
|
||||
top_level = true
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 16.0
|
||||
offset_top = 16.0
|
||||
offset_right = -764.0
|
||||
offset_bottom = -254.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MultiplayerChat"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
alignment = 1
|
||||
|
||||
[node name="Chat" type="TextEdit" parent="MultiplayerChat/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
text = "
|
||||
"
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="MultiplayerChat/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Message" type="LineEdit" parent="MultiplayerChat/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 4
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
|
||||
[node name="Send" type="Button" parent="MultiplayerChat/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
text = "Send"
|
||||
|
||||
[node name="ChatTitle" type="Label" parent="MultiplayerChat"]
|
||||
top_level = true
|
||||
layout_mode = 2
|
||||
anchor_right = 1.0
|
||||
offset_top = 16.0
|
||||
offset_right = -764.0
|
||||
offset_bottom = 34.0
|
||||
grow_horizontal = 2
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 6
|
||||
theme_override_fonts/font = ExtResource("3_icc4p")
|
||||
text = "Welcome to Global Chat!"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
uppercase = true
|
||||
|
||||
[node name="PlayersContainer" type="Node3D" parent="."]
|
||||
|
||||
[node name="GameControls" type="Control" parent="."]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
offset_right = 40.0
|
||||
offset_bottom = 40.0
|
||||
|
||||
[connection signal="pressed" from="Menu/MainContainer/MainMenu/Buttons/Host" to="." method="_on_host_pressed"]
|
||||
[connection signal="pressed" from="Menu/MainContainer/MainMenu/Buttons/Join" to="." method="_on_join_pressed"]
|
||||
[connection signal="pressed" from="Menu/MainContainer/MainMenu/Option4/Quit" to="." method="_on_quit_pressed"]
|
||||
[connection signal="pressed" from="MultiplayerChat/VBoxContainer/HBoxContainer/Send" to="." method="_on_send_pressed"]
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,36 @@
|
||||
extends Node3D
|
||||
class_name Body
|
||||
|
||||
const LERP_VELOCITY: float = 0.15
|
||||
|
||||
@export_category("Objects")
|
||||
@export var _character: CharacterBody3D = null
|
||||
@export var animation_player: AnimationPlayer = null
|
||||
|
||||
func apply_rotation(_velocity: Vector3) -> void:
|
||||
var new_rotation_y = lerp_angle(rotation.y, atan2(-_velocity.x, -_velocity.z), LERP_VELOCITY)
|
||||
rotation.y = new_rotation_y
|
||||
|
||||
# rpc("sync_player_rotation", new_rotation_y)
|
||||
|
||||
func animate(_velocity: Vector3) -> void:
|
||||
if not _character.is_on_floor():
|
||||
if _velocity.y < 0:
|
||||
animation_player.play("Fall")
|
||||
else:
|
||||
animation_player.play("Jump")
|
||||
return
|
||||
|
||||
if _velocity:
|
||||
if _character.is_running() and _character.is_on_floor():
|
||||
animation_player.play("Sprint")
|
||||
return
|
||||
|
||||
animation_player.play("Run")
|
||||
return
|
||||
|
||||
animation_player.play("Idle")
|
||||
|
||||
# @rpc("any_peer", "reliable")
|
||||
# func sync_player_rotation(rotation_y: float) -> void:
|
||||
# rotation.y = rotation_y
|
||||
@@ -0,0 +1 @@
|
||||
uid://v8j54rbc0ik
|
||||
@@ -0,0 +1,123 @@
|
||||
extends Node3D
|
||||
|
||||
@onready var skin_input: LineEdit = $Menu/MainContainer/MainMenu/Option2/SkinInput
|
||||
@onready var nick_input: LineEdit = $Menu/MainContainer/MainMenu/Option1/NickInput
|
||||
@onready var address_input: LineEdit = $Menu/MainContainer/MainMenu/Option3/AddressInput
|
||||
@onready var players_container: Node3D = $PlayersContainer
|
||||
@onready var menu: Control = $Menu
|
||||
@export var player_scene: PackedScene
|
||||
|
||||
# multiplayer chat
|
||||
@onready var message: LineEdit = $MultiplayerChat/VBoxContainer/HBoxContainer/Message
|
||||
@onready var send: Button = $MultiplayerChat/VBoxContainer/HBoxContainer/Send
|
||||
@onready var chat: TextEdit = $MultiplayerChat/VBoxContainer/Chat
|
||||
@onready var multiplayer_chat: Control = $MultiplayerChat
|
||||
|
||||
var chat_visible = false
|
||||
|
||||
func _ready():
|
||||
multiplayer_chat.hide()
|
||||
menu.show()
|
||||
multiplayer_chat.set_process_input(true)
|
||||
if not multiplayer.is_server():
|
||||
return
|
||||
|
||||
Network.connect("player_connected", Callable(self, "_on_player_connected"))
|
||||
multiplayer.peer_disconnected.connect(_remove_player)
|
||||
|
||||
func _on_player_connected(peer_id, player_info):
|
||||
# for id in Network.players.keys():
|
||||
# var player_data = Network.players[id]
|
||||
# if id != peer_id:
|
||||
# rpc_id(peer_id, "sync_player_skin", id, player_data["skin"])
|
||||
|
||||
_add_player(peer_id, player_info)
|
||||
|
||||
func _on_host_pressed():
|
||||
menu.hide()
|
||||
Network.start_host(nick_input.text.strip_edges(), skin_input.text.strip_edges().to_lower())
|
||||
|
||||
func _on_join_pressed():
|
||||
menu.hide()
|
||||
Network.join_game(nick_input.text.strip_edges(), skin_input.text.strip_edges().to_lower(), address_input.text.strip_edges())
|
||||
|
||||
func _add_player(id: int, player_info : Dictionary):
|
||||
if players_container.has_node(str(id)):
|
||||
return
|
||||
var player = player_scene.instantiate()
|
||||
player.name = str(id)
|
||||
player.position = get_spawn_point()
|
||||
players_container.add_child(player, true)
|
||||
|
||||
var nick = Network.players[id]["nick"]
|
||||
player.nickname.text = nick
|
||||
# player.rpc("change_nick", nick)
|
||||
|
||||
var skin_enum = player_info["skin"]
|
||||
player.set_player_skin(skin_enum)
|
||||
# rpc("sync_player_skin", id, skin_enum)
|
||||
|
||||
# rpc("sync_player_position", id, player.position)
|
||||
|
||||
func get_spawn_point() -> Vector3:
|
||||
var spawn_point = Vector2.from_angle(randf() * 2 * PI) * 10 # spawn radius
|
||||
return Vector3(spawn_point.x, 0, spawn_point.y)
|
||||
|
||||
func _remove_player(id):
|
||||
if not multiplayer.is_server() or not players_container.has_node(str(id)):
|
||||
return
|
||||
var player_node = players_container.get_node(str(id))
|
||||
if player_node:
|
||||
player_node.queue_free()
|
||||
|
||||
# @rpc("any_peer", "call_local")
|
||||
# func sync_player_position(id: int, new_position: Vector3):
|
||||
# var player = players_container.get_node(str(id))
|
||||
# if player:
|
||||
# player.position = new_position
|
||||
|
||||
# @rpc("any_peer", "call_local")
|
||||
# func sync_player_skin(id: int, skin_color: Character.SkinColor):
|
||||
# var player = players_container.get_node(str(id))
|
||||
# if player:
|
||||
# player.set_player_skin(skin_color)
|
||||
|
||||
func _on_quit_pressed() -> void:
|
||||
get_tree().quit()
|
||||
|
||||
# ---------- MULTIPLAYER CHAT ----------
|
||||
func toggle_chat():
|
||||
if menu.visible:
|
||||
return
|
||||
|
||||
chat_visible = !chat_visible
|
||||
if chat_visible:
|
||||
multiplayer_chat.show()
|
||||
message.grab_focus()
|
||||
else:
|
||||
multiplayer_chat.hide()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
func is_chat_visible() -> bool:
|
||||
return chat_visible
|
||||
|
||||
func _input(event):
|
||||
if event.is_action_pressed("toggle_chat"):
|
||||
toggle_chat()
|
||||
elif event is InputEventKey and event.keycode == KEY_ENTER:
|
||||
_on_send_pressed()
|
||||
|
||||
func _on_send_pressed() -> void:
|
||||
var trimmed_message = message.text.strip_edges()
|
||||
if trimmed_message == "":
|
||||
return # do not send empty messages
|
||||
|
||||
var nick = Network.players[multiplayer.get_unique_id()]["nick"]
|
||||
|
||||
rpc("msg_rpc", nick, trimmed_message)
|
||||
message.text = ""
|
||||
message.grab_focus()
|
||||
|
||||
@rpc("any_peer", "call_local")
|
||||
func msg_rpc(nick, msg):
|
||||
chat.text += str(nick, " : ", msg, "\n")
|
||||
@@ -0,0 +1 @@
|
||||
uid://d0dgljwwl463n
|
||||
@@ -0,0 +1,90 @@
|
||||
extends Node
|
||||
|
||||
const SERVER_ADDRESS: String = "127.0.0.1"
|
||||
const SERVER_PORT: int = 8080
|
||||
const MAX_PLAYERS : int = 10
|
||||
|
||||
var players = {}
|
||||
var player_info = {
|
||||
"nick" : "host",
|
||||
"skin" : Character.SkinColor.BLUE
|
||||
}
|
||||
|
||||
signal player_connected(peer_id, player_info)
|
||||
signal server_disconnected
|
||||
|
||||
func _process(_delta):
|
||||
if Input.is_action_just_pressed("quit"):
|
||||
get_tree().quit(0)
|
||||
|
||||
func _ready() -> void:
|
||||
multiplayer.server_disconnected.connect(_on_connection_failed)
|
||||
multiplayer.connection_failed.connect(_on_server_disconnected)
|
||||
multiplayer.peer_disconnected.connect(_on_player_disconnected)
|
||||
multiplayer.peer_connected.connect(_on_player_connected)
|
||||
multiplayer.connected_to_server.connect(_on_connected_ok)
|
||||
|
||||
func start_host(nickname: String, skin_color_str: String):
|
||||
var peer = ENetMultiplayerPeer.new()
|
||||
var error = peer.create_server(SERVER_PORT, MAX_PLAYERS)
|
||||
if error:
|
||||
return error
|
||||
multiplayer.multiplayer_peer = peer
|
||||
|
||||
if !nickname or nickname.strip_edges() == "":
|
||||
nickname = "Host_" + str(1)
|
||||
|
||||
player_info["nick"] = nickname
|
||||
player_info["skin"] = skin_str_to_e(skin_color_str)
|
||||
players[1] = player_info
|
||||
player_connected.emit(1, player_info)
|
||||
|
||||
func join_game(nickname: String, skin_color_str: String, address: String = SERVER_ADDRESS):
|
||||
var peer = ENetMultiplayerPeer.new()
|
||||
var error = peer.create_client(address, SERVER_PORT)
|
||||
if error:
|
||||
return error
|
||||
|
||||
multiplayer.multiplayer_peer = peer
|
||||
|
||||
if !nickname or nickname.strip_edges() == "":
|
||||
nickname = "Player_" + str(multiplayer.get_unique_id())
|
||||
|
||||
var skin_enum = skin_str_to_e(skin_color_str)
|
||||
|
||||
player_info["nick"] = nickname
|
||||
player_info["skin"] = skin_enum
|
||||
|
||||
func _on_connected_ok():
|
||||
var peer_id = multiplayer.get_unique_id()
|
||||
players[peer_id] = player_info
|
||||
player_connected.emit(peer_id, player_info)
|
||||
|
||||
func _on_player_connected(id):
|
||||
_register_player.rpc_id(id, player_info)
|
||||
|
||||
@rpc("any_peer", "reliable")
|
||||
func _register_player(new_player_info):
|
||||
var new_player_id = multiplayer.get_remote_sender_id()
|
||||
players[new_player_id] = new_player_info
|
||||
player_connected.emit(new_player_id, new_player_info)
|
||||
#print("debug function _register_player on Network.gd: ", players, "\n")
|
||||
|
||||
func _on_player_disconnected(id):
|
||||
players.erase(id)
|
||||
|
||||
func _on_connection_failed():
|
||||
multiplayer.multiplayer_peer = null
|
||||
|
||||
func _on_server_disconnected():
|
||||
multiplayer.multiplayer_peer = null
|
||||
players.clear()
|
||||
server_disconnected.emit()
|
||||
|
||||
func skin_str_to_e(s):
|
||||
match s.to_lower():
|
||||
"blue": return Character.SkinColor.BLUE
|
||||
"yellow": return Character.SkinColor.YELLOW
|
||||
"green": return Character.SkinColor.GREEN
|
||||
"red": return Character.SkinColor.RED
|
||||
_: return Character.SkinColor.BLUE
|
||||
@@ -0,0 +1 @@
|
||||
uid://cedubc87s78fo
|
||||
@@ -0,0 +1,136 @@
|
||||
extends CharacterBody3D
|
||||
class_name Character
|
||||
|
||||
const NORMAL_SPEED = 6.0
|
||||
const SPRINT_SPEED = 10.0
|
||||
const JUMP_VELOCITY = 10
|
||||
|
||||
enum SkinColor { BLUE, YELLOW, GREEN, RED }
|
||||
|
||||
@onready var nickname: Label3D = $PlayerNick/Nickname
|
||||
|
||||
@export_category("Objects")
|
||||
@export var _body: Node3D = null
|
||||
@export var _spring_arm_offset: Node3D = null
|
||||
|
||||
@export_category("Skin Colors")
|
||||
@export var blue_texture : CompressedTexture2D
|
||||
@export var yellow_texture : CompressedTexture2D
|
||||
@export var green_texture : CompressedTexture2D
|
||||
@export var red_texture : CompressedTexture2D
|
||||
|
||||
@onready var _bottom_mesh: MeshInstance3D = get_node("3DGodotRobot/RobotArmature/Skeleton3D/Bottom")
|
||||
@onready var _chest_mesh: MeshInstance3D = get_node("3DGodotRobot/RobotArmature/Skeleton3D/Chest")
|
||||
@onready var _face_mesh: MeshInstance3D = get_node("3DGodotRobot/RobotArmature/Skeleton3D/Face")
|
||||
@onready var _limbs_head_mesh: MeshInstance3D = get_node("3DGodotRobot/RobotArmature/Skeleton3D/Llimbs and head")
|
||||
|
||||
var _current_speed: float
|
||||
var _respawn_point = Vector3(0, 5, 0)
|
||||
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||
|
||||
func _enter_tree():
|
||||
set_multiplayer_authority(str(name).to_int())
|
||||
$SpringArmOffset/SpringArm3D/Camera3D.current = is_multiplayer_authority()
|
||||
|
||||
func _ready():
|
||||
return
|
||||
|
||||
func _physics_process(delta):
|
||||
if not is_multiplayer_authority(): return
|
||||
|
||||
var current_scene = get_tree().get_current_scene()
|
||||
if current_scene and current_scene.has_method("is_chat_visible") and current_scene.is_chat_visible() and is_on_floor():
|
||||
freeze()
|
||||
return
|
||||
|
||||
if not is_on_floor():
|
||||
velocity.y -= gravity * delta
|
||||
_body.animate(velocity)
|
||||
|
||||
if is_on_floor():
|
||||
if Input.is_action_just_pressed("jump"):
|
||||
velocity.y = JUMP_VELOCITY
|
||||
else:
|
||||
velocity.y -= gravity * delta
|
||||
|
||||
_move()
|
||||
move_and_slide()
|
||||
_body.animate(velocity)
|
||||
|
||||
func _process(_delta):
|
||||
if not is_multiplayer_authority(): return
|
||||
_check_fall_and_respawn()
|
||||
|
||||
func freeze():
|
||||
velocity.x = 0
|
||||
velocity.z = 0
|
||||
_current_speed = 0
|
||||
_body.animate(Vector3.ZERO)
|
||||
|
||||
func _move() -> void:
|
||||
var _input_direction: Vector2 = Vector2.ZERO
|
||||
if is_multiplayer_authority():
|
||||
_input_direction = Input.get_vector(
|
||||
"move_left", "move_right",
|
||||
"move_forward", "move_backward"
|
||||
)
|
||||
|
||||
var _direction: Vector3 = transform.basis * Vector3(_input_direction.x, 0, _input_direction.y).normalized()
|
||||
|
||||
is_running()
|
||||
_direction = _direction.rotated(Vector3.UP, _spring_arm_offset.rotation.y)
|
||||
|
||||
if _direction:
|
||||
velocity.x = _direction.x * _current_speed
|
||||
velocity.z = _direction.z * _current_speed
|
||||
_body.apply_rotation(velocity)
|
||||
return
|
||||
|
||||
velocity.x = move_toward(velocity.x, 0, _current_speed)
|
||||
velocity.z = move_toward(velocity.z, 0, _current_speed)
|
||||
|
||||
func is_running() -> bool:
|
||||
if Input.is_action_pressed("shift"):
|
||||
_current_speed = SPRINT_SPEED
|
||||
return true
|
||||
else:
|
||||
_current_speed = NORMAL_SPEED
|
||||
return false
|
||||
|
||||
func _check_fall_and_respawn():
|
||||
if global_transform.origin.y < -15.0:
|
||||
_respawn()
|
||||
|
||||
func _respawn():
|
||||
global_transform.origin = _respawn_point
|
||||
velocity = Vector3.ZERO
|
||||
|
||||
@rpc("any_peer", "reliable")
|
||||
func change_nick(new_nick: String):
|
||||
if nickname:
|
||||
nickname.text = new_nick
|
||||
|
||||
func get_texture_from_name(skin_color: SkinColor) -> CompressedTexture2D:
|
||||
match skin_color:
|
||||
SkinColor.BLUE: return blue_texture
|
||||
SkinColor.GREEN: return green_texture
|
||||
SkinColor.RED: return red_texture
|
||||
SkinColor.YELLOW: return yellow_texture
|
||||
_: return blue_texture
|
||||
|
||||
@rpc("any_peer", "reliable")
|
||||
func set_player_skin(skin_name: SkinColor) -> void:
|
||||
var texture = get_texture_from_name(skin_name)
|
||||
|
||||
set_mesh_texture(_bottom_mesh, texture)
|
||||
set_mesh_texture(_chest_mesh, texture)
|
||||
set_mesh_texture(_face_mesh, texture)
|
||||
set_mesh_texture(_limbs_head_mesh, texture)
|
||||
|
||||
func set_mesh_texture(mesh_instance: MeshInstance3D, texture: CompressedTexture2D) -> void:
|
||||
if mesh_instance:
|
||||
var material := mesh_instance.get_surface_override_material(0)
|
||||
if material and material is StandardMaterial3D:
|
||||
var new_material := material
|
||||
new_material.albedo_texture = texture
|
||||
mesh_instance.set_surface_override_material(0, new_material)
|
||||
@@ -0,0 +1 @@
|
||||
uid://c2si8gkbnde0c
|
||||
@@ -0,0 +1,14 @@
|
||||
extends Node3D
|
||||
class_name SpringArmCharacter
|
||||
|
||||
const MOUSE_SENSIBILITY: float = 0.005
|
||||
|
||||
@export_category("Objects")
|
||||
@export var _spring_arm: SpringArm3D = null
|
||||
|
||||
func _unhandled_input(_event) -> void:
|
||||
|
||||
if (_event is InputEventMouseMotion) and is_multiplayer_authority():
|
||||
rotate_y(-_event.relative.x * MOUSE_SENSIBILITY)
|
||||
_spring_arm.rotate_x(-_event.relative.y * MOUSE_SENSIBILITY)
|
||||
_spring_arm.rotation.x = clamp(_spring_arm.rotation.x, -PI/4, PI/24)
|
||||
@@ -0,0 +1 @@
|
||||
uid://bj7yrijm7bppq
|
||||
Reference in New Issue
Block a user