diff --git a/2d/rubegoldberg/engine.cfg b/2d/rubegoldberg/engine.cfg index 1f746c13..829133fd 100644 --- a/2d/rubegoldberg/engine.cfg +++ b/2d/rubegoldberg/engine.cfg @@ -6,5 +6,5 @@ icon="res://icon.png" [physics_2d] +default_linear_damp=0.01 default_gravity=500 -default_density=0.01 diff --git a/misc/window_management/observer/observer.gd b/misc/window_management/observer/observer.gd index f1008118..16032043 100644 --- a/misc/window_management/observer/observer.gd +++ b/misc/window_management/observer/observer.gd @@ -62,6 +62,7 @@ func _input(event): if(event.type == InputEvent.MOUSE_MOTION): r_pos = event.relative_pos + if(impulse(event, "ui_cancel")): if(state == STATE_GRAB): Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) diff --git a/misc/window_management/window_management.scn b/misc/window_management/window_management.scn index 91174669..aea8451e 100644 Binary files a/misc/window_management/window_management.scn and b/misc/window_management/window_management.scn differ diff --git a/networking/simple_multiplayer/bomb.gd b/networking/simple_multiplayer/bomb.gd new file mode 100644 index 00000000..faecd532 --- /dev/null +++ b/networking/simple_multiplayer/bomb.gd @@ -0,0 +1,35 @@ + +extends Area2D + +# member variables here, example: +# var a=2 +# var b="textvar" + +var in_area = [] +var owner +#called from the animation +func explode(): + if (not is_network_master()): + #but will call explosion only on master + return + + for p in in_area: + if (p.has_method("exploded")): + p.rpc("exploded",owner) #exploded has a master keyword, so it will only be received by the master + +func done(): + queue_free() + +func _ready(): + # Called every time the node is added to the scene. + # Initialization here + pass + +func _on_bomb_body_enter( body ): + if (not body in in_area): + in_area.append(body) + + +func _on_bomb_body_exit( body ): + in_area.erase(body) + diff --git a/networking/simple_multiplayer/bomb.tscn b/networking/simple_multiplayer/bomb.tscn new file mode 100644 index 00000000..f7119421 --- /dev/null +++ b/networking/simple_multiplayer/bomb.tscn @@ -0,0 +1,156 @@ +[gd_scene load_steps=8 format=1] + +[ext_resource path="res://bomb.gd" type="Script" id=1] +[ext_resource path="res://brickfloor.png" type="Texture" id=2] +[ext_resource path="res://explosion.png" type="Texture" id=3] + +[sub_resource type="RectangleShape2D" id=1] + +custom_solver_bias = 0.0 +extents = Vector2( 8, 96 ) + +[sub_resource type="RectangleShape2D" id=2] + +custom_solver_bias = 0.0 +extents = Vector2( 96, 8 ) + +[sub_resource type="ColorRamp" id=3] + +offsets = FloatArray( 0, 0.0233918, 0.80117, 1 ) +colors = ColorArray( 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0.922156, 0, 0, 0, 0 ) + +[sub_resource type="Animation" id=4] + +resource/name = "anim" +length = 4.0 +loop = false +step = 0.1 +tracks/0/type = "value" +tracks/0/path = NodePath("sprite:modulate") +tracks/0/interp = 1 +tracks/0/imported = false +tracks/0/keys = { "times":FloatArray( 0, 0.4, 0.6, 0.8, 1.1, 1.3, 1.5, 1.8, 1.9, 2, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 3 ), "transitions":FloatArray( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ), "update":0, "values":[ Color( 1, 1, 1, 1 ), Color( 1, 1, 1, 1 ), Color( 8, 8, 8, 1 ), Color( 1, 1, 1, 1 ), Color( 1, 1, 1, 1 ), Color( 8, 8, 8, 1 ), Color( 1, 1, 1, 1 ), Color( 1, 1, 1, 1 ), Color( 8, 8, 8, 1 ), Color( 1, 1, 1, 1 ), Color( 1, 1, 1, 1 ), Color( 8, 8, 8, 1 ), Color( 1, 1, 1, 1 ), Color( 8, 8, 8, 1 ), Color( 1, 1, 1, 1 ), Color( 8, 8, 8, 1 ), Color( 1, 1, 1, 1 ), Color( 1, 1, 1, 0 ) ] } +tracks/1/type = "value" +tracks/1/path = NodePath("explosion1:config/emitting") +tracks/1/interp = 1 +tracks/1/imported = false +tracks/1/keys = { "times":FloatArray( 2.8 ), "transitions":FloatArray( 1 ), "update":1, "values":[ true ] } +tracks/2/type = "value" +tracks/2/path = NodePath("explosion2:config/emitting") +tracks/2/interp = 1 +tracks/2/imported = false +tracks/2/keys = { "times":FloatArray( 2.8 ), "transitions":FloatArray( 1 ), "update":1, "values":[ true ] } +tracks/3/type = "method" +tracks/3/path = NodePath(".") +tracks/3/interp = 1 +tracks/3/imported = false +tracks/3/keys = { "times":FloatArray( 2.8, 3.4 ), "transitions":FloatArray( 1, 1 ), "values":[ { "args":[ ], "method":"explode" }, { "args":[ ], "method":"done" } ] } + +[node name="bomb" type="Area2D"] + +input/pickable = true +shapes/0/shape = SubResource( 1 ) +shapes/0/transform = Matrix32( 1, 0, 0, 1, 0, 0 ) +shapes/0/trigger = false +shapes/1/shape = SubResource( 2 ) +shapes/1/transform = Matrix32( 1, 0, 0, 1, 0, 0 ) +shapes/1/trigger = false +gravity_vec = Vector2( 0, 1 ) +gravity = 98.0 +linear_damp = 0.1 +angular_damp = 1.0 +script/script = ExtResource( 1 ) + +[node name="sprite" type="Sprite" parent="."] + +transform/pos = Vector2( -2.92606, -2.92606 ) +texture = ExtResource( 2 ) +region = true +region_rect = Rect2( 144, 0, 48, 48 ) + +[node name="shape1" type="CollisionShape2D" parent="."] + +shape = SubResource( 1 ) +trigger = false +_update_shape_index = 0 + +[node name="shape2" type="CollisionShape2D" parent="."] + +shape = SubResource( 2 ) +trigger = false +_update_shape_index = 1 + +[node name="explosion1" type="Particles2D" parent="."] + +config/amount = 16 +config/lifetime = 0.4 +config/emit_timeout = 0.4 +config/emitting = false +config/half_extents = Vector2( 80, 14 ) +config/explosiveness = 0.2 +config/texture = ExtResource( 3 ) +params/direction = 0.0 +params/spread = 10.0 +params/linear_velocity = 0.0 +params/spin_velocity = 3.0 +params/orbit_velocity = 0.0 +params/gravity_direction = 0.0 +params/gravity_strength = 0.0 +params/radial_accel = 0.0 +params/tangential_accel = 0.0 +params/damping = 0.0 +params/initial_angle = 358.292 +params/initial_size = 0.8 +params/final_size = 1.0 +params/hue_variation = 0.0 +params/anim_speed_scale = 1.0 +params/anim_initial_pos = 0.0 +randomness/spin_velocity = 1.0 +randomness/initial_angle = 1.0 +color/color_ramp = SubResource( 3 ) + +[node name="explosion2" type="Particles2D" parent="."] + +config/amount = 16 +config/lifetime = 0.4 +config/emit_timeout = 0.4 +config/emitting = false +config/half_extents = Vector2( 14, 80 ) +config/explosiveness = 0.2 +config/texture = ExtResource( 3 ) +params/direction = 0.0 +params/spread = 10.0 +params/linear_velocity = 0.0 +params/spin_velocity = 3.0 +params/orbit_velocity = 0.0 +params/gravity_direction = 0.0 +params/gravity_strength = 0.0 +params/radial_accel = 0.0 +params/tangential_accel = 0.0 +params/damping = 0.0 +params/initial_angle = 358.292 +params/initial_size = 0.8 +params/final_size = 1.0 +params/hue_variation = 0.0 +params/anim_speed_scale = 1.0 +params/anim_initial_pos = 0.0 +randomness/spin_velocity = 1.0 +randomness/initial_angle = 1.0 +color/color_ramp = SubResource( 3 ) + +[node name="anim" type="AnimationPlayer" parent="."] + +playback/process_mode = 1 +playback/default_blend_time = 0.0 +root/root = NodePath("..") +anims/anim = SubResource( 4 ) +playback/active = true +playback/speed = 1.0 +blend_times = [ ] +autoplay = "anim" + +[connection signal="body_enter" from="." to="." method="_on_bomb_body_enter"] + +[connection signal="body_exit" from="." to="." method="_on_bomb_body_exit"] + + diff --git a/networking/simple_multiplayer/brickfloor.png b/networking/simple_multiplayer/brickfloor.png new file mode 100644 index 00000000..f863169b Binary files /dev/null and b/networking/simple_multiplayer/brickfloor.png differ diff --git a/networking/simple_multiplayer/charwalk.png b/networking/simple_multiplayer/charwalk.png new file mode 100644 index 00000000..2812b589 Binary files /dev/null and b/networking/simple_multiplayer/charwalk.png differ diff --git a/networking/simple_multiplayer/engine.cfg b/networking/simple_multiplayer/engine.cfg new file mode 100644 index 00000000..d9af5791 --- /dev/null +++ b/networking/simple_multiplayer/engine.cfg @@ -0,0 +1,21 @@ +[application] + +name="Multiplayer Bomber" +main_scene="res://lobby.tscn" + +[autoload] + +gamestate="*res://gamestate.gd" + +[image_loader] + +filter=false +gen_mipmaps=false + +[input] + +move_left=[key(Left)] +move_right=[key(Right)] +move_up=[key(Up)] +move_down=[key(Down)] +set_bomb=[key(Space)] diff --git a/networking/simple_multiplayer/explosion.png b/networking/simple_multiplayer/explosion.png new file mode 100644 index 00000000..d0d550fc Binary files /dev/null and b/networking/simple_multiplayer/explosion.png differ diff --git a/networking/simple_multiplayer/gamestate.gd b/networking/simple_multiplayer/gamestate.gd new file mode 100644 index 00000000..fbbe8088 --- /dev/null +++ b/networking/simple_multiplayer/gamestate.gd @@ -0,0 +1,182 @@ + +extends Node + +#default game port +const DEFAULT_PORT = 10567 + +#name for my player +var player_name = "The Warrior" + +#names for remote players in id:name format +var players = {} + +#signals to let lobby GUI know what's going on +signal player_list_changed() +signal connection_failed() +signal connection_succeeded() +signal game_ended() +signal game_error(what) + +# callback from SceneTree +func _player_connected(id): + #this is not used, because _connected_ok is called for clients on success and will do the job. + pass + +# callback from SceneTree +func _player_disconnected(id): + + if (get_tree().is_network_server()): + if (has_node("/root/world")): # game is in progress + emit_signal("game_error","Player "+players[id]+" disconnected") + end_game() + else: #game is not in progress + #if we are the server, send to the new dude all the already registered playes + unregister_player(id) + for p_id in players: + #erase in the server + rpc_id( p_id, "unregister_player", id) + + +# callback from SceneTree, only for clients (not server) +func _connected_ok(): + #Registration of a client beings here, Tell everyone that we are here + rpc( "register_player", get_tree().get_network_unique_id(), player_name ) + emit_signal("connection_succeeded") + +# callback from SceneTree, only for clients (not server) +func _server_disconnected(): + emit_signal("game_error","Server disconnected") + end_game() + +# callback from SceneTree, only for clients (not server) +func _connected_fail(): + get_tree().set_network_peer(null) #remove peer + emit_signal("connection_failed") + +# lobby management functions +remote func register_player(id, name): + + if (get_tree().is_network_server()): + #if we are the server, let everyone know about the new players + rpc_id( id, "register_player", 1, player_name ) # send myself to new dude + for p_id in players: #then, for each remoe player + rpc_id( id, "register_player", p_id, players[p_id] ) # send player to new dude + rpc_id( p_id, "register_player", id, name ) # send new dude to player + + players[id]=name + + emit_signal("player_list_changed") + +remote func unregister_player(id): + players.erase(id) + emit_signal("player_list_changed") + +remote func pre_start_game(spawn_points): +#change scene + var world = load("res://world.tscn").instance() + get_tree().get_root().add_child(world) + + get_tree().get_root().get_node("lobby").hide() + + var player_scene = load("res://player.tscn") + + for p in spawn_points: + var spawn_pos = world.get_node("spawn_points/"+str(spawn_points[p])).get_pos() + var player = player_scene.instance() + + player.set_name( str(p) ) #use unique ID as node name + player.set_pos(spawn_pos) + + + if (p == get_tree().get_network_unique_id() ): + # if node for this peer id, set master + player.set_network_mode( NETWORK_MODE_MASTER ) + player.set_player_name( player_name ) + else: + # otherwise set slave + player.set_network_mode( NETWORK_MODE_SLAVE ) + player.set_player_name( players[p] ) + + world.get_node("players").add_child(player) + + #set up score + world.get_node("score").add_player(get_tree().get_network_unique_id(),player_name) + for pn in players: + world.get_node("score").add_player(pn,players[pn]) + + if (not get_tree().is_network_server()): + rpc("ready_to_start", get_tree().get_network_unique_id() ) + elif players.size()==0: + post_start_game() + + +remote func post_start_game(): + get_tree().set_pause(false) #unpause and unleash the game! + +var players_ready = [] + +remote func ready_to_start(id): + + assert( get_tree().is_network_server() ) + + if (not id in players_ready): + players_ready.append(id) + + if (players_ready.size() == players.size()): + for p in players: + rpc( "post_start_game" ) + + post_start_game() + +func host_game( name ): + player_name=name + var host = NetworkedMultiplayerENet.new() + host.create_server(DEFAULT_PORT,4) + get_tree().set_network_peer(host) + +func join_game(ip, name): + player_name=name + var host = NetworkedMultiplayerENet.new() + host.create_client(ip,DEFAULT_PORT) + get_tree().set_network_peer(host) + +func get_player_list(): + return players.values() + +func get_player_name(): + return player_name + +func begin_game(): + assert ( get_tree().is_network_server() ) + + #create a dictionary with peer id and respective spawn points, could be improved by randomizing + var spawn_points={} + spawn_points[1]=0 #server in spawn point 0 + var spawn_point_idx = 1 + for p in players: + spawn_points[p]=spawn_point_idx + spawn_point_idx+=1 + #call to pre-start game with the spawn points + for p in players: + rpc( "pre_start_game", spawn_points ) + + pre_start_game( spawn_points ) + +func end_game(): + if (has_node("/root/world")): # game is in progress + #end it + get_node("/root/world").queue_free() + + emit_signal("game_ended") + players.clear() + get_tree().set_network_peer( null ) #end networking + +func _ready(): + get_tree().connect("network_peer_connected",self,"_player_connected") + get_tree().connect("network_peer_disconnected",self,"_player_disconnected") + get_tree().connect("connected_to_server",self,"_connected_ok") + get_tree().connect("connection_failed",self,"_connected_fail") + get_tree().connect("server_disconnected",self,"_server_disconnected") + + + diff --git a/networking/simple_multiplayer/lobby.gd b/networking/simple_multiplayer/lobby.gd new file mode 100644 index 00000000..c0b29aac --- /dev/null +++ b/networking/simple_multiplayer/lobby.gd @@ -0,0 +1,85 @@ + +extends Control + +const DEFAULT_PORT = 10567 + +func _ready(): + # Called every time the node is added to the scene. + # Initialization here + gamestate.connect("connection_failed",self,"_on_connection_failed") + gamestate.connect("connection_succeeded",self,"_on_connection_success") + gamestate.connect("player_list_changed",self,"refresh_lobby") + gamestate.connect("game_ended",self,"_on_game_ended") + gamestate.connect("game_error",self,"_on_game_error") + + + pass + + +func _on_host_pressed(): + if (get_node("connect/name").get_text()==""): + get_node("connect/error_label").set_text("Invalid name!") + return + + + get_node("connect").hide() + get_node("players").show() + get_node("connect/error_label").set_text("") + + var name = get_node("connect/name").get_text() + gamestate.host_game( name ) + refresh_lobby() + + +func _on_join_pressed(): + if (get_node("connect/name").get_text()==""): + get_node("connect/error_label").set_text("Invalid name!") + return + + var ip = get_node("connect/ip").get_text() + if (not ip.is_valid_ip_address()): + get_node("connect/error_label").set_text("Invalid IPv4 Address!") + return + + get_node("connect/error_label").set_text("") + get_node("connect/host").set_disabled(true) + get_node("connect/join").set_disabled(true) + get_node("players/start").set_disabled(true) + + var name = get_node("connect/name").get_text() + + gamestate.join_game(ip,name) + refresh_lobby() + +func _on_connection_success(): + get_node("connect").hide() + get_node("players").show() + +func _on_connection_failed(): + get_node("connect/host").set_disabled(false) + get_node("connect/join").set_disabled(false) + get_node("connect/error_label").set_text("Connection Failed") + +func _on_game_ended(): + show() + get_node("connect").show() + get_node("players").hide() + get_node("connect/host").set_disabled(false) + get_node("connect/join").set_disabled(false) + +func _on_game_error(errtxt): + get_node("error").set_text(errtxt) + get_node("error").popup_centered_minsize() + +func refresh_lobby(): + var players = gamestate.get_player_list() + players.sort() + get_node("players/list").clear() + get_node("players/list").add_item(gamestate.get_player_name()+" (You)") + for p in players: + get_node("players/list").add_item(p) + + get_node("players/start").set_disabled( not get_tree().is_network_server() ) + +func _on_start_pressed(): + gamestate.begin_game() diff --git a/networking/simple_multiplayer/lobby.tscn b/networking/simple_multiplayer/lobby.tscn new file mode 100644 index 00000000..cab132f0 --- /dev/null +++ b/networking/simple_multiplayer/lobby.tscn @@ -0,0 +1,215 @@ +[gd_scene load_steps=2 format=1] + +[ext_resource path="res://lobby.gd" type="Script" id=1] + +[node name="lobby" type="Control"] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 0.0 +margin/bottom = 0.0 +script/script = ExtResource( 1 ) + +[node name="players" type="Panel" parent="."] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 393.0 +margin/top = 113.0 +margin/right = 645.0 +margin/bottom = 468.0 + +[node name="label" type="Label" parent="players"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 26.0 +margin/top = 18.0 +margin/right = 142.0 +margin/bottom = 32.0 +text = "Awaiting Players..." +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="start" type="Button" parent="players"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 68.0 +margin/top = 307.0 +margin/right = 193.0 +margin/bottom = 336.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "START!" +flat = false + +[node name="list" type="ItemList" parent="players"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 25.0 +margin/top = 37.0 +margin/right = 229.0 +margin/bottom = 296.0 + +[node name="connect" type="Panel" parent="."] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 370.0 +margin/top = 157.0 +margin/right = 647.0 +margin/bottom = 324.0 + +[node name="name_label" type="Label" parent="connect"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 14.0 +margin/top = 11.0 +margin/right = 56.0 +margin/bottom = 25.0 +text = "Name:" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="name" type="LineEdit" parent="connect"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 17.0 +margin/top = 30.0 +margin/right = 173.0 +margin/bottom = 54.0 +text = "The Warrior" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="ip_label" type="Label" parent="connect"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 15.0 +margin/top = 66.0 +margin/right = 57.0 +margin/bottom = 80.0 +text = "IP:" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="ip" type="LineEdit" parent="connect"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 17.0 +margin/top = 85.0 +margin/right = 173.0 +margin/bottom = 109.0 +text = "127.0.0.1" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="host" type="Button" parent="connect"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 181.0 +margin/top = 31.0 +margin/right = 246.0 +margin/bottom = 51.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Host" +flat = false + +[node name="join" type="Button" parent="connect"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 181.0 +margin/top = 87.0 +margin/right = 246.0 +margin/bottom = 107.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Join" +flat = false + +[node name="error_label" type="Label" parent="connect"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 15.0 +margin/top = 125.0 +margin/right = 257.0 +margin/bottom = 139.0 +custom_colors/font_color = Color( 0.820312, 0.291595, 0.291595, 1 ) +align = 1 +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="error" type="AcceptDialog" parent="."] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 55.0 +margin/bottom = 58.0 +popup/exclusive = false +window/title = "Alert!" +dialog/hide_on_ok = true + +[connection signal="pressed" from="players/start" to="." method="_on_start_pressed"] + +[connection signal="pressed" from="connect/host" to="." method="_on_host_pressed"] + +[connection signal="pressed" from="connect/join" to="." method="_on_join_pressed"] + + diff --git a/networking/simple_multiplayer/montserrat.otf b/networking/simple_multiplayer/montserrat.otf new file mode 100644 index 00000000..d5727507 Binary files /dev/null and b/networking/simple_multiplayer/montserrat.otf differ diff --git a/networking/simple_multiplayer/player.gd b/networking/simple_multiplayer/player.gd new file mode 100644 index 00000000..31dcf033 --- /dev/null +++ b/networking/simple_multiplayer/player.gd @@ -0,0 +1,103 @@ + +extends KinematicBody2D + +const MOTION_SPEED = 90.0 + +slave var slave_pos = Vector2() +slave var slave_motion = Vector2() + +export var stunned=false + +#use sync because it will be called everywhere +sync func setup_bomb(name,pos,by_who): + var bomb = preload("res://bomb.tscn").instance() + bomb.set_name( name ) #ensure unique name for the bomb + bomb.set_pos( pos ) + bomb.owner=by_who + get_node("../..").add_child(bomb) + +var current_anim="" +var prev_bombing=false +var bomb_index=0 + +func _fixed_process(delta): + + var motion = Vector2() + + if ( is_network_master() ): + + if (Input.is_action_pressed("move_left")): + motion+=Vector2(-1, 0) + if (Input.is_action_pressed("move_right")): + motion+=Vector2( 1, 0) + if (Input.is_action_pressed("move_up")): + motion+=Vector2( 0,-1) + if (Input.is_action_pressed("move_down")): + motion+=Vector2( 0, 1) + + var bombing = Input.is_action_pressed("set_bomb") + + if (stunned): + bombing=false + motion=Vector2() + + if (bombing and not prev_bombing): + var bomb_name = get_name() + str(bomb_index) + var bomb_pos = get_pos() + rpc("setup_bomb",bomb_name, bomb_pos, get_tree().get_network_unique_id() ) + + prev_bombing=bombing + motion*=delta + + + rset("slave_motion",motion) + rset("slave_pos",get_pos()) + else: + set_pos(slave_pos) + motion = slave_motion + + var new_anim="standing" + if (motion.y<0): + new_anim="walk_up" + elif (motion.y>0): + new_anim="walk_down" + elif (motion.x<0): + new_anim="walk_left" + elif (motion.x>0): + new_anim="walk_right" + + if (stunned): + new_anim="stunned" + + if (new_anim!=current_anim): + current_anim=new_anim + get_node("anim").play(current_anim) + + + var remainder = move( motion * MOTION_SPEED ) + + if (is_colliding()): + #slide through walls + move( get_collision_normal().slide( remainder ) ) + + if ( not is_network_master() ): + slave_pos = get_pos() # to avoid jitter + +slave func stun(): + stunned=true + +master func exploded(by_who): + if (stunned): + return + stun() + rpc("stun") +func set_player_name(name): + get_node("Label").set_text(name) + +func _ready(): + stunned=false + slave_pos=get_pos() + set_fixed_process(true) + pass + + diff --git a/networking/simple_multiplayer/player.tscn b/networking/simple_multiplayer/player.tscn new file mode 100644 index 00000000..099455d9 --- /dev/null +++ b/networking/simple_multiplayer/player.tscn @@ -0,0 +1,158 @@ +[gd_scene load_steps=12 format=1] + +[ext_resource path="res://player.gd" type="Script" id=1] +[ext_resource path="res://charwalk.png" type="Texture" id=2] +[ext_resource path="res://montserrat.otf" type="DynamicFontData" id=3] + +[sub_resource type="CircleShape2D" id=1] + +custom_solver_bias = 0.0 +radius = 20.0 + +[sub_resource type="Animation" id=2] + +resource/name = "standing" +length = 0.8 +loop = true +step = 0.1 +tracks/0/type = "value" +tracks/0/path = NodePath("Sprite:frame") +tracks/0/interp = 1 +tracks/0/imported = false +tracks/0/keys = { "times":FloatArray( 0, 0.2, 0.4, 0.6 ), "transitions":FloatArray( 1, 1, 1, 1 ), "update":1, "values":[ 0, 4, 8, 12 ] } + +[sub_resource type="Animation" id=3] + +resource/name = "stunned" +length = 1.2 +loop = false +step = 0.1 +tracks/0/type = "value" +tracks/0/path = NodePath("Sprite:frame") +tracks/0/interp = 1 +tracks/0/imported = false +tracks/0/keys = { "times":FloatArray( 0 ), "transitions":FloatArray( 1 ), "update":1, "values":[ 0 ] } +tracks/1/type = "value" +tracks/1/path = NodePath("Sprite:transform/rot") +tracks/1/interp = 1 +tracks/1/imported = false +tracks/1/keys = { "times":FloatArray( 0, 1, 1.1 ), "transitions":FloatArray( 1, 0, 1 ), "update":0, "values":[ 0.0, 720.0, 0.0 ] } +tracks/2/type = "value" +tracks/2/path = NodePath(".:stunned") +tracks/2/interp = 1 +tracks/2/imported = false +tracks/2/keys = { "times":FloatArray( 1 ), "transitions":FloatArray( 1 ), "update":1, "values":[ false ] } + +[sub_resource type="Animation" id=4] + +length = 0.8 +loop = true +step = 0.1 +tracks/0/type = "value" +tracks/0/path = NodePath("Sprite:frame") +tracks/0/interp = 1 +tracks/0/imported = false +tracks/0/keys = { "times":FloatArray( 0, 0.2, 0.4, 0.6 ), "transitions":FloatArray( 1, 1, 1, 1 ), "update":1, "values":[ 0, 4, 8, 12 ] } + +[sub_resource type="Animation" id=5] + +length = 0.8 +loop = true +step = 0.2 +tracks/0/type = "value" +tracks/0/path = NodePath("Sprite:frame") +tracks/0/interp = 1 +tracks/0/imported = false +tracks/0/keys = { "times":FloatArray( 0, 0.2, 0.4, 0.6 ), "transitions":FloatArray( 1, 1, 1, 1 ), "update":1, "values":[ 1, 5, 9, 13 ] } + +[sub_resource type="Animation" id=6] + +length = 0.8 +loop = true +step = 0.2 +tracks/0/type = "value" +tracks/0/path = NodePath("Sprite:frame") +tracks/0/interp = 1 +tracks/0/imported = false +tracks/0/keys = { "times":FloatArray( 0, 0.2, 0.4, 0.6 ), "transitions":FloatArray( 1, 1, 1, 1 ), "update":1, "values":[ 3, 7, 11, 15 ] } + +[sub_resource type="Animation" id=7] + +length = 0.8 +loop = true +step = 0.2 +tracks/0/type = "value" +tracks/0/path = NodePath("Sprite:frame") +tracks/0/interp = 1 +tracks/0/imported = false +tracks/0/keys = { "times":FloatArray( 0, 0.2, 0.4, 0.6 ), "transitions":FloatArray( 1, 1, 1, 1 ), "update":1, "values":[ 2, 6, 10, 14 ] } + +[sub_resource type="DynamicFont" id=8] + +font/size = 14 +font/use_mipmaps = false +font/use_filter = false +font/font = ExtResource( 3 ) + +[node name="player" type="KinematicBody2D"] + +input/pickable = false +shapes/0/shape = SubResource( 1 ) +shapes/0/transform = Matrix32( 1, 0, 0, 1, 0, 0 ) +shapes/0/trigger = false +collision/layers = 1 +collision/mask = 1 +collision/margin = 0.08 +script/script = ExtResource( 1 ) +stunned = false + +[node name="Sprite" type="Sprite" parent="."] + +transform/pos = Vector2( 0.0750351, 6.23615 ) +texture = ExtResource( 2 ) +offset = Vector2( -0.0750351, -6.23615 ) +vframes = 4 +hframes = 4 + +[node name="shape" type="CollisionShape2D" parent="."] + +shape = SubResource( 1 ) +trigger = false +_update_shape_index = 0 + +[node name="anim" type="AnimationPlayer" parent="."] + +playback/process_mode = 1 +playback/default_blend_time = 0.0 +root/root = NodePath("..") +anims/standing = SubResource( 2 ) +anims/stunned = SubResource( 3 ) +anims/walk_down = SubResource( 4 ) +anims/walk_left = SubResource( 5 ) +anims/walk_right = SubResource( 6 ) +anims/walk_up = SubResource( 7 ) +next/walk_down = "" +playback/active = true +playback/speed = 1.0 +blend_times = [ ] +autoplay = "" + +[node name="Label" type="Label" parent="."] + +visibility/opacity = 0.7 +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = -82.0 +margin/top = -35.0 +margin/right = 85.0 +margin/bottom = -14.0 +custom_fonts/font = SubResource( 8 ) +text = "Player 1" +align = 1 +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + + diff --git a/networking/simple_multiplayer/rock.gd b/networking/simple_multiplayer/rock.gd new file mode 100644 index 00000000..252638ec --- /dev/null +++ b/networking/simple_multiplayer/rock.gd @@ -0,0 +1,14 @@ + +extends KinematicBody2D + +#sent to everyone else +slave func do_explosion(): + get_node("anim").play("explode") + +#received by owner of the rock +master func exploded(by_who): + rpc("do_explosion") #re-sent to slave rocks + get_node("../../score").rpc("increase_score",by_who) + do_explosion() + + \ No newline at end of file diff --git a/networking/simple_multiplayer/rock.tscn b/networking/simple_multiplayer/rock.tscn new file mode 100644 index 00000000..92e99c9b --- /dev/null +++ b/networking/simple_multiplayer/rock.tscn @@ -0,0 +1,101 @@ +[gd_scene load_steps=7 format=1] + +[ext_resource path="res://rock.gd" type="Script" id=1] +[ext_resource path="res://brickfloor.png" type="Texture" id=2] +[ext_resource path="res://rock_bit.png" type="Texture" id=3] + +[sub_resource type="RectangleShape2D" id=1] + +custom_solver_bias = 0.0 +extents = Vector2( 24, 24 ) + +[sub_resource type="ColorRamp" id=2] + +offsets = FloatArray( 0, 0.860465, 1 ) +colors = ColorArray( 1, 1, 1, 1, 0.860465, 0.860465, 0.860465, 1, 1, 1, 1, 0 ) + +[sub_resource type="Animation" id=3] + +resource/name = "explode" +length = 1.0 +loop = false +step = 0.1 +tracks/0/type = "value" +tracks/0/path = NodePath("explosion:config/emitting") +tracks/0/interp = 1 +tracks/0/imported = false +tracks/0/keys = { "times":FloatArray( 0 ), "transitions":FloatArray( 1 ), "update":1, "values":[ true ] } +tracks/1/type = "method" +tracks/1/path = NodePath(".") +tracks/1/interp = 1 +tracks/1/imported = false +tracks/1/keys = { "times":FloatArray( 1 ), "transitions":FloatArray( 1 ), "values":[ { "args":[ ], "method":"queue_free" } ] } +tracks/2/type = "value" +tracks/2/path = NodePath("sprite:visibility/visible") +tracks/2/interp = 1 +tracks/2/imported = false +tracks/2/keys = { "times":FloatArray( 0 ), "transitions":FloatArray( 1 ), "update":1, "values":[ false ] } + +[node name="rock" type="KinematicBody2D"] + +input/pickable = false +shapes/0/shape = SubResource( 1 ) +shapes/0/transform = Matrix32( 1, 0, 0, 1, 0, 0 ) +shapes/0/trigger = false +collision/layers = 1 +collision/mask = 1 +collision/margin = 0.001 +script/script = ExtResource( 1 ) + +[node name="sprite" type="Sprite" parent="."] + +texture = ExtResource( 2 ) +region = true +region_rect = Rect2( 96, 0, 48, 48 ) + +[node name="shape" type="CollisionShape2D" parent="."] + +shape = SubResource( 1 ) +trigger = false +_update_shape_index = 0 + +[node name="explosion" type="Particles2D" parent="."] + +config/amount = 32 +config/lifetime = 0.8 +config/emit_timeout = 0.8 +config/emitting = false +config/half_extents = Vector2( 15, 15 ) +config/explosiveness = 0.1 +config/texture = ExtResource( 3 ) +params/direction = 0.0 +params/spread = 180.0 +params/linear_velocity = 100.0 +params/spin_velocity = 4.0 +params/orbit_velocity = 0.0 +params/gravity_direction = 0.0 +params/gravity_strength = 90.0 +params/radial_accel = 0.0 +params/tangential_accel = 0.0 +params/damping = 0.0 +params/initial_angle = 0.0 +params/initial_size = 2.0 +params/final_size = 2.0 +params/hue_variation = 0.0 +params/anim_speed_scale = 1.0 +params/anim_initial_pos = 0.0 +randomness/spin_velocity = 0.95 +color/color_ramp = SubResource( 2 ) + +[node name="anim" type="AnimationPlayer" parent="."] + +playback/process_mode = 1 +playback/default_blend_time = 0.0 +root/root = NodePath("..") +anims/explode = SubResource( 3 ) +playback/active = true +playback/speed = 1.0 +blend_times = [ ] +autoplay = "" + + diff --git a/networking/simple_multiplayer/rock_bit.png b/networking/simple_multiplayer/rock_bit.png new file mode 100644 index 00000000..f4971815 Binary files /dev/null and b/networking/simple_multiplayer/rock_bit.png differ diff --git a/networking/simple_multiplayer/score.gd b/networking/simple_multiplayer/score.gd new file mode 100644 index 00000000..06fe94e8 --- /dev/null +++ b/networking/simple_multiplayer/score.gd @@ -0,0 +1,56 @@ + +extends HBoxContainer + +# member variables here, example: +# var a=2 +# var b="textvar" + +var player_labels={} + +func _process(delta): + + var rocks_left = get_node("../rocks").get_child_count() + if (rocks_left==0): + var winner_name = "" + var winner_score = 0 + for p in player_labels: + if (player_labels[p].score > winner_score): + winner_score=player_labels[p].score + winner_name=player_labels[p].name + + get_node("../winner").set_text("THE WINNER IS:\n"+winner_name) + get_node("../winner").show() + + + + +sync func increase_score(for_who): + assert( for_who in player_labels ) + var pl = player_labels[for_who] + pl.score+=1 + pl.label.set_text( pl.name+"\n"+str(pl.score) ) + + +func add_player(id,name): + var l = Label.new() + l.set_align(Label.ALIGN_CENTER) + l.set_text(name+"\n"+"0") + l.set_h_size_flags(SIZE_EXPAND_FILL) + var font = DynamicFont.new() + font.set_size(18) + font.set_font_data( preload("res://montserrat.otf" ) ) + l.add_font_override("font",font) + + add_child(l) + + player_labels[id]={ name=name, label=l, score=0 } + +func _ready(): + get_node("../winner").hide() + set_process(true) + + + +func _on_exit_game_pressed(): + gamestate.end_game() + diff --git a/networking/simple_multiplayer/tile_scene.tscn b/networking/simple_multiplayer/tile_scene.tscn new file mode 100644 index 00000000..604e4c31 --- /dev/null +++ b/networking/simple_multiplayer/tile_scene.tscn @@ -0,0 +1,45 @@ +[gd_scene load_steps=3 format=1] + +[ext_resource path="res://brickfloor.png" type="Texture" id=1] + +[sub_resource type="RectangleShape2D" id=1] + +custom_solver_bias = 0.0 +extents = Vector2( 24, 24 ) + +[node name="Node2D" type="Node2D"] + +[node name="wall" type="Sprite" parent="."] + +transform/pos = Vector2( 24, 24 ) +texture = ExtResource( 1 ) +region = true +region_rect = Rect2( 0, 0, 48, 48 ) + +[node name="col" type="StaticBody2D" parent="wall"] + +input/pickable = false +shapes/0/shape = SubResource( 1 ) +shapes/0/transform = Matrix32( 1, 0, 0, 1, 0, 0 ) +shapes/0/trigger = false +collision/layers = 1 +collision/mask = 1 +constant_linear_velocity = Vector2( 0, 0 ) +constant_angular_velocity = 0.0 +friction = 1.0 +bounce = 0.0 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="wall/col"] + +shape = SubResource( 1 ) +trigger = false +_update_shape_index = 0 + +[node name="floor" type="Sprite" parent="."] + +transform/pos = Vector2( 72, 24 ) +texture = ExtResource( 1 ) +region = true +region_rect = Rect2( 48, 0, 48, 48 ) + + diff --git a/networking/simple_multiplayer/tileset.tres b/networking/simple_multiplayer/tileset.tres new file mode 100644 index 00000000..e75615ca --- /dev/null +++ b/networking/simple_multiplayer/tileset.tres @@ -0,0 +1,28 @@ +[gd_resource type="TileSet" load_steps=3 format=1] + +[ext_resource path="res://brickfloor.png" type="Texture" id=1] + +[sub_resource type="RectangleShape2D" id=1] + +custom_solver_bias = 0.0 +extents = Vector2( 24, 24 ) + +[resource] + +0/name = "wall" +0/texture = ExtResource( 1 ) +0/tex_offset = Vector2( 0, 0 ) +0/region = Rect2( 0, 0, 48, 48 ) +0/occluder_offset = Vector2( 24, 24 ) +0/navigation_offset = Vector2( 24, 24 ) +0/shape_offset = Vector2( 24, 24 ) +0/shapes = [ SubResource( 1 ) ] +1/name = "floor" +1/texture = ExtResource( 1 ) +1/tex_offset = Vector2( 0, 0 ) +1/region = Rect2( 48, 0, 48, 48 ) +1/occluder_offset = Vector2( 24, 24 ) +1/navigation_offset = Vector2( 24, 24 ) +1/shape_offset = Vector2( 0, 0 ) +1/shapes = [ ] + diff --git a/networking/simple_multiplayer/world.tscn b/networking/simple_multiplayer/world.tscn new file mode 100644 index 00000000..959ff811 --- /dev/null +++ b/networking/simple_multiplayer/world.tscn @@ -0,0 +1,427 @@ +[gd_scene load_steps=6 format=1] + +[ext_resource path="res://tileset.tres" type="TileSet" id=1] +[ext_resource path="res://rock.tscn" type="PackedScene" id=2] +[ext_resource path="res://score.gd" type="Script" id=3] +[ext_resource path="res://montserrat.otf" type="DynamicFontData" id=4] + +[sub_resource type="DynamicFont" id=1] + +font/size = 44 +font/use_mipmaps = false +font/use_filter = false +font/font = ExtResource( 4 ) + +[node name="world" type="Node2D"] + +[node name="map" type="TileMap" parent="."] + +mode = 0 +tile_set = ExtResource( 1 ) +cell/size = Vector2( 48, 48 ) +cell/quadrant_size = 16 +cell/custom_transform = Matrix32( 1, 0, 0, 1, 0, 0 ) +cell/half_offset = 2 +cell/tile_origin = 0 +cell/y_sort = false +collision/use_kinematic = false +collision/friction = 1.0 +collision/bounce = 0.0 +collision/layers = 1 +collision/mask = 1 +occluder/light_mask = 1 +tile_data = IntArray( 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 65536, 0, 65537, 1, 65538, 1, 65539, 1, 65540, 1, 65541, 1, 65542, 1, 65543, 1, 65544, 1, 65545, 1, 65546, 1, 65547, 1, 65548, 1, 65549, 1, 65550, 1, 65551, 1, 65552, 1, 65553, 1, 65554, 1, 65555, 1, 65556, 0, 65557, 0, 131072, 0, 131073, 1, 131074, 0, 131075, 1, 131076, 0, 131077, 1, 131078, 0, 131079, 1, 131080, 0, 131081, 1, 131082, 0, 131083, 0, 131084, 0, 131085, 0, 131086, 0, 131087, 1, 131088, 0, 131089, 1, 131090, 0, 131091, 1, 131092, 0, 131093, 0, 196608, 0, 196609, 1, 196610, 1, 196611, 1, 196612, 0, 196613, 1, 196614, 1, 196615, 1, 196616, 1, 196617, 1, 196618, 0, 196619, 1, 196620, 1, 196621, 1, 196622, 1, 196623, 1, 196624, 1, 196625, 1, 196626, 1, 196627, 1, 196628, 0, 196629, 0, 262144, 0, 262145, 1, 262146, 0, 262147, 1, 262148, 0, 262149, 1, 262150, 0, 262151, 1, 262152, 0, 262153, 1, 262154, 0, 262155, 1, 262156, 0, 262157, 1, 262158, 0, 262159, 1, 262160, 0, 262161, 1, 262162, 0, 262163, 1, 262164, 0, 262165, 0, 327680, 0, 327681, 1, 327682, 1, 327683, 1, 327684, 1, 327685, 1, 327686, 0, 327687, 1, 327688, 1, 327689, 1, 327690, 1, 327691, 1, 327692, 1, 327693, 1, 327694, 1, 327695, 1, 327696, 1, 327697, 1, 327698, 0, 327699, 1, 327700, 0, 327701, 0, 393216, 0, 393217, 1, 393218, 0, 393219, 1, 393220, 0, 393221, 1, 393222, 0, 393223, 1, 393224, 0, 393225, 1, 393226, 0, 393227, 1, 393228, 0, 393229, 0, 393230, 0, 393231, 0, 393232, 0, 393233, 1, 393234, 0, 393235, 1, 393236, 0, 393237, 0, 458752, 0, 458753, 1, 458754, 1, 458755, 1, 458756, 1, 458757, 1, 458758, 1, 458759, 1, 458760, 1, 458761, 1, 458762, 1, 458763, 1, 458764, 1, 458765, 1, 458766, 1, 458767, 1, 458768, 1, 458769, 1, 458770, 1, 458771, 1, 458772, 0, 458773, 0, 524288, 0, 524289, 1, 524290, 0, 524291, 0, 524292, 0, 524293, 1, 524294, 0, 524295, 1, 524296, 0, 524297, 1, 524298, 0, 524299, 1, 524300, 0, 524301, 0, 524302, 0, 524303, 1, 524304, 0, 524305, 1, 524306, 0, 524307, 1, 524308, 0, 524309, 0, 589824, 0, 589825, 1, 589826, 1, 589827, 1, 589828, 1, 589829, 1, 589830, 1, 589831, 1, 589832, 0, 589833, 1, 589834, 1, 589835, 1, 589836, 0, 589837, 1, 589838, 1, 589839, 1, 589840, 1, 589841, 1, 589842, 1, 589843, 1, 589844, 0, 589845, 0, 655360, 0, 655361, 1, 655362, 0, 655363, 1, 655364, 0, 655365, 1, 655366, 0, 655367, 1, 655368, 0, 655369, 1, 655370, 0, 655371, 1, 655372, 0, 655373, 1, 655374, 0, 655375, 1, 655376, 0, 655377, 1, 655378, 0, 655379, 1, 655380, 0, 655381, 0, 720896, 0, 720897, 1, 720898, 1, 720899, 1, 720900, 1, 720901, 1, 720902, 1, 720903, 1, 720904, 1, 720905, 1, 720906, 1, 720907, 1, 720908, 1, 720909, 1, 720910, 1, 720911, 1, 720912, 1, 720913, 1, 720914, 1, 720915, 1, 720916, 0, 720917, 0, 786432, 0, 786433, 0, 786434, 0, 786435, 0, 786436, 0, 786437, 0, 786438, 0, 786439, 0, 786440, 0, 786441, 0, 786442, 0, 786443, 0, 786444, 0, 786445, 0, 786446, 0, 786447, 0, 786448, 0, 786449, 0, 786450, 0, 786451, 0, 786452, 0, 786453, 0 ) +__meta__ = { "_edit_lock_":true } + +[node name="spawn_points" type="Node2D" parent="."] + +editor/display_folded = true + +[node name="0" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 72, 72 ) + +[node name="1" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 264, 216 ) + +[node name="2" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 72, 456 ) + +[node name="3" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 360, 552 ) + +[node name="4" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 840, 360 ) + +[node name="5" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 456, 264 ) + +[node name="6" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 696, 264 ) + +[node name="7" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 744, 456 ) + +[node name="8" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 312, 456 ) + +[node name="9" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 696, 72 ) + +[node name="10" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 504, 72 ) + +[node name="11" type="Position2D" parent="spawn_points"] + +transform/pos = Vector2( 936, 72 ) + +[node name="rocks" type="Node2D" parent="."] + +[node name="rock" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 120, 72 ) + +[node name="rock1" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 264, 168 ) + +[node name="rock2" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 264, 120 ) + +[node name="rock3" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 216, 72 ) + +[node name="rock4" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 264, 72 ) + +[node name="rock5" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 312, 72 ) + +[node name="rock6" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 552, 168 ) + +[node name="rock7" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 600, 168 ) + +[node name="rock8" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 552, 216 ) + +[node name="rock9" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 264, 312 ) + +[node name="rock10" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 120, 360 ) + +[node name="rock11" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 168, 360 ) + +[node name="rock12" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 216, 360 ) + +[node name="rock13" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 120, 264 ) + +[node name="rock14" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 168, 216 ) + +[node name="rock15" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 72, 360 ) + +[node name="rock16" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 72, 312 ) + +[node name="rock17" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 72, 264 ) + +[node name="rock18" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 360, 360 ) + +[node name="rock19" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 408, 360 ) + +[node name="rock20" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 504, 360 ) + +[node name="rock21" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 600, 360 ) + +[node name="rock22" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 648, 360 ) + +[node name="rock23" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 504, 456 ) + +[node name="rock24" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 552, 456 ) + +[node name="rock25" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 552, 408 ) + +[node name="rock26" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 360, 456 ) + +[node name="rock27" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 360, 504 ) + +[node name="rock28" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 264, 504 ) + +[node name="rock29" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 264, 552 ) + +[node name="rock30" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 168, 456 ) + +[node name="rock31" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 168, 504 ) + +[node name="rock32" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 72, 552 ) + +[node name="rock33" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 120, 552 ) + +[node name="rock34" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 504, 552 ) + +[node name="rock35" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 600, 552 ) + +[node name="rock36" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 648, 552 ) + +[node name="rock37" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 648, 504 ) + +[node name="rock38" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 456, 216 ) + +[node name="rock39" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 360, 216 ) + +[node name="rock40" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 360, 168 ) + +[node name="rock41" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 456, 120 ) + +[node name="rock42" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 456, 408 ) + +[node name="rock43" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 456, 456 ) + +[node name="rock44" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 456, 504 ) + +[node name="rock45" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 600, 264 ) + +[node name="rock46" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 600, 72 ) + +[node name="rock47" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 408, 72 ) + +[node name="rock48" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 792, 168 ) + +[node name="rock49" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 744, 168 ) + +[node name="rock50" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 744, 264 ) + +[node name="rock51" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 792, 264 ) + +[node name="rock52" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 744, 360 ) + +[node name="rock53" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 744, 408 ) + +[node name="rock54" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 792, 552 ) + +[node name="rock55" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 840, 552 ) + +[node name="rock56" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 840, 504 ) + +[node name="rock57" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 840, 312 ) + +[node name="rock58" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 840, 264 ) + +[node name="rock59" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 840, 216 ) + +[node name="rock60" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 840, 120 ) + +[node name="rock61" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 792, 72 ) + +[node name="rock62" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 840, 72 ) + +[node name="rock63" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 936, 216 ) + +[node name="rock64" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 936, 264 ) + +[node name="rock65" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 936, 408 ) + +[node name="rock66" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 888, 456 ) + +[node name="rock67" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 936, 456 ) + +[node name="rock68" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 792, 456 ) + +[node name="rock69" parent="rocks" instance=ExtResource( 2 )] + +transform/pos = Vector2( 840, 456 ) + +[node name="players" type="Node2D" parent="."] + +[node name="score" type="HBoxContainer" parent="."] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1024.0 +margin/bottom = 40.0 +alignment = 0 +script/script = ExtResource( 3 ) + +[node name="winner" type="Label" parent="."] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1031.0 +margin/bottom = 617.0 +custom_fonts/font = SubResource( 1 ) +custom_colors/font_color_shadow = Color( 0, 0, 0, 1 ) +custom_constants/shadow_offset_x = 2 +custom_constants/shadow_offset_y = 2 +custom_constants/shadow_as_outline = 1 +text = "THE WINNER IS:\nYOU" +align = 1 +valign = 1 +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="exit_game" type="Button" parent="winner"] + +process/pause_mode = 2 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 384.0 +margin/top = 408.0 +margin/right = 649.0 +margin/bottom = 469.0 +custom_fonts/font = SubResource( 1 ) +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "EXIT GAME" +flat = false + +[connection signal="pressed" from="winner/exit_game" to="score" method="_on_exit_game_pressed"] + + diff --git a/misc/udp_chat/chat.gd b/networking/udp_chat/chat.gd similarity index 100% rename from misc/udp_chat/chat.gd rename to networking/udp_chat/chat.gd diff --git a/misc/udp_chat/chat.scn b/networking/udp_chat/chat.scn similarity index 100% rename from misc/udp_chat/chat.scn rename to networking/udp_chat/chat.scn diff --git a/misc/udp_chat/engine.cfg b/networking/udp_chat/engine.cfg similarity index 100% rename from misc/udp_chat/engine.cfg rename to networking/udp_chat/engine.cfg diff --git a/misc/udp_chat/icon.png b/networking/udp_chat/icon.png similarity index 100% rename from misc/udp_chat/icon.png rename to networking/udp_chat/icon.png