awesome!!!
This commit is contained in:
commit
07577d3fd3
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
|
|
||||||
|
# Godot-specific ignores
|
||||||
|
.import/
|
||||||
|
export.cfg
|
||||||
|
export_presets.cfg
|
||||||
|
|
||||||
|
# Imported translations (automatically generated from CSV files)
|
||||||
|
*.translation
|
||||||
|
|
||||||
|
# Mono-specific ignores
|
||||||
|
.mono/
|
||||||
|
data_*/
|
||||||
|
mono_crash.*.json
|
BIN
assets/drop.png
Normal file
BIN
assets/drop.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 172 B |
34
assets/drop.png.import
Normal file
34
assets/drop.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cwbl0r1e26eja"
|
||||||
|
path="res://.godot/imported/drop.png-46e76e0a1a49ec3b9e6c8f19494b9486.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/drop.png"
|
||||||
|
dest_files=["res://.godot/imported/drop.png-46e76e0a1a49ec3b9e6c8f19494b9486.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
BIN
assets/sfx/boom.wav
Normal file
BIN
assets/sfx/boom.wav
Normal file
Binary file not shown.
24
assets/sfx/boom.wav.import
Normal file
24
assets/sfx/boom.wav.import
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://3dlhs18w1fa2"
|
||||||
|
path="res://.godot/imported/boom.wav-b7dc2436738b092118bc6a9ac139ed1b.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sfx/boom.wav"
|
||||||
|
dest_files=["res://.godot/imported/boom.wav-b7dc2436738b092118bc6a9ac139ed1b.sample"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
force/8_bit=false
|
||||||
|
force/mono=false
|
||||||
|
force/max_rate=false
|
||||||
|
force/max_rate_hz=44100
|
||||||
|
edit/trim=false
|
||||||
|
edit/normalize=false
|
||||||
|
edit/loop_mode=0
|
||||||
|
edit/loop_begin=0
|
||||||
|
edit/loop_end=-1
|
||||||
|
compress/mode=0
|
BIN
assets/sfx/splash-small-quiet.wav
Normal file
BIN
assets/sfx/splash-small-quiet.wav
Normal file
Binary file not shown.
24
assets/sfx/splash-small-quiet.wav.import
Normal file
24
assets/sfx/splash-small-quiet.wav.import
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://blgrl2wl05feq"
|
||||||
|
path="res://.godot/imported/splash-small-quiet.wav-5d79804a4ce6d654b376652fbb9b2033.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sfx/splash-small-quiet.wav"
|
||||||
|
dest_files=["res://.godot/imported/splash-small-quiet.wav-5d79804a4ce6d654b376652fbb9b2033.sample"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
force/8_bit=false
|
||||||
|
force/mono=false
|
||||||
|
force/max_rate=false
|
||||||
|
force/max_rate_hz=44100
|
||||||
|
edit/trim=false
|
||||||
|
edit/normalize=false
|
||||||
|
edit/loop_mode=0
|
||||||
|
edit/loop_begin=0
|
||||||
|
edit/loop_end=-1
|
||||||
|
compress/mode=0
|
BIN
assets/sfx/splash-small.wav
Normal file
BIN
assets/sfx/splash-small.wav
Normal file
Binary file not shown.
24
assets/sfx/splash-small.wav.import
Normal file
24
assets/sfx/splash-small.wav.import
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://dtjpv2b74g24m"
|
||||||
|
path="res://.godot/imported/splash-small.wav-395e6cb2278f19594f3004dfba45fa36.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sfx/splash-small.wav"
|
||||||
|
dest_files=["res://.godot/imported/splash-small.wav-395e6cb2278f19594f3004dfba45fa36.sample"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
force/8_bit=false
|
||||||
|
force/mono=false
|
||||||
|
force/max_rate=false
|
||||||
|
force/max_rate_hz=44100
|
||||||
|
edit/trim=false
|
||||||
|
edit/normalize=false
|
||||||
|
edit/loop_mode=0
|
||||||
|
edit/loop_begin=0
|
||||||
|
edit/loop_end=-1
|
||||||
|
compress/mode=0
|
BIN
assets/sprout.png
Normal file
BIN
assets/sprout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 345 B |
34
assets/sprout.png.import
Normal file
34
assets/sprout.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://d35y5ckne72qe"
|
||||||
|
path="res://.godot/imported/sprout.png-98a4ab515d3bfdbd6f6db7d14b52ead7.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sprout.png"
|
||||||
|
dest_files=["res://.godot/imported/sprout.png-98a4ab515d3bfdbd6f6db7d14b52ead7.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
9
default_bus_layout.tres
Normal file
9
default_bus_layout.tres
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[gd_resource type="AudioBusLayout" format=3 uid="uid://dcxpomrfumov"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
bus/1/name = &"SoundEffects"
|
||||||
|
bus/1/solo = false
|
||||||
|
bus/1/mute = false
|
||||||
|
bus/1/bypass_fx = false
|
||||||
|
bus/1/volume_db = 0.0
|
||||||
|
bus/1/send = &"Master"
|
1
icon.svg
Normal file
1
icon.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
|
After Width: | Height: | Size: 994 B |
37
icon.svg.import
Normal file
37
icon.svg.import
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cb6qv3c0iojfl"
|
||||||
|
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
82
project.godot
Normal file
82
project.godot
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=5
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="Soil Tower"
|
||||||
|
run/main_scene="res://src/main/main.tscn"
|
||||||
|
config/features=PackedStringArray("4.3", "GL Compatibility")
|
||||||
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
[display]
|
||||||
|
|
||||||
|
window/size/viewport_width=640
|
||||||
|
window/size/viewport_height=360
|
||||||
|
window/size/window_width_override=1280
|
||||||
|
window/size/window_height_override=720
|
||||||
|
window/stretch/mode="canvas_items"
|
||||||
|
window/stretch/aspect="expand"
|
||||||
|
|
||||||
|
[global_group]
|
||||||
|
|
||||||
|
spawn_points=""
|
||||||
|
voids=""
|
||||||
|
|
||||||
|
[input]
|
||||||
|
|
||||||
|
move_forward={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
move_backward={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
strafe_left={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
strafe_right={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
jump={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
chat={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":84,"key_label":0,"unicode":116,"location":0,"echo":false,"script":null)
|
||||||
|
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":89,"key_label":0,"unicode":121,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
fire={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
[layer_names]
|
||||||
|
|
||||||
|
3d_physics/layer_1="solid"
|
||||||
|
3d_physics/layer_2="players"
|
||||||
|
3d_physics/layer_3="projectiles"
|
||||||
|
3d_physics/layer_4="plants"
|
||||||
|
3d_physics/layer_5="pickups"
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
renderer/rendering_method="gl_compatibility"
|
||||||
|
renderer/rendering_method.mobile="gl_compatibility"
|
10
src/ingame/chlorophyll.gd
Normal file
10
src/ingame/chlorophyll.gd
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
set_multiplayer_authority(1)
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
|
func pick_up() -> void:
|
||||||
|
queue_free()
|
25
src/ingame/chlorophyll.tscn
Normal file
25
src/ingame/chlorophyll.tscn
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://byfbrru6pl1ue"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://src/ingame/chlorophyll.gd" id="1_t6bqw"]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_l1bir"]
|
||||||
|
albedo_color = Color(0, 0.894118, 0.211765, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0, 0.894118, 0.211765, 1)
|
||||||
|
emission_energy_multiplier = 2.0
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_so6gf"]
|
||||||
|
radius = 0.3
|
||||||
|
|
||||||
|
[node name="Chlorophyll" type="Node3D"]
|
||||||
|
script = ExtResource("1_t6bqw")
|
||||||
|
|
||||||
|
[node name="CSGSphere3D" type="CSGSphere3D" parent="."]
|
||||||
|
material_override = SubResource("StandardMaterial3D_l1bir")
|
||||||
|
radius = 0.1
|
||||||
|
|
||||||
|
[node name="PickupArea" type="Area3D" parent="."]
|
||||||
|
collision_layer = 16
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="PickupArea"]
|
||||||
|
shape = SubResource("SphereShape3D_so6gf")
|
133
src/ingame/ingame.gd
Normal file
133
src/ingame/ingame.gd
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export var _player_scene: PackedScene
|
||||||
|
|
||||||
|
@export var _players: Node3D
|
||||||
|
@export var _chat_panel: Panel
|
||||||
|
@export var _chat_input: LineEdit
|
||||||
|
@export var _chat_history_scroll: ScrollContainer
|
||||||
|
@export var _chat_history: VBoxContainer
|
||||||
|
@export var _chat_panel_inactive: Panel
|
||||||
|
@export var _chat_history_inactive: VBoxContainer
|
||||||
|
@export var _chat_history_scroll_inactive: ScrollContainer
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
print("ingame ready")
|
||||||
|
|
||||||
|
_chat_history_scroll.get_v_scroll_bar().changed.connect(
|
||||||
|
_on_chat_history_scroll_changed.bind(_chat_history_scroll)
|
||||||
|
)
|
||||||
|
_chat_history_scroll_inactive.get_v_scroll_bar().changed.connect(
|
||||||
|
_on_chat_history_scroll_changed.bind(_chat_history_scroll_inactive)
|
||||||
|
)
|
||||||
|
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||||
|
|
||||||
|
if not multiplayer.is_server():
|
||||||
|
return
|
||||||
|
|
||||||
|
multiplayer.peer_connected.connect(_add_player)
|
||||||
|
multiplayer.peer_disconnected.connect(_remove_player)
|
||||||
|
|
||||||
|
for id in multiplayer.get_peers():
|
||||||
|
_add_player.call_deferred(id)
|
||||||
|
|
||||||
|
if not OS.has_feature("dedicated_server"):
|
||||||
|
_add_player.call_deferred(1)
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
if not multiplayer.is_server():
|
||||||
|
return
|
||||||
|
|
||||||
|
multiplayer.peer_connected.disconnect(_add_player)
|
||||||
|
multiplayer.peer_disconnected.disconnect(_remove_player)
|
||||||
|
|
||||||
|
|
||||||
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if event.is_action_pressed("chat"):
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
_activate_chat()
|
||||||
|
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event.is_action_pressed("ui_cancel"):
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
_deactivate_chat()
|
||||||
|
|
||||||
|
|
||||||
|
func _activate_chat() -> void:
|
||||||
|
_chat_panel.show()
|
||||||
|
_chat_panel_inactive.hide()
|
||||||
|
_chat_input.grab_focus.call_deferred()
|
||||||
|
_players.get_node(str(multiplayer.get_unique_id())).controls_disabled = true
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||||
|
|
||||||
|
|
||||||
|
func _deactivate_chat() -> void:
|
||||||
|
_chat_panel.hide()
|
||||||
|
_chat_panel_inactive.show()
|
||||||
|
_players.get_node(str(multiplayer.get_unique_id())).controls_disabled = false
|
||||||
|
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||||
|
|
||||||
|
|
||||||
|
func _add_player(id: int) -> void:
|
||||||
|
print("add player %d" % id)
|
||||||
|
var character: CharacterBody3D = _player_scene.instantiate()
|
||||||
|
character.id = id
|
||||||
|
character.name = str(id)
|
||||||
|
_players.add_child(character, true)
|
||||||
|
_set_character_authority.rpc(id)
|
||||||
|
|
||||||
|
|
||||||
|
func _remove_player(id: int) -> void:
|
||||||
|
if not _players.has_node(str(id)):
|
||||||
|
return
|
||||||
|
|
||||||
|
print("remove player %d" % id)
|
||||||
|
_players.get_node(str(id)).queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func _set_character_authority(id: int) -> void:
|
||||||
|
if not _players.has_node(str(id)):
|
||||||
|
return
|
||||||
|
|
||||||
|
_players.get_node(str(id)).set_multiplayer_authority(id)
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("any_peer", "call_local", "reliable", 1)
|
||||||
|
func _submit_chat_message(text: String) -> void:
|
||||||
|
var id := multiplayer.get_remote_sender_id()
|
||||||
|
var username: String = GameState.fetch().player_data[id].username
|
||||||
|
_add_chat_message.rpc(username, text)
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable", 1)
|
||||||
|
func _add_chat_message(username: String, text: String) -> void:
|
||||||
|
_chat_history.add_child(_make_chat_message(username, text))
|
||||||
|
_chat_history_inactive.add_child(_make_chat_message(username, text))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_chat_history_scroll_changed(history: ScrollContainer) -> void:
|
||||||
|
# keep history scrolled to the bottom
|
||||||
|
history.scroll_vertical = history.get_v_scroll_bar().max_value
|
||||||
|
|
||||||
|
|
||||||
|
func _make_chat_message(username: String, text: String) -> RichTextLabel:
|
||||||
|
var label := RichTextLabel.new()
|
||||||
|
label.bbcode_enabled = true
|
||||||
|
label.fit_content = true
|
||||||
|
label.append_text("[color=red]%s[/color] %s" % [username.replace("[", "[lb]"), text.replace("[", "[lb]")])
|
||||||
|
return label
|
||||||
|
|
||||||
|
|
||||||
|
func _on_chat_message_submitted(new_text := "") -> void:
|
||||||
|
if _chat_input.text.is_empty():
|
||||||
|
_deactivate_chat()
|
||||||
|
return
|
||||||
|
|
||||||
|
_submit_chat_message.rpc_id(1, _chat_input.text)
|
||||||
|
_chat_input.clear()
|
||||||
|
_deactivate_chat()
|
261
src/ingame/ingame.tscn
Normal file
261
src/ingame/ingame.tscn
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
[gd_scene load_steps=11 format=3 uid="uid://oyvhcwq60v2"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://src/ingame/ingame.gd" id="1_akuuj"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cs8c570bxh6u" path="res://src/ingame/player.tscn" id="2_w1gjc"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bysgtksvovyur" path="res://src/ingame/sprout.tscn" id="3_2xvqq"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_l0cfx"]
|
||||||
|
size = Vector3(8, 0.2, 17)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_8v8cv"]
|
||||||
|
size = Vector3(4, 0.6, 17)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_0k58u"]
|
||||||
|
size = Vector3(2.2, 0.6, 3)
|
||||||
|
|
||||||
|
[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_eu7fm"]
|
||||||
|
|
||||||
|
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_e4ynx"]
|
||||||
|
ground_bottom_color = Color(0.647059, 0.654902, 0.670588, 1)
|
||||||
|
sun_angle_max = 8.0
|
||||||
|
sun_curve = 8.81744
|
||||||
|
energy_multiplier = 1.5
|
||||||
|
|
||||||
|
[sub_resource type="Sky" id="Sky_ygvd3"]
|
||||||
|
sky_material = SubResource("ProceduralSkyMaterial_e4ynx")
|
||||||
|
|
||||||
|
[sub_resource type="Environment" id="Environment_ijk14"]
|
||||||
|
background_mode = 2
|
||||||
|
sky = SubResource("Sky_ygvd3")
|
||||||
|
ambient_light_color = Color(0, 0.164706, 0.278431, 1)
|
||||||
|
ambient_light_energy = 2.0
|
||||||
|
|
||||||
|
[node name="Ingame" type="Node3D" node_paths=PackedStringArray("_players", "_chat_panel", "_chat_input", "_chat_history_scroll", "_chat_history", "_chat_panel_inactive", "_chat_history_inactive", "_chat_history_scroll_inactive")]
|
||||||
|
script = ExtResource("1_akuuj")
|
||||||
|
_player_scene = ExtResource("2_w1gjc")
|
||||||
|
_players = NodePath("Players")
|
||||||
|
_chat_panel = NodePath("UI/ChatPanel")
|
||||||
|
_chat_input = NodePath("UI/ChatPanel/ChatInput")
|
||||||
|
_chat_history_scroll = NodePath("UI/ChatPanel/ChatHistoryScroll")
|
||||||
|
_chat_history = NodePath("UI/ChatPanel/ChatHistoryScroll/ChatHistory")
|
||||||
|
_chat_panel_inactive = NodePath("UI/ChatPanelInactive")
|
||||||
|
_chat_history_inactive = NodePath("UI/ChatPanelInactive/ChatHistoryScroll/ChatHistory")
|
||||||
|
_chat_history_scroll_inactive = NodePath("UI/ChatPanelInactive/ChatHistoryScroll")
|
||||||
|
|
||||||
|
[node name="UI" type="CanvasLayer" parent="."]
|
||||||
|
|
||||||
|
[node name="ChatPanel" type="Panel" parent="UI"]
|
||||||
|
visible = false
|
||||||
|
self_modulate = Color(1, 1, 1, 0.498039)
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -312.0
|
||||||
|
offset_top = 12.0
|
||||||
|
offset_bottom = 172.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="ChatHistoryScroll" type="ScrollContainer" parent="UI/ChatPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 8.0
|
||||||
|
offset_top = 8.0
|
||||||
|
offset_right = -8.0
|
||||||
|
offset_bottom = -48.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="ChatHistory" type="VBoxContainer" parent="UI/ChatPanel/ChatHistoryScroll"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="ChatInput" type="LineEdit" parent="UI/ChatPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 8.0
|
||||||
|
offset_top = 120.0
|
||||||
|
offset_right = -72.0
|
||||||
|
offset_bottom = -9.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
placeholder_text = "say something"
|
||||||
|
max_length = 300
|
||||||
|
context_menu_enabled = false
|
||||||
|
clear_button_enabled = true
|
||||||
|
middle_mouse_paste_enabled = false
|
||||||
|
|
||||||
|
[node name="ChatSendButton" type="Button" parent="UI/ChatPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 248.0
|
||||||
|
offset_top = 120.0
|
||||||
|
offset_right = -8.0
|
||||||
|
offset_bottom = -9.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "send"
|
||||||
|
|
||||||
|
[node name="ChatPanelInactive" type="Panel" parent="UI"]
|
||||||
|
self_modulate = Color(1, 1, 1, 0)
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -312.0
|
||||||
|
offset_top = 12.0
|
||||||
|
offset_bottom = 172.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="ChatHistoryScroll" type="ScrollContainer" parent="UI/ChatPanelInactive"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 8.0
|
||||||
|
offset_top = 8.0
|
||||||
|
offset_right = -8.0
|
||||||
|
offset_bottom = -9.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
vertical_scroll_mode = 3
|
||||||
|
|
||||||
|
[node name="ChatHistory" type="VBoxContainer" parent="UI/ChatPanelInactive/ChatHistoryScroll"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="CSGBox3D" type="CSGBox3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 7.45058e-09, 0)
|
||||||
|
collision_mask = 0
|
||||||
|
size = Vector3(8, 0.2, 17)
|
||||||
|
|
||||||
|
[node name="StaticBody3D" type="StaticBody3D" parent="CSGBox3D"]
|
||||||
|
collision_mask = 0
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="CSGBox3D/StaticBody3D"]
|
||||||
|
shape = SubResource("BoxShape3D_l0cfx")
|
||||||
|
|
||||||
|
[node name="GPUParticlesCollisionBox3D" type="GPUParticlesCollisionBox3D" parent="CSGBox3D"]
|
||||||
|
size = Vector3(8, 0.2, 17)
|
||||||
|
|
||||||
|
[node name="CSGBox3D2" type="CSGBox3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.03442, 0.2, 0)
|
||||||
|
collision_mask = 0
|
||||||
|
size = Vector3(4, 0.6, 17)
|
||||||
|
|
||||||
|
[node name="StaticBody3D" type="StaticBody3D" parent="CSGBox3D2"]
|
||||||
|
collision_mask = 0
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="CSGBox3D2/StaticBody3D"]
|
||||||
|
shape = SubResource("BoxShape3D_8v8cv")
|
||||||
|
|
||||||
|
[node name="GPUParticlesCollisionBox3D" type="GPUParticlesCollisionBox3D" parent="CSGBox3D2"]
|
||||||
|
size = Vector3(4, 0.6, 17)
|
||||||
|
|
||||||
|
[node name="CSGBox3D3" type="CSGBox3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.23442, 0.8, -2.4)
|
||||||
|
collision_mask = 0
|
||||||
|
size = Vector3(2.2, 0.6, 3)
|
||||||
|
|
||||||
|
[node name="StaticBody3D" type="StaticBody3D" parent="CSGBox3D3"]
|
||||||
|
collision_mask = 0
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="CSGBox3D3/StaticBody3D"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.76837e-07, 0, 0)
|
||||||
|
shape = SubResource("BoxShape3D_0k58u")
|
||||||
|
|
||||||
|
[node name="GPUParticlesCollisionBox3D" type="GPUParticlesCollisionBox3D" parent="CSGBox3D3"]
|
||||||
|
size = Vector3(2.2, 0.6, 3)
|
||||||
|
|
||||||
|
[node name="Void" type="StaticBody3D" parent="." groups=["voids"]]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -8, 0)
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Void"]
|
||||||
|
shape = SubResource("WorldBoundaryShape3D_eu7fm")
|
||||||
|
|
||||||
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||||
|
environment = SubResource("Environment_ijk14")
|
||||||
|
|
||||||
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||||
|
transform = Transform3D(0.943957, 0.3178, 0.0891561, 0, -0.270113, 0.962829, 0.33007, -0.908868, -0.254975, 0, 0, 0)
|
||||||
|
light_energy = 2.0
|
||||||
|
|
||||||
|
[node name="SpawnPoint" type="Marker3D" parent="." groups=["spawn_points"]]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
||||||
|
|
||||||
|
[node name="PlayerSpawner" type="MultiplayerSpawner" parent="."]
|
||||||
|
_spawnable_scenes = PackedStringArray("res://src/ingame/player.tscn")
|
||||||
|
spawn_path = NodePath("../Players")
|
||||||
|
|
||||||
|
[node name="Players" type="Node3D" parent="."]
|
||||||
|
|
||||||
|
[node name="Plants" type="Node3D" parent="."]
|
||||||
|
|
||||||
|
[node name="Sprout" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00401986, 0.396167, -3.22022)
|
||||||
|
|
||||||
|
[node name="Sprout2" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.60402, 0.396167, -3.22022)
|
||||||
|
|
||||||
|
[node name="Sprout3" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.59598, 0.396167, -3.22022)
|
||||||
|
|
||||||
|
[node name="Sprout4" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00401986, 0.396167, 2.77978)
|
||||||
|
|
||||||
|
[node name="Sprout5" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.60402, 0.396167, 2.77978)
|
||||||
|
|
||||||
|
[node name="Sprout6" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.59598, 0.396167, 2.77978)
|
||||||
|
|
||||||
|
[node name="Sprout7" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00401986, 0.396167, 3.37978)
|
||||||
|
|
||||||
|
[node name="Sprout8" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.60402, 0.396167, 3.37978)
|
||||||
|
|
||||||
|
[node name="Sprout9" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.59598, 0.396167, 3.37978)
|
||||||
|
|
||||||
|
[node name="Sprout10" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.99598, 1.39617, -2.22022)
|
||||||
|
|
||||||
|
[node name="Sprout11" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.39598, 1.39617, -2.22022)
|
||||||
|
|
||||||
|
[node name="Sprout12" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.59598, 1.39617, -2.22022)
|
||||||
|
|
||||||
|
[node name="Sprout16" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.99598, 1.39617, -2.82022)
|
||||||
|
|
||||||
|
[node name="Sprout17" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.39598, 1.39617, -2.82022)
|
||||||
|
|
||||||
|
[node name="Sprout18" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.59598, 1.39617, -2.82022)
|
||||||
|
|
||||||
|
[node name="Sprout13" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.99598, 1.39617, -1.62022)
|
||||||
|
|
||||||
|
[node name="Sprout14" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.39598, 1.39617, -1.62022)
|
||||||
|
|
||||||
|
[node name="Sprout15" parent="Plants" instance=ExtResource("3_2xvqq")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.59598, 1.39617, -1.62022)
|
||||||
|
|
||||||
|
[connection signal="text_submitted" from="UI/ChatPanel/ChatInput" to="." method="_on_chat_message_submitted"]
|
||||||
|
[connection signal="pressed" from="UI/ChatPanel/ChatSendButton" to="." method="_on_chat_message_submitted"]
|
105
src/ingame/player.gd
Normal file
105
src/ingame/player.gd
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
extends CharacterBody3D
|
||||||
|
|
||||||
|
|
||||||
|
const SPEED = 5.0
|
||||||
|
const JUMP_VELOCITY = 4.5
|
||||||
|
|
||||||
|
@export var _projectile_scene: PackedScene
|
||||||
|
|
||||||
|
@export var _projectile_holder: Node
|
||||||
|
@export var _projectile_point: Marker3D
|
||||||
|
@export var _camera_pivot: Node3D
|
||||||
|
@export var _camera: Camera3D
|
||||||
|
@export var _shot_sound: AudioStreamPlayer3D
|
||||||
|
|
||||||
|
@export var id: int
|
||||||
|
@export var input_dir := Vector2()
|
||||||
|
@export var input_jumped := false
|
||||||
|
|
||||||
|
var _max_speed := 12
|
||||||
|
var _mouse_sensitivity := 0.008 # radians/pixel
|
||||||
|
|
||||||
|
var _projectile_speed := 12.0
|
||||||
|
|
||||||
|
var controls_disabled := false
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if id != multiplayer.get_unique_id():
|
||||||
|
return
|
||||||
|
|
||||||
|
$Model.hide()
|
||||||
|
_camera.make_current()
|
||||||
|
|
||||||
|
var spawn_point: Marker3D = get_tree().get_nodes_in_group("spawn_points").pick_random()
|
||||||
|
global_position = spawn_point.global_position
|
||||||
|
reset_physics_interpolation()
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if id != multiplayer.get_unique_id():
|
||||||
|
return
|
||||||
|
|
||||||
|
_process_input()
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
# Add the gravity.
|
||||||
|
if not is_on_floor():
|
||||||
|
velocity += get_gravity() * delta
|
||||||
|
|
||||||
|
# Handle jump.
|
||||||
|
if input_jumped 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 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 = move_toward(velocity.x, 0, SPEED)
|
||||||
|
velocity.z = move_toward(velocity.z, 0, SPEED)
|
||||||
|
|
||||||
|
move_and_slide()
|
||||||
|
|
||||||
|
|
||||||
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if controls_disabled or id != multiplayer.get_unique_id():
|
||||||
|
return
|
||||||
|
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
rotate_y(-event.relative.x * _mouse_sensitivity)
|
||||||
|
_camera_pivot.rotate_x(-event.relative.y * _mouse_sensitivity)
|
||||||
|
_camera_pivot.rotation.x = clamp(_camera_pivot.rotation.x, -1.2, 1.2)
|
||||||
|
return
|
||||||
|
|
||||||
|
if event.is_action_pressed("fire"):
|
||||||
|
var new_projectile: Node3D = _projectile_scene.instantiate()
|
||||||
|
_projectile_holder.add_child(new_projectile, true)
|
||||||
|
_set_projectile_authority.rpc(new_projectile.get_path(), id)
|
||||||
|
new_projectile.set_global_pos.rpc(_projectile_point.global_position)
|
||||||
|
|
||||||
|
new_projectile.body.process_mode = Node.PROCESS_MODE_INHERIT
|
||||||
|
new_projectile.body.linear_velocity = -_camera.global_basis.z * _projectile_speed
|
||||||
|
|
||||||
|
_shot_sound.play()
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func _set_projectile_authority(path: NodePath, authority_id: int) -> void:
|
||||||
|
if not _projectile_holder.has_node(path):
|
||||||
|
return
|
||||||
|
|
||||||
|
_projectile_holder.get_node(path).set_multiplayer_authority(authority_id)
|
||||||
|
|
||||||
|
|
||||||
|
func _process_input() -> void:
|
||||||
|
if controls_disabled:
|
||||||
|
input_dir = Vector2.ZERO
|
||||||
|
input_jumped = false
|
||||||
|
return
|
||||||
|
|
||||||
|
input_dir = Input.get_vector("strafe_left", "strafe_right", "move_forward", "move_backward")
|
||||||
|
input_jumped = Input.is_action_just_pressed("jump")
|
71
src/ingame/player.tscn
Normal file
71
src/ingame/player.tscn
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
[gd_scene load_steps=7 format=3 uid="uid://cs8c570bxh6u"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://src/ingame/player.gd" id="1_isrmf"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://tdsbo3e5ic86" path="res://src/ingame/water_bomb.tscn" id="2_naek4"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://3dlhs18w1fa2" path="res://assets/sfx/boom.wav" id="3_u2hxa"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_2xotl"]
|
||||||
|
properties/0/path = NodePath(".:position")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
properties/1/path = NodePath(".:id")
|
||||||
|
properties/1/spawn = true
|
||||||
|
properties/1/replication_mode = 0
|
||||||
|
properties/2/path = NodePath(".:rotation")
|
||||||
|
properties/2/spawn = true
|
||||||
|
properties/2/replication_mode = 1
|
||||||
|
properties/3/path = NodePath(".:input_dir")
|
||||||
|
properties/3/spawn = true
|
||||||
|
properties/3/replication_mode = 1
|
||||||
|
properties/4/path = NodePath(".:input_jumped")
|
||||||
|
properties/4/spawn = true
|
||||||
|
properties/4/replication_mode = 2
|
||||||
|
properties/5/path = NodePath("ShotSound:playing")
|
||||||
|
properties/5/spawn = true
|
||||||
|
properties/5/replication_mode = 2
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleMesh" id="CapsuleMesh_hi8jw"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_f4jjl"]
|
||||||
|
|
||||||
|
[node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("_projectile_holder", "_projectile_point", "_camera_pivot", "_camera", "_shot_sound")]
|
||||||
|
collision_layer = 2
|
||||||
|
script = ExtResource("1_isrmf")
|
||||||
|
_projectile_scene = ExtResource("2_naek4")
|
||||||
|
_projectile_holder = NodePath("ProjectileHolder")
|
||||||
|
_projectile_point = NodePath("ProjectilePoint")
|
||||||
|
_camera_pivot = NodePath("CameraPivot")
|
||||||
|
_camera = NodePath("CameraPivot/Camera3D")
|
||||||
|
_shot_sound = NodePath("ShotSound")
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
|
replication_config = SubResource("SceneReplicationConfig_2xotl")
|
||||||
|
|
||||||
|
[node name="ProjectileSpawner" type="MultiplayerSpawner" parent="."]
|
||||||
|
_spawnable_scenes = PackedStringArray("res://src/ingame/water_bomb.tscn")
|
||||||
|
spawn_path = NodePath("../ProjectileHolder")
|
||||||
|
|
||||||
|
[node name="ProjectileHolder" type="Node" parent="."]
|
||||||
|
|
||||||
|
[node name="ProjectilePoint" type="Marker3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.3, -0.095)
|
||||||
|
|
||||||
|
[node name="Model" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
|
||||||
|
mesh = SubResource("CapsuleMesh_hi8jw")
|
||||||
|
|
||||||
|
[node name="CSGBox3D" type="CSGBox3D" parent="Model"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.5)
|
||||||
|
size = Vector3(0.8, 0.8, 0.8)
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("CapsuleShape3D_f4jjl")
|
||||||
|
|
||||||
|
[node name="CameraPivot" type="Node3D" parent="."]
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="CameraPivot"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, 0)
|
||||||
|
|
||||||
|
[node name="ShotSound" type="AudioStreamPlayer3D" parent="."]
|
||||||
|
stream = ExtResource("3_u2hxa")
|
||||||
|
bus = &"SoundEffects"
|
25
src/ingame/sprout.gd
Normal file
25
src/ingame/sprout.gd
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export var _need_water_drop: Sprite3D
|
||||||
|
@export var _production_timer: Timer
|
||||||
|
|
||||||
|
var needs_water := true
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
set_multiplayer_authority(1)
|
||||||
|
_need_water_drop.show()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_production_timer_timeout() -> void:
|
||||||
|
needs_water = true
|
||||||
|
_need_water_drop.show()
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
|
func water() -> void:
|
||||||
|
if needs_water:
|
||||||
|
needs_water = false
|
||||||
|
_need_water_drop.hide()
|
||||||
|
|
||||||
|
_production_timer.start()
|
53
src/ingame/sprout.tscn
Normal file
53
src/ingame/sprout.tscn
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://bysgtksvovyur"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://src/ingame/sprout.gd" id="1_snma1"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://d35y5ckne72qe" path="res://assets/sprout.png" id="2_ipgad"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cwbl0r1e26eja" path="res://assets/drop.png" id="3_kghdv"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_rs2qp"]
|
||||||
|
properties/0/path = NodePath(".:needs_water")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 2
|
||||||
|
properties/1/path = NodePath("NeedWaterDrop:visible")
|
||||||
|
properties/1/spawn = true
|
||||||
|
properties/1/replication_mode = 2
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cwbye"]
|
||||||
|
radius = 0.3
|
||||||
|
height = 0.8
|
||||||
|
|
||||||
|
[node name="Sprout" type="Node3D" node_paths=PackedStringArray("_need_water_drop", "_production_timer")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00401986, -0.00383317, 0.00119042)
|
||||||
|
script = ExtResource("1_snma1")
|
||||||
|
_need_water_drop = NodePath("NeedWaterDrop")
|
||||||
|
_production_timer = NodePath("ProductionTimer")
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
|
replication_config = SubResource("SceneReplicationConfig_rs2qp")
|
||||||
|
|
||||||
|
[node name="Sprite3D" type="Sprite3D" parent="."]
|
||||||
|
pixel_size = 0.02
|
||||||
|
billboard = 2
|
||||||
|
shaded = true
|
||||||
|
texture_filter = 2
|
||||||
|
texture = ExtResource("2_ipgad")
|
||||||
|
|
||||||
|
[node name="NeedWaterDrop" type="Sprite3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.3, 0)
|
||||||
|
visible = false
|
||||||
|
pixel_size = 0.02
|
||||||
|
billboard = 1
|
||||||
|
texture_filter = 2
|
||||||
|
texture = ExtResource("3_kghdv")
|
||||||
|
|
||||||
|
[node name="Area3D" type="Area3D" parent="."]
|
||||||
|
collision_layer = 8
|
||||||
|
collision_mask = 0
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Area3D"]
|
||||||
|
shape = SubResource("CapsuleShape3D_cwbye")
|
||||||
|
|
||||||
|
[node name="ProductionTimer" type="Timer" parent="."]
|
||||||
|
one_shot = true
|
||||||
|
|
||||||
|
[connection signal="timeout" from="ProductionTimer" to="." method="_on_production_timer_timeout"]
|
66
src/ingame/water_bomb.gd
Normal file
66
src/ingame/water_bomb.gd
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export var _splash_small_sound: AudioStreamPlayer3D
|
||||||
|
@export var _splash_small_quiet_sound: AudioStreamPlayer3D
|
||||||
|
@export var _model: Node3D
|
||||||
|
@export var _splash_particles: GPUParticles3D
|
||||||
|
@export var body: RigidBody3D
|
||||||
|
## no longer exists and shouldn't be considered, but not ready to be freed yet
|
||||||
|
@export var is_dead := false
|
||||||
|
|
||||||
|
var _in_splash_range := {}
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
body.process_mode = Node.PROCESS_MODE_DISABLED
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
if not is_multiplayer_authority():
|
||||||
|
return
|
||||||
|
|
||||||
|
global_position = body.global_position
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func _disable_body() -> void:
|
||||||
|
# not using synchronizer for this because it ends up enabling processing
|
||||||
|
# on other clients
|
||||||
|
(func() -> void: body.process_mode = Node.PROCESS_MODE_DISABLED).call_deferred()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_body_entered(p_body: Node3D) -> void:
|
||||||
|
if p_body.is_in_group("voids"):
|
||||||
|
queue_free()
|
||||||
|
return
|
||||||
|
|
||||||
|
for area: Area3D in _in_splash_range:
|
||||||
|
area.get_parent_node_3d().water.rpc_id(1)
|
||||||
|
|
||||||
|
_splash_small_sound.play()
|
||||||
|
_splash_small_quiet_sound.play()
|
||||||
|
_splash_particles.emitting = true
|
||||||
|
|
||||||
|
is_dead = true
|
||||||
|
_model.hide()
|
||||||
|
_disable_body.rpc()
|
||||||
|
|
||||||
|
await _splash_small_sound.finished
|
||||||
|
if _splash_small_quiet_sound.playing:
|
||||||
|
await _splash_small_quiet_sound.finished
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_splash_area_entered(area: Area3D) -> void:
|
||||||
|
_in_splash_range[area] = true
|
||||||
|
|
||||||
|
|
||||||
|
func _on_splash_area_exited(area: Area3D) -> void:
|
||||||
|
_in_splash_range.erase(area)
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func set_global_pos(new: Vector3) -> void:
|
||||||
|
global_position = new
|
||||||
|
body.global_position = new
|
||||||
|
body.reset_physics_interpolation()
|
110
src/ingame/water_bomb.tscn
Normal file
110
src/ingame/water_bomb.tscn
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
[gd_scene load_steps=11 format=3 uid="uid://tdsbo3e5ic86"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://src/ingame/water_bomb.gd" id="1_lk5fq"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://dtjpv2b74g24m" path="res://assets/sfx/splash-small.wav" id="2_0wk8g"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://blgrl2wl05feq" path="res://assets/sfx/splash-small-quiet.wav" id="3_hgy7l"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_0ebrr"]
|
||||||
|
properties/0/path = NodePath(".:position")
|
||||||
|
properties/0/spawn = true
|
||||||
|
properties/0/replication_mode = 1
|
||||||
|
properties/1/path = NodePath("SplashSmallSound:playing")
|
||||||
|
properties/1/spawn = true
|
||||||
|
properties/1/replication_mode = 2
|
||||||
|
properties/2/path = NodePath("SplashSmallQuietSound:playing")
|
||||||
|
properties/2/spawn = true
|
||||||
|
properties/2/replication_mode = 2
|
||||||
|
properties/3/path = NodePath(".:is_dead")
|
||||||
|
properties/3/spawn = true
|
||||||
|
properties/3/replication_mode = 2
|
||||||
|
properties/4/path = NodePath("Model:visible")
|
||||||
|
properties/4/spawn = true
|
||||||
|
properties/4/replication_mode = 2
|
||||||
|
properties/5/path = NodePath("SplashParticles:emitting")
|
||||||
|
properties/5/spawn = true
|
||||||
|
properties/5/replication_mode = 2
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ptaep"]
|
||||||
|
albedo_color = Color(0.0936238, 0.825356, 1, 1)
|
||||||
|
metallic = 0.8
|
||||||
|
roughness = 0.4
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_v7dnr"]
|
||||||
|
albedo_color = Color(0, 1, 1, 1)
|
||||||
|
roughness = 0.2
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_rjbgm"]
|
||||||
|
direction = Vector3(0, 1, 0)
|
||||||
|
initial_velocity_min = 5.0
|
||||||
|
initial_velocity_max = 5.0
|
||||||
|
gravity = Vector3(0, -8, 0)
|
||||||
|
collision_mode = 2
|
||||||
|
|
||||||
|
[sub_resource type="SphereMesh" id="SphereMesh_bhdh4"]
|
||||||
|
radius = 0.1
|
||||||
|
height = 0.2
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_6c830"]
|
||||||
|
radius = 0.2
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_y6453"]
|
||||||
|
radius = 1.5
|
||||||
|
|
||||||
|
[node name="WaterBomb" type="Node3D" node_paths=PackedStringArray("_splash_small_sound", "_splash_small_quiet_sound", "_model", "_splash_particles", "body")]
|
||||||
|
script = ExtResource("1_lk5fq")
|
||||||
|
_splash_small_sound = NodePath("SplashSmallSound")
|
||||||
|
_splash_small_quiet_sound = NodePath("SplashSmallQuietSound")
|
||||||
|
_model = NodePath("Model")
|
||||||
|
_splash_particles = NodePath("SplashParticles")
|
||||||
|
body = NodePath("RigidBody3D")
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
|
replication_config = SubResource("SceneReplicationConfig_0ebrr")
|
||||||
|
|
||||||
|
[node name="Model" type="CSGSphere3D" parent="."]
|
||||||
|
material_override = SubResource("StandardMaterial3D_ptaep")
|
||||||
|
radius = 0.2
|
||||||
|
radial_segments = 24
|
||||||
|
rings = 12
|
||||||
|
|
||||||
|
[node name="SplashParticles" type="GPUParticles3D" parent="."]
|
||||||
|
material_override = SubResource("StandardMaterial3D_v7dnr")
|
||||||
|
emitting = false
|
||||||
|
amount = 32
|
||||||
|
lifetime = 2.0
|
||||||
|
one_shot = true
|
||||||
|
explosiveness = 1.0
|
||||||
|
randomness = 1.0
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_rjbgm")
|
||||||
|
draw_pass_1 = SubResource("SphereMesh_bhdh4")
|
||||||
|
|
||||||
|
[node name="RigidBody3D" type="RigidBody3D" parent="."]
|
||||||
|
top_level = true
|
||||||
|
collision_layer = 4
|
||||||
|
contact_monitor = true
|
||||||
|
max_contacts_reported = 1
|
||||||
|
linear_damp_mode = 1
|
||||||
|
linear_damp = 0.3
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="RigidBody3D"]
|
||||||
|
shape = SubResource("SphereShape3D_6c830")
|
||||||
|
|
||||||
|
[node name="SplashArea" type="Area3D" parent="RigidBody3D"]
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 8
|
||||||
|
monitorable = false
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="RigidBody3D/SplashArea"]
|
||||||
|
shape = SubResource("SphereShape3D_y6453")
|
||||||
|
|
||||||
|
[node name="SplashSmallSound" type="AudioStreamPlayer3D" parent="."]
|
||||||
|
stream = ExtResource("2_0wk8g")
|
||||||
|
bus = &"SoundEffects"
|
||||||
|
|
||||||
|
[node name="SplashSmallQuietSound" type="AudioStreamPlayer3D" parent="."]
|
||||||
|
stream = ExtResource("3_hgy7l")
|
||||||
|
bus = &"SoundEffects"
|
||||||
|
|
||||||
|
[connection signal="body_entered" from="RigidBody3D" to="." method="_on_body_entered"]
|
||||||
|
[connection signal="area_entered" from="RigidBody3D/SplashArea" to="." method="_on_splash_area_entered"]
|
||||||
|
[connection signal="area_exited" from="RigidBody3D/SplashArea" to="." method="_on_splash_area_exited"]
|
14
src/lib/game_state.gd
Normal file
14
src/lib/game_state.gd
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class_name GameState
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var player_data := {}
|
||||||
|
|
||||||
|
static var _instance := GameState.new()
|
||||||
|
|
||||||
|
|
||||||
|
static func save() -> void:
|
||||||
|
ResourceSaver.save(_instance, "user://game_state.tres")
|
||||||
|
|
||||||
|
|
||||||
|
static func fetch() -> GameState:
|
||||||
|
return _instance
|
4
src/lib/player_data.gd
Normal file
4
src/lib/player_data.gd
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
class_name PlayerData
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var username: String
|
164
src/main/main.gd
Normal file
164
src/main/main.gd
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
@export var _start_menu: Control
|
||||||
|
@export var _username_input: LineEdit
|
||||||
|
@export var _ip_input: LineEdit
|
||||||
|
|
||||||
|
@export var _player_list: VBoxContainer
|
||||||
|
@export var _chat_menu: Control
|
||||||
|
@export var _chat_input: LineEdit
|
||||||
|
@export var _chat_history_scroll: ScrollContainer
|
||||||
|
@export var _chat_history: VBoxContainer
|
||||||
|
@export var _start_button: Button
|
||||||
|
|
||||||
|
@export var _ingame_scene: PackedScene
|
||||||
|
|
||||||
|
var _game_started := false
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_start_menu.show()
|
||||||
|
_chat_menu.hide()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_player_joined(id: int) -> void:
|
||||||
|
for player_id in GameState.fetch().player_data.keys():
|
||||||
|
var username = GameState.fetch().player_data[player_id].username
|
||||||
|
_register_player.rpc_id(id, username)
|
||||||
|
|
||||||
|
if _game_started:
|
||||||
|
_start_game.rpc_id(id)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_player_left(id: int) -> void:
|
||||||
|
_unregister_player.rpc(id)
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
|
func _register_player(username: String) -> void:
|
||||||
|
var id = multiplayer.get_remote_sender_id()
|
||||||
|
GameState.fetch().player_data[id] = PlayerData.new()
|
||||||
|
GameState.fetch().player_data[id].username = username
|
||||||
|
|
||||||
|
var list_label := RichTextLabel.new()
|
||||||
|
list_label.bbcode_enabled = false
|
||||||
|
list_label.fit_content = true
|
||||||
|
list_label.text = username
|
||||||
|
_player_list.add_child(list_label)
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func _unregister_player(id: int) -> void:
|
||||||
|
var labels := _player_list.get_children()
|
||||||
|
for label: RichTextLabel in labels:
|
||||||
|
if label.text == GameState.fetch().player_data[id].username:
|
||||||
|
label.queue_free()
|
||||||
|
break
|
||||||
|
|
||||||
|
GameState.fetch().player_data.erase(id)
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("any_peer", "call_local", "reliable", 1)
|
||||||
|
func _submit_chat_message(text: String) -> void:
|
||||||
|
var id := multiplayer.get_remote_sender_id()
|
||||||
|
var username: String = GameState.fetch().player_data[id].username
|
||||||
|
_add_chat_message.rpc(username, text)
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable", 1)
|
||||||
|
func _add_chat_message(username: String, text: String) -> void:
|
||||||
|
var label := RichTextLabel.new()
|
||||||
|
label.bbcode_enabled = true
|
||||||
|
label.fit_content = true
|
||||||
|
label.append_text("[color=red]%s[/color] %s" % [username.replace("[", "[lb]"), text.replace("[", "[lb]")])
|
||||||
|
_chat_history.add_child(label)
|
||||||
|
|
||||||
|
# keep chat scrolled to the bottom
|
||||||
|
await _chat_history_scroll.get_v_scroll_bar().changed
|
||||||
|
_chat_history_scroll.scroll_vertical = _chat_history_scroll.get_v_scroll_bar().max_value
|
||||||
|
|
||||||
|
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func _start_game() -> void:
|
||||||
|
_start_menu.hide()
|
||||||
|
_chat_menu.hide()
|
||||||
|
_game_started = true
|
||||||
|
|
||||||
|
|
||||||
|
# START MENU #
|
||||||
|
func _on_host_button_pressed() -> void:
|
||||||
|
var peer := ENetMultiplayerPeer.new()
|
||||||
|
var error = peer.create_server(20106, 8, 2)
|
||||||
|
if error != OK:
|
||||||
|
match error:
|
||||||
|
ERR_ALREADY_IN_USE:
|
||||||
|
push_error("server ERR_ALREADY_IN_USE")
|
||||||
|
ERR_CANT_CREATE:
|
||||||
|
push_error("server ERR_CANT_CREATE")
|
||||||
|
return
|
||||||
|
|
||||||
|
multiplayer.multiplayer_peer = peer
|
||||||
|
multiplayer.multiplayer_peer.peer_connected.connect(_on_player_joined)
|
||||||
|
multiplayer.multiplayer_peer.peer_disconnected.connect(_on_player_left)
|
||||||
|
|
||||||
|
var username := _username_input.text
|
||||||
|
if username.is_empty():
|
||||||
|
username = "schlorpy"
|
||||||
|
_register_player.rpc_id(1, username)
|
||||||
|
|
||||||
|
_start_button.disabled = false
|
||||||
|
_start_menu.hide()
|
||||||
|
_chat_menu.show()
|
||||||
|
|
||||||
|
print("hosted!")
|
||||||
|
|
||||||
|
|
||||||
|
func _on_join_button_pressed() -> void:
|
||||||
|
var peer := ENetMultiplayerPeer.new()
|
||||||
|
|
||||||
|
var ip := ""
|
||||||
|
if _ip_input.text.is_empty():
|
||||||
|
ip = "127.0.0.1"
|
||||||
|
else:
|
||||||
|
ip = _ip_input.text
|
||||||
|
|
||||||
|
var error = peer.create_client(ip, 20106, 2)
|
||||||
|
|
||||||
|
|
||||||
|
if error != OK:
|
||||||
|
match error:
|
||||||
|
ERR_ALREADY_IN_USE:
|
||||||
|
push_error("client ERR_ALREADY_IN_USE")
|
||||||
|
ERR_CANT_CREATE:
|
||||||
|
push_error("client ERR_CANT_CREATE")
|
||||||
|
return
|
||||||
|
|
||||||
|
multiplayer.multiplayer_peer = peer
|
||||||
|
|
||||||
|
multiplayer.connected_to_server.connect(
|
||||||
|
func() -> void:
|
||||||
|
var username := _username_input.text
|
||||||
|
if username.is_empty():
|
||||||
|
username = "schlorpy"
|
||||||
|
_register_player.rpc(username)
|
||||||
|
|
||||||
|
_start_button.disabled = true
|
||||||
|
_start_menu.hide()
|
||||||
|
_chat_menu.show()
|
||||||
|
|
||||||
|
print("joined!")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# CHAT MENU #
|
||||||
|
func _on_start_button_pressed() -> void:
|
||||||
|
_start_game.rpc()
|
||||||
|
$IngameContainer.add_child.call_deferred(_ingame_scene.instantiate())
|
||||||
|
|
||||||
|
|
||||||
|
func _on_chat_message_submitted(text := "") -> void:
|
||||||
|
if _chat_input.text.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
_submit_chat_message.rpc_id(1, _chat_input.text)
|
||||||
|
_chat_input.clear()
|
213
src/main/main.tscn
Normal file
213
src/main/main.tscn
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://dk6pok1gk6ick"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://src/main/main.gd" id="1_fqmow"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://oyvhcwq60v2" path="res://src/ingame/ingame.tscn" id="2_5ajgq"]
|
||||||
|
|
||||||
|
[node name="Main" type="Node" node_paths=PackedStringArray("_start_menu", "_username_input", "_ip_input", "_player_list", "_chat_menu", "_chat_input", "_chat_history_scroll", "_chat_history", "_start_button")]
|
||||||
|
script = ExtResource("1_fqmow")
|
||||||
|
_start_menu = NodePath("StartMenu")
|
||||||
|
_username_input = NodePath("StartMenu/UsernameInput")
|
||||||
|
_ip_input = NodePath("StartMenu/IPInput")
|
||||||
|
_player_list = NodePath("ChatMenu/PlayersPanel/ScrollContainer/PlayerList")
|
||||||
|
_chat_menu = NodePath("ChatMenu")
|
||||||
|
_chat_input = NodePath("ChatMenu/ChatPanel/ChatInput")
|
||||||
|
_chat_history_scroll = NodePath("ChatMenu/ChatPanel/ChatHistoryScroll")
|
||||||
|
_chat_history = NodePath("ChatMenu/ChatPanel/ChatHistoryScroll/ChatHistory")
|
||||||
|
_start_button = NodePath("ChatMenu/StartButton")
|
||||||
|
_ingame_scene = ExtResource("2_5ajgq")
|
||||||
|
|
||||||
|
[node name="IngameSpawner" type="MultiplayerSpawner" parent="."]
|
||||||
|
_spawnable_scenes = PackedStringArray("res://src/ingame/ingame.tscn")
|
||||||
|
spawn_path = NodePath("../IngameContainer")
|
||||||
|
spawn_limit = 1
|
||||||
|
|
||||||
|
[node name="IngameContainer" type="Node" parent="."]
|
||||||
|
|
||||||
|
[node name="StartMenu" type="Control" parent="."]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -20.0
|
||||||
|
offset_top = -20.0
|
||||||
|
offset_right = 20.0
|
||||||
|
offset_bottom = 20.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="UsernameInput" type="LineEdit" parent="StartMenu"]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = -44.0
|
||||||
|
offset_top = -128.0
|
||||||
|
offset_right = 84.0
|
||||||
|
offset_bottom = -97.0
|
||||||
|
placeholder_text = "username"
|
||||||
|
alignment = 1
|
||||||
|
max_length = 12
|
||||||
|
context_menu_enabled = false
|
||||||
|
middle_mouse_paste_enabled = false
|
||||||
|
|
||||||
|
[node name="IPInput" type="LineEdit" parent="StartMenu"]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = -180.0
|
||||||
|
offset_top = 112.0
|
||||||
|
offset_right = 220.0
|
||||||
|
offset_bottom = 143.0
|
||||||
|
placeholder_text = "127.0.0.1"
|
||||||
|
alignment = 1
|
||||||
|
max_length = 39
|
||||||
|
context_menu_enabled = false
|
||||||
|
middle_mouse_paste_enabled = false
|
||||||
|
|
||||||
|
[node name="HostButton" type="Button" parent="StartMenu"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -64.0
|
||||||
|
offset_top = -100.0
|
||||||
|
offset_right = 64.0
|
||||||
|
offset_bottom = -36.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "host"
|
||||||
|
|
||||||
|
[node name="JoinButton" type="Button" parent="StartMenu"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -64.0
|
||||||
|
offset_top = 12.0
|
||||||
|
offset_right = 64.0
|
||||||
|
offset_bottom = 76.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "join"
|
||||||
|
|
||||||
|
[node name="ChatMenu" type="Control" parent="."]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -20.0
|
||||||
|
offset_top = -20.0
|
||||||
|
offset_right = 20.0
|
||||||
|
offset_bottom = 20.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="PlayersPanel" type="Panel" parent="ChatMenu"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -312.0
|
||||||
|
offset_top = -172.0
|
||||||
|
offset_right = -192.0
|
||||||
|
offset_bottom = 4.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="ScrollContainer" type="ScrollContainer" parent="ChatMenu/PlayersPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 8.0
|
||||||
|
offset_top = 8.0
|
||||||
|
offset_right = -8.0
|
||||||
|
offset_bottom = -8.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="PlayerList" type="VBoxContainer" parent="ChatMenu/PlayersPanel/ScrollContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="ChatPanel" type="Panel" parent="ChatMenu"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -312.0
|
||||||
|
offset_top = 12.0
|
||||||
|
offset_right = 312.0
|
||||||
|
offset_bottom = 172.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="ChatHistoryScroll" type="ScrollContainer" parent="ChatMenu/ChatPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 8.0
|
||||||
|
offset_top = 8.0
|
||||||
|
offset_right = -8.0
|
||||||
|
offset_bottom = -48.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="ChatHistory" type="VBoxContainer" parent="ChatMenu/ChatPanel/ChatHistoryScroll"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="ChatInput" type="LineEdit" parent="ChatMenu/ChatPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 8.0
|
||||||
|
offset_top = 120.0
|
||||||
|
offset_right = -72.0
|
||||||
|
offset_bottom = -9.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
placeholder_text = "say something"
|
||||||
|
max_length = 300
|
||||||
|
context_menu_enabled = false
|
||||||
|
clear_button_enabled = true
|
||||||
|
middle_mouse_paste_enabled = false
|
||||||
|
|
||||||
|
[node name="ChatSendButton" type="Button" parent="ChatMenu/ChatPanel"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 560.0
|
||||||
|
offset_top = 120.0
|
||||||
|
offset_right = -8.0
|
||||||
|
offset_bottom = -9.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
text = "send"
|
||||||
|
|
||||||
|
[node name="StartButton" type="Button" parent="ChatMenu"]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = -164.0
|
||||||
|
offset_top = -32.0
|
||||||
|
offset_right = -100.0
|
||||||
|
offset_bottom = 23.0
|
||||||
|
text = "Start!"
|
||||||
|
|
||||||
|
[connection signal="pressed" from="StartMenu/HostButton" to="." method="_on_host_button_pressed"]
|
||||||
|
[connection signal="pressed" from="StartMenu/JoinButton" to="." method="_on_join_button_pressed"]
|
||||||
|
[connection signal="text_submitted" from="ChatMenu/ChatPanel/ChatInput" to="." method="_on_chat_message_submitted"]
|
||||||
|
[connection signal="pressed" from="ChatMenu/ChatPanel/ChatSendButton" to="." method="_on_chat_message_submitted"]
|
||||||
|
[connection signal="pressed" from="ChatMenu/StartButton" to="." method="_on_start_button_pressed"]
|
Loading…
Reference in New Issue
Block a user