online multiplayer chess game (note server currently down)
pointless multiplayer + better san display
| -rw-r--r-- | Grid.gd | 10 | ||||
| -rw-r--r-- | Utils.gd | 2 | ||||
| -rw-r--r-- | World.gd | 4 | ||||
| -rw-r--r-- | World.tscn | 4 | ||||
| -rw-r--r-- | ui/GameUI.tscn | 90 | ||||
| -rw-r--r-- | ui/Lobby.gd | 135 | ||||
| -rw-r--r-- | ui/Lobby.tscn | 104 | ||||
| -rw-r--r-- | ui/MovesList.gd | 41 | ||||
| -rw-r--r-- | ui/StartMenu.gd | 5 | ||||
| -rw-r--r-- | ui/StartMenu.tscn | 7 | ||||
| -rw-r--r-- | ui/flatblack.tres | 1 | ||||
| -rw-r--r-- | ui/main.tres | 12 |
12 files changed, 394 insertions, 21 deletions
@@ -140,7 +140,7 @@ func drawed(): Events.emit_signal("game_over") SoundFx.play("Draw") yield(get_tree().create_timer(5), "timeout") - get_tree().reload_current_scene() + get_parent().emit_signal("game_over") SoundFx.play("Victory") @@ -149,7 +149,7 @@ func win(winner): print(winner, " won the game in ", Globals.turns(winner), " turns!") SoundFx.play("Victory") yield(get_tree().create_timer(5), "timeout") - get_tree().reload_current_scene() + get_parent().emit_signal("game_over") SoundFx.play("Victory") @@ -212,9 +212,9 @@ func init_board(): # create the board func add_pieces(): # add the pieces add_pawns() - # add_rooks() - # add_knights() - # add_bishops() + add_rooks() + add_knights() + add_bishops() add_queens() add_kings() @@ -20,7 +20,7 @@ func add_move(move): turn_moves.append(str(Globals.white_turns + 1) + ". " + move) else: turn_moves.append(move) - emit_signal("newmove", turn_moves[-1]) + emit_signal("newmove", move) func calculate_algebraic_position(real_position): diff --git a/World.gd b/World.gd new file mode 100644 index 0000000..6abfb7f --- /dev/null +++ b/World.gd @@ -0,0 +1,4 @@ +extends Node2D + +# warning-ignore-all:unused_signal +signal game_over @@ -1,9 +1,11 @@ -[gd_scene load_steps=3 format=2] +[gd_scene load_steps=4 format=2] [ext_resource path="res://Grid.gd" type="Script" id=1] [ext_resource path="res://ui/GameUI.tscn" type="PackedScene" id=2] +[ext_resource path="res://World.gd" type="Script" id=3] [node name="World" type="Node2D"] +script = ExtResource( 3 ) [node name="Grid" type="Node2D" parent="."] script = ExtResource( 1 ) diff --git a/ui/GameUI.tscn b/ui/GameUI.tscn index 9fc8a58..0e2afc5 100644 --- a/ui/GameUI.tscn +++ b/ui/GameUI.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=9 format=2] +[gd_scene load_steps=22 format=2] [ext_resource path="res://ui/main.tres" type="Theme" id=1] [ext_resource path="res://ui/roboto.tres" type="DynamicFont" id=2] @@ -7,11 +7,83 @@ [ext_resource path="res://ui/Timer.gd" type="Script" id=5] [ext_resource path="res://ui/MovesList.gd" type="Script" id=6] [ext_resource path="res://ui/Status.gd" type="Script" id=7] +[ext_resource path="res://assets/ui/whitespace.png" type="Texture" id=8] +[ext_resource path="res://assets/ui/verdana-bold.ttf" type="DynamicFontData" id=9] +[ext_resource path="res://assets/ui/checkedbox.png" type="Texture" id=10] +[ext_resource path="res://assets/ui/button.png" type="Texture" id=11] +[ext_resource path="res://ui/flatblack.tres" type="StyleBox" id=12] +[ext_resource path="res://ui/button.tres" type="StyleBox" id=13] +[ext_resource path="res://ui/buttonhover.tres" type="StyleBox" id=14] [sub_resource type="DynamicFont" id=1] size = 25 font_data = ExtResource( 3 ) +[sub_resource type="StyleBoxEmpty" id=2] + +[sub_resource type="StyleBoxEmpty" id=4] + +[sub_resource type="StyleBoxFlat" id=3] +bg_color = Color( 0.0784314, 0.0784314, 0.0784314, 1 ) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color( 1, 1, 1, 1 ) +corner_detail = 20 + +[sub_resource type="StyleBoxEmpty" id=5] + +[sub_resource type="DynamicFont" id=7] +size = 35 +font_data = ExtResource( 9 ) + +[sub_resource type="Theme" id=6] +default_font = SubResource( 7 ) +Button/colors/font_color = Color( 1, 1, 1, 1 ) +Button/colors/font_color_focus = Color( 1, 1, 1, 1 ) +Button/colors/font_color_hover = Color( 0, 0, 0, 1 ) +Button/colors/font_color_pressed = Color( 1, 1, 1, 1 ) +Button/styles/disabled = SubResource( 2 ) +Button/styles/focus = ExtResource( 13 ) +Button/styles/hover = ExtResource( 14 ) +Button/styles/normal = ExtResource( 13 ) +Button/styles/pressed = ExtResource( 13 ) +CheckBox/icons/checked = ExtResource( 10 ) +CheckBox/icons/checked_disabled = null +CheckBox/icons/radio_checked = null +CheckBox/icons/radio_checked_disabled = null +CheckBox/icons/radio_unchecked = null +CheckBox/icons/radio_unchecked_disabled = null +CheckBox/icons/unchecked = ExtResource( 11 ) +CheckBox/icons/unchecked_disabled = null +HBoxContainer/constants/separation = 15 +ItemList/colors/font_color = Color( 1, 1, 1, 1 ) +ItemList/colors/font_color_selected = Color( 0.905882, 0.905882, 0.905882, 1 ) +ItemList/styles/bg = SubResource( 4 ) +ItemList/styles/bg_focus = ExtResource( 12 ) +LineEdit/colors/cursor_color = Color( 1, 1, 1, 1 ) +LineEdit/colors/font_color = Color( 1, 1, 1, 1 ) +LineEdit/colors/font_color_uneditable = Color( 1, 1, 1, 0.67451 ) +LineEdit/styles/focus = ExtResource( 13 ) +LineEdit/styles/normal = ExtResource( 13 ) +LineEdit/styles/read_only = ExtResource( 13 ) +OptionButton/colors/font_color = Color( 1, 1, 1, 1 ) +OptionButton/colors/font_color_focus = Color( 1, 1, 1, 1 ) +OptionButton/colors/font_color_hover = Color( 0, 0, 0, 1 ) +OptionButton/colors/font_color_pressed = Color( 1, 1, 1, 1 ) +OptionButton/icons/arrow = ExtResource( 8 ) +PopupMenu/colors/font_color = Color( 1, 1, 1, 1 ) +PopupMenu/colors/font_color_accel = Color( 1, 1, 1, 0.8 ) +PopupMenu/colors/font_color_hover = Color( 1, 1, 1, 1 ) +PopupMenu/colors/font_color_separator = Color( 0.262745, 0.262745, 0.262745, 1 ) +PopupMenu/icons/radio_checked = ExtResource( 8 ) +PopupMenu/icons/radio_unchecked = ExtResource( 8 ) +PopupMenu/styles/hover = SubResource( 3 ) +PopupMenu/styles/panel = ExtResource( 12 ) +VBoxContainer/constants/separation = 15 +VScrollBar/styles/scroll = SubResource( 5 ) + [node name="UI" type="CanvasLayer"] [node name="Holder" type="Control" parent="."] @@ -65,24 +137,28 @@ color = Color( 0, 0, 0, 1 ) [node name="Status" type="Label" parent="Holder/Back/VBox"] visible = false -margin_top = 355.0 +margin_top = 259.0 margin_right = 400.0 -margin_bottom = 386.0 +margin_bottom = 290.0 custom_fonts/font = SubResource( 1 ) +text = "hi there" align = 1 autowrap = true script = ExtResource( 7 ) -[node name="MovesList" type="ItemList" parent="Holder/Back/VBox"] +[node name="MovesList" type="ScrollContainer" parent="Holder/Back/VBox"] margin_top = 300.0 margin_right = 400.0 margin_bottom = 500.0 rect_min_size = Vector2( 0, 200 ) -focus_mode = 0 -custom_constants/hseparation = 25 -max_columns = 2 +theme = SubResource( 6 ) +scroll_horizontal_enabled = false script = ExtResource( 6 ) +[node name="sans" type="GridContainer" parent="Holder/Back/VBox/MovesList"] +custom_constants/vseparation = 0 +columns = 3 + [node name="WhiteTime" type="Label" parent="Holder/Back/VBox"] margin_top = 550.0 margin_right = 400.0 diff --git a/ui/Lobby.gd b/ui/Lobby.gd new file mode 100644 index 0000000..0637e84 --- /dev/null +++ b/ui/Lobby.gd @@ -0,0 +1,135 @@ +# Default game server port. Can be any number between 1024 and 49151. +# Not on the list of registered or common ports as of November 2020: +# https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers +extends Control + +# Default game server port. Can be any number between 1024 and 49151. +# Not on the list of registered or common ports as of November 2020: +# https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers +const DEFAULT_PORT = 8910 + +var peer = null + +onready var address: LineEdit = $Back/Center/HBox/VBox/Address +onready var host_button = $Back/Center/HBox/VBox/HBox/HostButton +onready var join_button = $Back/Center/HBox/VBox/HBox/JoinButton +onready var status_ok = $Back/Center/HBox/VBox/StatusOK +onready var status_fail = $Back/Center/HBox/VBox/StatusFail +onready var port_forward_label = $Back/Center/HBox/VBox2/Portforward +onready var find_public_ip_button = $Back/Center/HBox/VBox2/FindPublicIP + + +func toggle(onoff): + visible = onoff + + +func _ready(): + address.get_menu() + # Connect all the callbacks related to networking. + 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") + + +#### Network callbacks from SceneTree #### + + +# Callback from SceneTree. +func _player_connected(_id): + # Someone connected, start the game! + var chess = load("res://World.tscn").instance() + # Connect deferred so we can safely erase it from the callback. + chess.connect("game_over", self, "_end_game", [], CONNECT_DEFERRED) + + get_tree().get_root().add_child(chess) + + +func _player_disconnected(_id): + if get_tree().is_network_server(): + _end_game("Client disconnected") + else: + _end_game("Server disconnected") + + +# Callback from SceneTree, only for clients (not server). +func _connected_ok(): + pass # This function is not needed for this project. + + +# Callback from SceneTree, only for clients (not server). +func _connected_fail(): + _set_status("Couldn't connect", false) + + get_tree().set_network_peer(null) # Remove peer. + host_button.show() + address.editable = true + + +func _server_disconnected(): + _end_game("Server disconnected") + + +##### Game creation functions ###### + + +func _end_game(_with_error = ""): + if has_node("/root/World"): + # Erase immediately, otherwise network might show + # errors (this is why we connected deferred above). + get_node("/root/World").free() + show() + + get_tree().set_network_peer(null) # Remove peer. + host_button.show() + join_button.show() + address.editable = true + + +func _set_status(text, isok): + # Simple way to show status. + if isok: + status_ok.set_text(text) + status_fail.set_text("") + status_ok.visible = len(status_ok.text) > 0 + status_fail.visible = len(status_fail.text) > 0 + else: + status_ok.set_text("") + status_fail.set_text(text) + status_fail.visible = len(status_fail.text) > 0 + status_ok.visible = len(status_ok.text) > 0 + + +func _on_host_pressed(): + peer = NetworkedMultiplayerENet.new() + peer.set_compression_mode(NetworkedMultiplayerENet.COMPRESS_RANGE_CODER) + var err = peer.create_server(DEFAULT_PORT, 1) # Maximum of 1 peer, since it's a 2-player game. + if err != OK: + # Is another server running? + _set_status("Can't host, address in use.", false) + return + + get_tree().set_network_peer(peer) + host_button.hide() + address.editable = false + join_button.hide() + _set_status("Waiting for player...", true) + + # Only show hosting instructions when relevant. + + +func _on_join_pressed(): + var ip = address.get_text() + if not ip.is_valid_ip_address(): + _set_status("IP address is invalid", false) + return + + peer = NetworkedMultiplayerENet.new() + peer.set_compression_mode(NetworkedMultiplayerENet.COMPRESS_RANGE_CODER) + peer.create_client(ip, DEFAULT_PORT) + get_tree().set_network_peer(peer) + + +func _on_find_public_ip_pressed(): + OS.shell_open("https://icanhazip.com/") diff --git a/ui/Lobby.tscn b/ui/Lobby.tscn index 67f3236..02e0148 100644 --- a/ui/Lobby.tscn +++ b/ui/Lobby.tscn @@ -1,5 +1,107 @@ -[gd_scene format=2] +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://ui/main.tres" type="Theme" id=1] +[ext_resource path="res://ui/Lobby.gd" type="Script" id=2] +[ext_resource path="res://assets/ui/verdana-bold.ttf" type="DynamicFontData" id=3] + +[sub_resource type="DynamicFont" id=1] +size = 30 +font_data = ExtResource( 3 ) [node name="Lobby" type="Control"] anchor_right = 1.0 anchor_bottom = 1.0 +theme = ExtResource( 1 ) +script = ExtResource( 2 ) + +[node name="Back" type="ColorRect" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +color = Color( 0, 0, 0, 0.784314 ) + +[node name="Center" type="CenterContainer" parent="Back"] +anchor_right = 1.0 +anchor_bottom = 1.0 + +[node name="HBox" type="HBoxContainer" parent="Back/Center"] +margin_left = 437.0 +margin_top = 189.0 +margin_right = 763.0 +margin_bottom = 611.0 + +[node name="VBox" type="VBoxContainer" parent="Back/Center/HBox"] +margin_right = 311.0 +margin_bottom = 422.0 + +[node name="AddressLabel" type="Label" parent="Back/Center/HBox/VBox"] +margin_right = 311.0 +margin_bottom = 50.0 +text = "address" + +[node name="Address" type="LineEdit" parent="Back/Center/HBox/VBox"] +margin_top = 65.0 +margin_right = 311.0 +margin_bottom = 171.0 +focus_mode = 1 +text = "127.0.0.1" +placeholder_text = "127.0.0.1" +caret_blink = true +caret_blink_speed = 0.35 + +[node name="HBox" type="HBoxContainer" parent="Back/Center/HBox/VBox"] +margin_top = 186.0 +margin_right = 311.0 +margin_bottom = 292.0 + +[node name="HostButton" type="Button" parent="Back/Center/HBox/VBox/HBox"] +margin_right = 154.0 +margin_bottom = 106.0 +focus_mode = 0 +enabled_focus_mode = 0 +text = "host" + +[node name="JoinButton" type="Button" parent="Back/Center/HBox/VBox/HBox"] +margin_left = 169.0 +margin_right = 311.0 +margin_bottom = 106.0 +focus_mode = 0 +enabled_focus_mode = 0 +text = "join" + +[node name="StatusOK" type="Label" parent="Back/Center/HBox/VBox"] +margin_top = 307.0 +margin_right = 311.0 +margin_bottom = 357.0 +custom_colors/font_color = Color( 1, 1, 1, 1 ) + +[node name="StatusFail" type="Label" parent="Back/Center/HBox/VBox"] +margin_top = 372.0 +margin_right = 311.0 +margin_bottom = 422.0 +custom_colors/font_color = Color( 0.698039, 0.415686, 0.415686, 1 ) + +[node name="VBox2" type="VBoxContainer" parent="Back/Center/HBox"] +margin_left = 326.0 +margin_right = 326.0 +margin_bottom = 422.0 + +[node name="Portforward" type="Label" parent="Back/Center/HBox/VBox2"] +visible = false +margin_right = 600.0 +margin_bottom = 161.0 +rect_min_size = Vector2( 600, 0 ) +custom_fonts/font = SubResource( 1 ) +text = "If you want non-LAN clients to connect, +make sure the port 8910 in UDP +is forwarded on your router." +autowrap = true + +[node name="FindPublicIP" type="LinkButton" parent="Back/Center/HBox/VBox2"] +visible = false +margin_right = 295.0 +margin_bottom = 50.0 +text = "find public ip" + +[connection signal="pressed" from="Back/Center/HBox/VBox/HBox/HostButton" to="." method="_on_host_pressed"] +[connection signal="pressed" from="Back/Center/HBox/VBox/HBox/JoinButton" to="." method="_on_join_pressed"] +[connection signal="pressed" from="Back/Center/HBox/VBox2/FindPublicIP" to="." method="_on_find_public_ip_pressed"] diff --git a/ui/MovesList.gd b/ui/MovesList.gd index 9af2cd9..1cf697d 100644 --- a/ui/MovesList.gd +++ b/ui/MovesList.gd @@ -1,7 +1,12 @@ -extends ItemList +extends ScrollContainer + var tween: Tween -onready var scrollbar = get_v_scroll() +var number = 1 + +onready var scroll_container = self +onready var scroll_bar = get_v_scrollbar() +onready var sans = $sans func _ready(): @@ -10,10 +15,36 @@ func _ready(): Utils.connect("newmove", self, "on_new_move") +func create_number_label(num): + var clr = ColorRect.new() + clr.color = Color(1, 1, 1, 0.13) + clr.rect_min_size = Vector2(70, 30) + var label = Label.new() + label.text = str(num) + ". " + label.align = Label.ALIGN_RIGHT + label.valign = Label.VALIGN_CENTER + label.rect_min_size = clr.rect_min_size + clr.add_child(label) + sans.add_child(clr) + + +func create_san_label(text, alignment = Label.ALIGN_RIGHT): + var label = Label.new() + label.text = text + label.valign = Label.VALIGN_CENTER + label.align = alignment + label.rect_min_size = Vector2(115, 0) + sans.add_child(label) + + func on_new_move(move): - add_item(move) + var alignment = Label.ALIGN_RIGHT + if Globals.turn: # white just moved + alignment = Label.ALIGN_LEFT + create_number_label(Globals.white_turns + 1) + number = 0 + create_san_label(move, alignment) tween.interpolate_property( # scrolldown - scrollbar, "value", scrollbar.value, scrollbar.max_value, 0.5, Tween.TRANS_BOUNCE, Tween.EASE_IN_OUT + scroll_bar, "value", scroll_bar.value, scroll_bar.max_value, 0.5, Tween.TRANS_BOUNCE, Tween.EASE_IN_OUT ) tween.start() - scrollbar.value = scrollbar.max_value diff --git a/ui/StartMenu.gd b/ui/StartMenu.gd index 2bbcabe..fa47bbc 100644 --- a/ui/StartMenu.gd +++ b/ui/StartMenu.gd @@ -10,6 +10,7 @@ onready var settings := $ColorRect/Settings onready var colorrect := $ColorRect onready var tween := $Tween onready var timer := $Timer +onready var lobby := $ColorRect/Lobby func _ready(): @@ -43,3 +44,7 @@ func _on_Timer_timeout(): tween.interpolate_property(colorrect, "color", colorrect.color, clr, timer_length, Tween.TRANS_ELASTIC) tween.start() timer.start(timer_length) + + +func _on_multiplayer_pressed(): + lobby.toggle(true) diff --git a/ui/StartMenu.tscn b/ui/StartMenu.tscn index 5f39e84..873b826 100644 --- a/ui/StartMenu.tscn +++ b/ui/StartMenu.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=4 format=2] +[gd_scene load_steps=5 format=2] [ext_resource path="res://ui/main.tres" type="Theme" id=1] [ext_resource path="res://ui/StartMenu.gd" type="Script" id=2] [ext_resource path="res://ui/Settings.tscn" type="PackedScene" id=3] +[ext_resource path="res://ui/Lobby.tscn" type="PackedScene" id=4] [node name="StartMenu" type="Control"] anchor_right = 1.0 @@ -70,11 +71,15 @@ text = "exit" [node name="Settings" parent="ColorRect" instance=ExtResource( 3 )] visible = false +[node name="Lobby" parent="ColorRect" instance=ExtResource( 4 )] +visible = false + [node name="Tween" type="Tween" parent="."] [node name="Timer" type="Timer" parent="."] one_shot = true +[connection signal="pressed" from="ColorRect/MainButtons/multiplayer" to="." method="_on_multiplayer_pressed"] [connection signal="pressed" from="ColorRect/MainButtons/settings" to="." method="_on_settings_pressed"] [connection signal="pressed" from="ColorRect/MainButtons/local" to="." method="_on_local_pressed"] [connection signal="pressed" from="ColorRect/MainButtons/quit" to="." method="_on_quit_pressed"] diff --git a/ui/flatblack.tres b/ui/flatblack.tres index 3186dbe..81baf6d 100644 --- a/ui/flatblack.tres +++ b/ui/flatblack.tres @@ -2,3 +2,4 @@ [resource] bg_color = Color( 0, 0, 0, 1 ) +corner_detail = 20 diff --git a/ui/main.tres b/ui/main.tres index e798c9d..fc4318d 100644 --- a/ui/main.tres +++ b/ui/main.tres @@ -14,6 +14,12 @@ [sub_resource type="StyleBoxFlat" id=3] bg_color = Color( 0.0784314, 0.0784314, 0.0784314, 1 ) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color( 1, 1, 1, 1 ) +corner_detail = 20 [sub_resource type="StyleBoxEmpty" id=5] @@ -41,6 +47,12 @@ ItemList/colors/font_color = Color( 1, 1, 1, 1 ) ItemList/colors/font_color_selected = Color( 0.905882, 0.905882, 0.905882, 1 ) ItemList/styles/bg = SubResource( 4 ) ItemList/styles/bg_focus = ExtResource( 7 ) +LineEdit/colors/cursor_color = Color( 1, 1, 1, 1 ) +LineEdit/colors/font_color = Color( 1, 1, 1, 1 ) +LineEdit/colors/font_color_uneditable = Color( 1, 1, 1, 0.67451 ) +LineEdit/styles/focus = ExtResource( 2 ) +LineEdit/styles/normal = ExtResource( 2 ) +LineEdit/styles/read_only = ExtResource( 2 ) OptionButton/colors/font_color = Color( 1, 1, 1, 1 ) OptionButton/colors/font_color_focus = Color( 1, 1, 1, 1 ) OptionButton/colors/font_color_hover = Color( 0, 0, 0, 1 ) |