online multiplayer chess game (note server currently down)
pointless multiplayer + better san display
bendn 2022-05-18
parent 473cff5 · commit 3a621b2
-rw-r--r--Grid.gd10
-rw-r--r--Utils.gd2
-rw-r--r--World.gd4
-rw-r--r--World.tscn4
-rw-r--r--ui/GameUI.tscn90
-rw-r--r--ui/Lobby.gd135
-rw-r--r--ui/Lobby.tscn104
-rw-r--r--ui/MovesList.gd41
-rw-r--r--ui/StartMenu.gd5
-rw-r--r--ui/StartMenu.tscn7
-rw-r--r--ui/flatblack.tres1
-rw-r--r--ui/main.tres12
12 files changed, 394 insertions, 21 deletions
diff --git a/Grid.gd b/Grid.gd
index 9b6e7a8..0647337 100644
--- a/Grid.gd
+++ b/Grid.gd
@@ -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()
diff --git a/Utils.gd b/Utils.gd
index 0660e67..114fc67 100644
--- a/Utils.gd
+++ b/Utils.gd
@@ -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
diff --git a/World.tscn b/World.tscn
index 9b820e2..ef7994c 100644
--- a/World.tscn
+++ b/World.tscn
@@ -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 )