feat: 重构多人游戏界面和代码,使用文件存储游戏配置,重构底层代码

This commit is contained in:
ZZY 2024-11-06 22:13:03 +08:00
parent d323a0bee7
commit d6cbb5e11d
30 changed files with 715 additions and 262 deletions

File diff suppressed because one or more lines are too long

View File

@ -41,6 +41,8 @@ public partial class Main : Node2D
// board.Visible = false; // board.Visible = false;
// board.Can // board.Can
global = GetNode<Global>("/root/Global"); global = GetNode<Global>("/root/Global");
global.GlobalTheme = GetChild<Control>(GetChildCount() - 1).Theme;
global.ConfigFlush();
} }
// Called every frame. 'delta' is the elapsed time since the previous frame. // Called every frame. 'delta' is the elapsed time since the previous frame.
@ -54,7 +56,7 @@ public partial class Main : Node2D
private void GoToMultiPlayer() { private void GoToMultiPlayer() {
// global.GotoScene("res://Scenes/MultiPlayer.tscn"); // global.GotoScene("res://Scenes/MultiPlayer.tscn");
global.GotoScene("res://Scenes/Menu.tscn"); global.GotoScene("res://Scenes/GameLobby.tscn");
} }
private void GoToSetting() { private void GoToSetting() {

View File

@ -8,50 +8,68 @@
script = ExtResource("1_3x8ac") script = ExtResource("1_3x8ac")
[node name="Chessboard" parent="." instance=ExtResource("1_yheur")] [node name="Chessboard" parent="." instance=ExtResource("1_yheur")]
position = Vector2(360, 660) position = Vector2(360, 600)
scale = Vector2(2.5, 2.5) scale = Vector2(2.5, 2.5)
[node name="Control" type="Control" parent="."] [node name="Control" type="Control" parent="."]
custom_minimum_size = Vector2(720, 1280)
layout_mode = 3 layout_mode = 3
anchors_preset = 0 anchors_preset = 0
offset_right = 40.0 offset_right = 720.0
offset_bottom = 40.0 offset_bottom = 1280.0
theme = ExtResource("3_rcfhx") theme = ExtResource("3_rcfhx")
[node name="Over" type="Button" parent="Control"] [node name="MarginContainer" type="MarginContainer" parent="Control"]
layout_mode = 0 layout_mode = 1
offset_left = 270.0 anchors_preset = 10
offset_top = 1105.0 anchor_right = 1.0
offset_right = 449.0 offset_bottom = 81.0
offset_bottom = 1209.0 grow_horizontal = 2
[node name="HBoxContainer" type="HBoxContainer" parent="Control/MarginContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="Control/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Home" type="Button" parent="Control/MarginContainer/HBoxContainer/MarginContainer"]
layout_mode = 2
text = "返回主页"
[node name="MarginContainer2" type="MarginContainer" parent="Control/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Undo" type="Button" parent="Control/MarginContainer/HBoxContainer/MarginContainer2"]
layout_mode = 2
size_flags_vertical = 4
text = "撤回"
[node name="MarginContainer3" type="MarginContainer" parent="Control/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="ReInit" type="Button" parent="Control/MarginContainer/HBoxContainer/MarginContainer3"]
layout_mode = 2
text = "重开"
[node name="MarginContainer2" type="MarginContainer" parent="Control"]
layout_mode = 1
anchors_preset = 12
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = -114.0
grow_horizontal = 2
grow_vertical = 0
[node name="Over" type="Button" parent="Control/MarginContainer2"]
layout_mode = 2
text = "结束回合 text = "结束回合
(提示对方结束)" (提示对方结束)"
[node name="Home" type="Button" parent="Control"] [connection signal="pressed" from="Control/MarginContainer/HBoxContainer/MarginContainer/Home" to="." method="GoHome"]
layout_mode = 0 [connection signal="pressed" from="Control/MarginContainer/HBoxContainer/MarginContainer2/Undo" to="." method="Undo"]
offset_left = 55.0 [connection signal="pressed" from="Control/MarginContainer/HBoxContainer/MarginContainer3/ReInit" to="." method="ReInit"]
offset_top = 56.0 [connection signal="pressed" from="Control/MarginContainer2/Over" to="." method="BtnOver"]
offset_right = 157.0
offset_bottom = 164.0
text = "返回主页"
[node name="Undo" type="Button" parent="Control"]
layout_mode = 0
offset_left = 319.0
offset_top = 58.0
offset_right = 419.0
offset_bottom = 158.0
text = "撤回"
[node name="ReInit" type="Button" parent="Control"]
layout_mode = 0
offset_left = 578.0
offset_top = 55.0
offset_right = 678.0
offset_bottom = 155.0
text = "重开"
[connection signal="pressed" from="Control/Over" to="." method="BtnOver"]
[connection signal="pressed" from="Control/Home" to="." method="GoHome"]
[connection signal="pressed" from="Control/Undo" to="." method="Undo"]
[connection signal="pressed" from="Control/ReInit" to="." method="ReInit"]

View File

@ -0,0 +1,17 @@
[gd_scene format=3 uid="uid://pc83bstfltn"]
[node name="ServerStatus" type="HBoxContainer"]
anchors_preset = -1
anchor_right = 0.176389
anchor_bottom = 0.0179687
offset_right = -126.0
metadata/_edit_use_anchors_ = true
[node name="Label" type="Label" parent="."]
layout_mode = 2
size_flags_horizontal = 0
text = "Server Status"
[node name="ColorRect" type="ColorRect" parent="."]
custom_minimum_size = Vector2(15, 15)
layout_mode = 2

78
Scenes/GameLobby.tscn Normal file
View File

@ -0,0 +1,78 @@
[gd_scene load_steps=3 format=3 uid="uid://00jxjgnmfbn7"]
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/defaultTheme.tres" id="1_ge0tq"]
[ext_resource type="Script" path="res://Scripts/Controllers/GameLobby.cs" id="2_blx46"]
[node name="GameLobby" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_ge0tq")
script = ExtResource("2_blx46")
[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
[node name="Button" type="Button" parent="MarginContainer/VBoxContainer/MarginContainer"]
layout_mode = 2
text = "Back
"
[node name="MarginContainer2" type="HFlowContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/MarginContainer2"]
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/MarginContainer2/MarginContainer"]
layout_mode = 2
text = "Connect States"
[node name="MarginContainer2" type="MarginContainer" parent="MarginContainer/VBoxContainer/MarginContainer2"]
layout_mode = 2
size_flags_horizontal = 3
[node name="ColorRect" type="ColorRect" parent="MarginContainer/VBoxContainer/MarginContainer2/MarginContainer2"]
layout_mode = 2
size_flags_horizontal = 3
[node name="MarginContainer3" type="MarginContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="ItemList" type="ItemList" parent="MarginContainer/VBoxContainer/MarginContainer3"]
layout_mode = 2
[node name="Dialogs" type="Control" parent="."]
layout_mode = 3
anchors_preset = 0
[node name="AcceptDialog" type="AcceptDialog" parent="Dialogs"]
auto_translate_mode = 1
initial_position = 2
size = Vector2i(100, 118)
[node name="PopupMenu" type="PopupMenu" parent="Dialogs"]
auto_translate_mode = 1
[node name="ConfirmationDialog" type="ConfirmationDialog" parent="Dialogs"]
auto_translate_mode = 1
initial_position = 2
size = Vector2i(200, 118)
[connection signal="pressed" from="MarginContainer/VBoxContainer/MarginContainer/Button" to="." method="OnBack"]
[connection signal="item_activated" from="MarginContainer/VBoxContainer/MarginContainer3/ItemList" to="." method="OnItemSelected"]

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=3 format=3 uid="uid://cl8nkm6j8s8jh"] [gd_scene load_steps=3 format=3 uid="uid://bc7w0h2x4bbdh"]
[ext_resource type="Script" path="res://Scripts/Controllers/Menu.cs" id="1_chiyi"] [ext_resource type="Script" path="res://Scripts/Controllers/Menu.cs" id="1_chiyi"]
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/defaultTheme.tres" id="1_mkeko"] [ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/defaultTheme.tres" id="1_mkeko"]
@ -13,6 +13,7 @@ grow_vertical = 2
theme = ExtResource("1_mkeko") theme = ExtResource("1_mkeko")
script = ExtResource("1_chiyi") script = ExtResource("1_chiyi")
metadata/_edit_horizontal_guides_ = [141.0] metadata/_edit_horizontal_guides_ = [141.0]
metadata/_edit_use_anchors_ = true
[node name="Home" type="Button" parent="."] [node name="Home" type="Button" parent="."]
layout_mode = 0 layout_mode = 0
@ -113,6 +114,7 @@ initial_position = 2
size = Vector2i(200, 118) size = Vector2i(200, 118)
[node name="URL" type="LineEdit" parent="."] [node name="URL" type="LineEdit" parent="."]
visible = false
layout_mode = 0 layout_mode = 0
offset_left = 37.0 offset_left = 37.0
offset_top = 290.0 offset_top = 290.0

157
Scenes/Setting.tscn Normal file
View File

@ -0,0 +1,157 @@
[gd_scene load_steps=4 format=3 uid="uid://c6gxufppw1fu3"]
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/defaultTheme.tres" id="1_6yfoi"]
[ext_resource type="Script" path="res://Scripts/Controllers/Setting.cs" id="1_xbvb3"]
[ext_resource type="PackedScene" uid="uid://pc83bstfltn" path="res://Scenes/Entities/ServerStatus.tscn" id="3_e50hu"]
[node name="Setting" type="MarginContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_6yfoi")
script = ExtResource("1_xbvb3")
[node name="BoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="BoxContainer"]
layout_mode = 2
[node name="Back" type="Button" parent="BoxContainer/MarginContainer"]
layout_mode = 2
text = "Back"
[node name="MarginContainer7" type="MarginContainer" parent="BoxContainer"]
layout_mode = 2
[node name="Button" type="Button" parent="BoxContainer/MarginContainer7"]
layout_mode = 2
text = "Save"
[node name="MarginContainer2" type="MarginContainer" parent="BoxContainer"]
layout_mode = 2
[node name="Server" type="HFlowContainer" parent="BoxContainer/MarginContainer2"]
layout_mode = 2
[node name="Label" type="Label" parent="BoxContainer/MarginContainer2/Server"]
layout_mode = 2
text = "Server IP"
[node name="LineEdit" type="LineEdit" parent="BoxContainer/MarginContainer2/Server"]
layout_mode = 2
size_flags_horizontal = 3
[node name="MarginContainer3" type="MarginContainer" parent="BoxContainer"]
layout_mode = 2
[node name="Name" type="HFlowContainer" parent="BoxContainer/MarginContainer3"]
layout_mode = 2
[node name="Label" type="Label" parent="BoxContainer/MarginContainer3/Name"]
layout_mode = 2
text = "Name"
[node name="LineEdit" type="LineEdit" parent="BoxContainer/MarginContainer3/Name"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Button" type="Button" parent="BoxContainer/MarginContainer3/Name"]
visible = false
layout_mode = 2
text = "OK"
[node name="MarginContainer4" type="MarginContainer" parent="BoxContainer"]
layout_mode = 2
[node name="HFlowContainer" type="HFlowContainer" parent="BoxContainer/MarginContainer4"]
layout_mode = 2
[node name="ServerStatus" parent="BoxContainer/MarginContainer4/HFlowContainer" instance=ExtResource("3_e50hu")]
layout_mode = 2
size_flags_horizontal = 3
[node name="CheckButton" type="CheckButton" parent="BoxContainer/MarginContainer4/HFlowContainer"]
visible = false
layout_mode = 2
text = "Server Start"
[node name="MarginContainer5" type="MarginContainer" parent="BoxContainer"]
layout_mode = 2
[node name="HBoxContainer" type="HFlowContainer" parent="BoxContainer/MarginContainer5"]
layout_mode = 2
[node name="Label" type="Label" parent="BoxContainer/MarginContainer5/HBoxContainer"]
layout_mode = 2
text = "Font Size"
[node name="FontSize" type="LineEdit" parent="BoxContainer/MarginContainer5/HBoxContainer"]
layout_mode = 2
editable = false
[node name="MarginContainer6" type="MarginContainer" parent="BoxContainer"]
layout_mode = 2
[node name="FontSizeBar" type="HSlider" parent="BoxContainer/MarginContainer6"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 4
min_value = 10.0
max_value = 50.0
value = 10.0
[node name="HBoxContainer" type="HFlowContainer" parent="BoxContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="BoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Button" type="Button" parent="BoxContainer/HBoxContainer/MarginContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Clear Config"
[node name="MarginContainer2" type="MarginContainer" parent="BoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Button2" type="Button" parent="BoxContainer/HBoxContainer/MarginContainer2"]
layout_mode = 2
text = "Clear User Data"
[node name="HFlowContainer" type="HFlowContainer" parent="BoxContainer"]
layout_mode = 2
[node name="Button" type="Button" parent="BoxContainer/HFlowContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "GetCacheDir"
[node name="Button2" type="Button" parent="BoxContainer/HFlowContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "GetConfigDir"
[node name="Button3" type="Button" parent="BoxContainer/HFlowContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "GetDataDir"
[node name="Button4" type="Button" parent="BoxContainer/HFlowContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "GetUserDataDir"
[connection signal="pressed" from="BoxContainer/MarginContainer/Back" to="." method="OnBack"]
[connection signal="text_changed" from="BoxContainer/MarginContainer2/Server/LineEdit" to="." method="OnServerUrlChanged"]
[connection signal="text_changed" from="BoxContainer/MarginContainer3/Name/LineEdit" to="." method="OnNameChanged"]
[connection signal="value_changed" from="BoxContainer/MarginContainer6/FontSizeBar" to="." method="OnFontSizeChanged"]
[connection signal="pressed" from="BoxContainer/HBoxContainer/MarginContainer2/Button2" to="." method="OnClearUserData"]
[connection signal="pressed" from="BoxContainer/HFlowContainer/Button" to="." method="OnGetCacheDir"]
[connection signal="pressed" from="BoxContainer/HFlowContainer/Button2" to="." method="OnGetConfigDir"]
[connection signal="pressed" from="BoxContainer/HFlowContainer/Button3" to="." method="OnGetDataDir"]
[connection signal="pressed" from="BoxContainer/HFlowContainer/Button4" to="." method="OnGetUserDataDir"]

View File

@ -1,3 +0,0 @@
[gd_scene format=3 uid="uid://dp044iptyvvh"]
[node name="Web" type="Node"]

View File

@ -7,8 +7,9 @@ public partial class ChessGame : Node2D
Global global; Global global;
ConfirmationDialog dialog; ConfirmationDialog dialog;
private bool isSession = false; private bool isSession = false;
private Vector2 from;
private Vector2 to; private Player playerSelf;
private Player playerOpponent;
// Called when the node enters the scene tree for the first time. // Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
@ -16,45 +17,47 @@ public partial class ChessGame : Node2D
// Init.Call(); // Init.Call();
global = GetNode<Global>("/root/Global"); global = GetNode<Global>("/root/Global");
board = GetNode<ChessBoard>("Chessboard"); board = GetNode<ChessBoard>("Chessboard");
playerSelf = new Player(board.board, Player.PlayerType.Human);
playerOpponent = new Player(board.board, Player.PlayerType.Human);
board.OnMouseClicked += (sender, clickPosition) => {
Vector2 clickBoardPos = (PosTrans.transArrToPix.AffineInverse() *
clickPosition).Round();
playerSelf.HandleBoardPosClick(clickBoardPos);
};
dialog = new ConfirmationDialog { dialog = new ConfirmationDialog {
DialogAutowrap = true, DialogAutowrap = true,
MinSize = new Vector2I(400, 200), MinSize = new Vector2I(400, 200),
Position = new Vector2I(200, 400), Position = new Vector2I(200, 400),
}; };
AddChild(dialog); AddChild(dialog);
// GetNode<Button>("Undo").Connect("pressed", Callable.From(board.Undo));
// GetNode<Button>("ReInit").Connect("pressed", Callable.From(board.ReInit));
// GetNode<Button>("Home").Connect("pressed", Callable.From(this.GoHome));
if (!global.RPClient.GetIsConnected()) { if (!global.RPClient.GetIsConnected()) {
return; return;
} }
isSession = true; isSession = true;
GD.Print("ws is connected"); GD.Print("ws is connected");
global.RPClient.OnPRCSessionExit += (cmd, code) => { global.RPClient.OnPRCSessionExit += (cmd, code) => {
GoHome(); GoHome();
}; };
// board.Set("Hello", Callable.From(() => {GD.PrintErr("hello");}));
board.board.OnMove += (sender, args) => { board.OnMouseClicked += (sender, clickPosition) => {
Vector2 newPos = args.To; Vector2 clickBoardPos = (PosTrans.transArrToPix.AffineInverse() *
Vector2 fromPos = args.From; clickPosition).Round();
if (from.X == fromPos.X && from.Y == fromPos.Y && to.X == newPos.X && to.Y == newPos.Y) {
return; var res = global.RPClient.SendSessionToAll(global.sessionId, new Dictionary {
} {"type", "mouseClicked"},
from = fromPos; {"X", clickBoardPos.X},
to = newPos; {"Y", clickBoardPos.Y},
var res = global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
{"type", "move"},
{"from", fromPos},
{"to", newPos},
{"fromX", fromPos.X},
{"fromY", fromPos.Y},
{"toX", newPos.X},
{"toY", newPos.Y},
}); });
GD.Print($"chessMoveFunc Callback {fromPos} -> {newPos} {res}"); // GD.Print($"chessMoveFunc Callback {fromPos} -> {newPos} {res}");
}; };
global.RPClient.OnPRCSessionRecv += (msg) => { global.RPClient.OnPRCSessionRecv += (msg) => {
SessionMsgHandle(msg["msg"].AsGodotDictionary()); SessionMsgHandle(msg["msg"].AsGodotDictionary());
}; };
@ -75,18 +78,10 @@ public partial class ChessGame : Node2D
dialog.DialogText = "Turn On You\n"; dialog.DialogText = "Turn On You\n";
dialog.Visible = true; dialog.Visible = true;
break; break;
case "move": case "mouseClicked":
Vector2 _to = new(GD.StrToVar(msg["toX"].ToString()).AsInt32(), Vector2 mouseClicked = new(GD.StrToVar(msg["X"].ToString()).AsInt32(),
GD.StrToVar(msg["toY"].ToString()).AsInt32()); GD.StrToVar(msg["Y"].ToString()).AsInt32());
playerOpponent.HandleBoardPosClick(mouseClicked);
Vector2 _from = new(GD.StrToVar(msg["fromX"].ToString()).AsInt32(),
GD.StrToVar(msg["fromY"].ToString()).AsInt32());
if (_to.X == to.X && _to.Y == to.Y && _from.X == from.X && _from.Y == from.Y) {
return;
}
to = _to;
from = _from;
board.playerSelf.MoveAndRecord(to, from);
break; break;
case "undo": case "undo":
_Undo(); _Undo();
@ -98,16 +93,16 @@ public partial class ChessGame : Node2D
} }
private void _Undo() { private void _Undo() {
board.playerSelf.Undo(); playerSelf.Undo();
} }
private void _ReInit() { private void _ReInit() {
board.playerSelf.ReInit(); playerSelf.ReInit();
board.InitChessBoard(); board.InitChessBoard();
} }
private void BtnOver() { private void BtnOver() {
GD.PrintErr($"BtnOver {isSession}"); GD.Print($"BtnOver {isSession}");
if (isSession == false) { if (isSession == false) {
return; return;
} }
@ -125,22 +120,26 @@ public partial class ChessGame : Node2D
} }
public void Undo() { public void Undo() {
GD.PrintErr($"Undo {isSession}"); GD.Print($"Undo {isSession}");
if (isSession == false) {
_Undo(); if (isSession) {
}
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{ global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
{"type", "undo"}, {"type", "undo"},
}); });
} else {
_Undo();
}
} }
public void ReInit() { public void ReInit() {
GD.PrintErr($"ReInit {isSession}"); GD.PrintErr($"ReInit {isSession}");
if (isSession == false) {
_ReInit(); if (isSession) {
}
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{ global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
{"type", "reInit"}, {"type", "reInit"},
}); });
} else {
_ReInit();
}
} }
} }

View File

@ -1,48 +1,50 @@
using Godot; using Godot;
using Godot.Collections; using Godot.Collections;
public partial class Menu : Control public partial class GameLobby : Control {
{
Global global = null; Global global = null;
ItemList lists = null;
ConfirmationDialog dialog = null;
LineEdit nameLineEdit = null;
LineEdit urlLineEdit = null;
ColorRect colorRect = null;
Timer timer = null; Timer timer = null;
// Called when the node enters the scene tree for the first time. ItemList lists = null;
public override void _Ready() ConfirmationDialog dialog = null;
{
global = GetNode<Global>("/root/Global");
nameLineEdit = GetNode<LineEdit>("Name/LineEdit");
urlLineEdit = GetNode<LineEdit>("URL");
urlLineEdit.Text = global.URL;
urlLineEdit.Set("text_submitted", Callable.From(()=>{
global.URL = urlLineEdit.Text;
}));
lists = GetNode<ItemList>("Server/ItemList"); string URL;
string userName;
// Called when the node enters the scene tree for the first time.
public override void _Ready() {
global = GetNode<Global>("/root/Global");
lists = GetNode<ItemList>("MarginContainer/VBoxContainer/MarginContainer3/ItemList");
dialog = GetNode<ConfirmationDialog>("Dialogs/ConfirmationDialog"); dialog = GetNode<ConfirmationDialog>("Dialogs/ConfirmationDialog");
colorRect = GetNode<ColorRect>("Server/ColorRect"); URL = global.GlobalConfigDict["server_url"].AsString();
dialog.DialogAutowrap = true; userName = global.GlobalConfigDict["user_name"].AsString();
dialog.MinSize = new Vector2I(400, 200); dialog.MinSize = new Vector2I(400, 200);
dialog.DialogAutowrap = true;
dialog.Canceled += () => { dialog.Canceled += () => {
if (dialog.Title == "Session Created") if (dialog.Title == "Session Created")
global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), false); global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), false);
}; };
dialog.Confirmed += () => { dialog.Confirmed += () => {
// GD.PrintErr("confirm", dialog.GetLabel().Text);
// goToSignle();
if (dialog.Title == "Session Created") if (dialog.Title == "Session Created")
global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), true); global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), true);
}; };
global.RPClient.RegSessionAckCreateCallback(( global.RPClient.OnOpen += (string eventName, object[] args) => {
sessionId, global.RPClient.UserInit(userName, "godot chessboard", () => {
res, global.RPClient.UserRename(userName);
reqUserId, return global.RPClient.RegionAdd("server");
reqUserName) => { });
};
// global.RPClient.OnOpen += (eventName, args) => {
// global.RPClient.UserInit(userName, "none", () => {
// GD.PrintErr($"User Init Success");
// return true;
// });
// // global.RPClient.UserRename(userName);
// };
global.RPClient.RegSessionAckCreateCallback((sessionId, res, reqUserId, reqUserName) => {
if (reqUserId != null) { if (reqUserId != null) {
dialog.Title = "Session Created"; dialog.Title = "Session Created";
dialog.SetMeta("reqUserName", reqUserName); dialog.SetMeta("reqUserName", reqUserName);
@ -67,18 +69,28 @@ public partial class Menu : Control
timer = new Timer(); timer = new Timer();
AddChild(timer); AddChild(timer);
ColorRect colorRect = GetNode<ColorRect>("MarginContainer/VBoxContainer/MarginContainer2/MarginContainer2/ColorRect");
timer.Connect("timeout", Callable.From(() => { timer.Connect("timeout", Callable.From(() => {
if (global.RPClient.GetIsConnected()) { if (global.RPClient.GetIsConnected()) {
colorRect.Color = Colors.Green; colorRect.Color = Colors.Green;
} else { } else {
colorRect.Color = Colors.Red; colorRect.Color = Colors.Red;
} }
FlushData();
})); }));
timer.Start(1); timer.Start(1);
Connect();
} }
// Called every frame. 'delta' is the elapsed time since the previous frame. public void Connect() {
public override void _Process(double delta) { GD.Print("Connect");
if (global.RPClient.GetIsConnected()) {
return;
}
// global.RPClient.ExitServer();
global.RPClient.ConnectToUrlEx(URL);
global.SetProcess(true);
} }
private void OnItemSelected(int index) { private void OnItemSelected(int index) {
@ -88,11 +100,10 @@ public partial class Menu : Control
global.RPClient.SessionCreate(strings); global.RPClient.SessionCreate(strings);
} }
private void FlushData() private void FlushData() {
{
global.RPClient.RegionInspect("server", (data) => { global.RPClient.RegionInspect("server", (data) => {
GD.Print(data); // GD.Print(data);
lists.Clear(); lists?.Clear();
foreach (Dictionary<string, string> user in data) { foreach (Dictionary<string, string> user in data) {
string userId = user["id"].ToString(); string userId = user["id"].ToString();
string userName = user["name"].ToString(); string userName = user["name"].ToString();
@ -110,27 +121,9 @@ public partial class Menu : Control
}); });
} }
public void Connect()
{
GD.Print("Connect");
global.RPClient.ExitServer();
global.RPClient.ConnectToUrlEx(urlLineEdit.Text);
global.SetProcess(true);
}
public void EnterName() { private void OnBack() {
var newLine = nameLineEdit.Text;
global.RPClient.UserRename(newLine);
nameLineEdit.Text = newLine;
}
private void goToHome() {
global.RPClient.ExitServer(); global.RPClient.ExitServer();
global.GotoScene("res://Main.tscn"); global.GotoScene("res://Main.tscn");
} }
// private void OnItemListItemClicked(int index, Vector2 atPosition, int mouse_button_index)
// {
// GD.Print($"Item {index} clicked at {atPosition} with mouse button index {mouse_button_index}");
// }
} }

View File

@ -0,0 +1,91 @@
using Godot;
using System;
public partial class Setting : Control
{
Global global;
int font_size;
LineEdit fontOut;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
global = GetNode<Global>("/root/Global");
fontOut = GetNode<LineEdit>("BoxContainer/MarginContainer5/HBoxContainer/FontSize");
font_size = (int)global.GlobalConfigDict["font_size"];
GetNode<HSlider>("BoxContainer/MarginContainer6/FontSizeBar")
.Value = font_size;
fontOut.Text = font_size.ToString();
FillingData();
}
private void FillingData()
{
GetNode<LineEdit>("BoxContainer/MarginContainer2/Server/LineEdit")
.Text = global.GlobalConfigDict["server_url"].ToString();
GetNode<LineEdit>("BoxContainer/MarginContainer3/Name/LineEdit")
.Text = global.GlobalConfigDict["user_name"].ToString();
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
private void OnBack() {
global.SaveConfig();
global.GotoScene("res://Main.tscn", null);
}
void OnNameChanged(string Value)
{
global.GlobalConfigDict["user_name"] = Value;
// global.ConfigFlush();
}
private void OnServerUrlChanged(string Value)
{
global.GlobalConfigDict["server_url"] = Value;
// global.ConfigFlush();
}
private void OnFontSizeChanged(float Value)
{
font_size = (int)Value;
global.GlobalConfigDict["font_size"] = font_size;
global.ConfigFlush();
fontOut.Text = font_size.ToString();
}
private static void OnClearData() {
// ProjectSettings.GlobalizePath("user://");
// DirAccess.CopyAbsolute("res://userdata", "user://");
}
private static void OnClearUserData() {
string path = ProjectSettings.GlobalizePath("user://");
// DirAccess dirAccess = DirAccess.Open(path);
// dirAccess.Remove(path);
if (DirAccess.RemoveAbsolute(path) != Error.Ok) {
FormattableString msg = $"Failed to delete user data at {path}";
OS.Alert(msg.ToString(), "Error");
}
}
private static void OnGetCacheDir() {
OS.Alert(OS.GetCacheDir(), "Cache Dir");
}
private static void OnGetConfigDir() {
OS.Alert(OS.GetConfigDir(), "Config Dir");
}
private static void OnGetDataDir() {
OS.Alert(OS.GetDataDir(), "Data Dir");
}
private static void OnGetUserDataDir() {
OS.Alert(OS.GetUserDataDir(), "User Data Dir");
}
}

View File

@ -1,4 +1,5 @@
// Chessboard.cs // Chessboard.cs
using System;
using Godot; using Godot;
public partial class ChessBoard : Node2D { public partial class ChessBoard : Node2D {
@ -7,6 +8,7 @@ public partial class ChessBoard : Node2D {
public delegate bool ChessMoveFunc(Vector2 toPos, Vector2 fromPos); public delegate bool ChessMoveFunc(Vector2 toPos, Vector2 fromPos);
// public Callable chessMoveFunc { get; set; } // public Callable chessMoveFunc { get; set; }
public event EventHandler<Vector2> OnMouseClicked;
public override void _Ready() { public override void _Ready() {
board = new VirtualBoard(9, 10); board = new VirtualBoard(9, 10);
@ -36,15 +38,9 @@ public partial class ChessBoard : Node2D {
mouseEvent.Pressed && mouseEvent.Pressed &&
mouseEvent.ButtonIndex == MouseButton.Left) { mouseEvent.ButtonIndex == MouseButton.Left) {
// HandleMouseClick(GetGlobalTransformWithCanvas().AffineInverse() * mouseButton.Position); // HandleMouseClick(GetGlobalTransformWithCanvas().AffineInverse() * mouseButton.Position);
HandleMouseClick(GetLocalMousePosition());
}
}
private void HandleMouseClick(Vector2 clickPosition) { OnMouseClicked?.Invoke(this, GetLocalMousePosition());
Vector2 clickBoardPos = (PosTrans.transArrToPix.AffineInverse() * }
clickPosition).Round();
playerSelf.HandleBoardPosClick(clickBoardPos);
} }
public void InsertNode(ChessPiece node, Vector2 arrayPos) { public void InsertNode(ChessPiece node, Vector2 arrayPos) {
@ -74,65 +70,11 @@ public partial class ChessBoard : Node2D {
private void InitializePieces(string color, int baseY, (string label, int x, int y)[] positions) { private void InitializePieces(string color, int baseY, (string label, int x, int y)[] positions) {
foreach (var (label, x, y) in positions) { foreach (var (label, x, y) in positions) {
InsertNode(new ChessPiece { ChessPiece piece = new ChessPiece {
PieceLabel = label, PieceLabel = label,
LabelColor = new Color(color) LabelColor = new Color(color)
}, new Vector2(x, baseY + y)); };
InsertNode(piece, new Vector2(x, baseY + y));
} }
} }
// using Godot;
// public enum ChessType
// {
// Carriage,
// Horse,
// Elephant,
// Advisor,
// General,
// Cannon,
// Pawn
// }
// public class VirtualBoard
// {
// // ...其他原有成员变量...
// public VirtualBoard(Node root = null)
// {
// BoardRoot = root ?? GetTree().CurrentScene; // 如果未提供root默认为当前场景
// }
// public void InitChessBoard()
// {
// // 定义黑色和红色棋子的初始位置和类型
// var positions = new (Vector2 position, ChessType type)[]
// {
// // 黑方棋子初始化...
// // 示例省略具体位置和类型,你需要根据实际情况填写
// // (new Vector2(x, y), ChessType.Pawn),
// // 红方棋子初始化...
// // 同上
// };
// // 初始化棋子
// foreach (var (position, type) in positions)
// {
// var color = position.Y == 0 ? new Color("black") : new Color("red"); // 根据行判断颜色
// var piece = CreateChessPiece(type, color);
// InsertChess(piece, position);
// }
// }
// private ChessPiece CreateChessPiece(ChessType type, Color labelColor)
// {
// // 根据ChessType创建对应的棋子实例并设置Label和颜色
// // 这里需要你实现具体的逻辑例如switch case或映射表来决定创建哪种棋子
// // 返回创建的棋子实例
// }
// // ...其他原有方法...
// }
} }

View File

@ -11,7 +11,7 @@ public partial class ChessPiece : Sprite2D {
private Vector2 textureSize; private Vector2 textureSize;
private Label labelOfChessName; private Label labelOfChessName;
private VirtualPiece piece; private readonly VirtualPiece piece;
public VirtualPiece GetVirtualPiece() { public VirtualPiece GetVirtualPiece() {
return piece; return piece;

View File

@ -1,3 +1,4 @@
using System.Collections.Generic;
using Godot; using Godot;
using RPPackage; using RPPackage;
@ -5,28 +6,60 @@ public partial class Global : Node
{ {
public RPClientEDWS RPClient = new(); public RPClientEDWS RPClient = new();
public string sessionId; public string sessionId;
public string URL = "wss://game.zzyxyz.com/";
public Node CurrentScene { get; set; } public Node CurrentScene { get; set; }
public Theme GlobalTheme = null;
readonly GodotConfigManager GlobalConfig = new("user://config.cfg");
public Dictionary<string, Variant> GlobalConfigDict = new() {
{"font_size", 20},
{"server_url", "wss://game.zzyxyz.com/"},
{"user_name", "undefined"}
};
// Called when the node enters the scene tree for the first time. // Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
{ {
if (OS.GetName() == "Android") {
bool ret = OS.RequestPermissions();
GD.Print($"RequestPermissions ret is {ret}");
}
// OS.RequestPermissions();
RPClient.OnRPCError += (string errCode, string type, string cmd, string errMsg) => { RPClient.OnRPCError += (string errCode, string type, string cmd, string errMsg) => {
GD.PrintErr($"errCode {errCode}, type/cmd {type}/{cmd}, errMsg {errMsg}"); GD.PrintErr($"errCode {errCode}, type/cmd {type}/{cmd}, errMsg {errMsg}");
}; };
RPClient.OnClose += (string eventName, object[] args) => { RPClient.OnClose += (string eventName, object[] args) => {
SetProcess(false); SetProcess(false);
}; };
RPClient.OnOpen += (string eventName, object[] args) => {
RPClient.UserInit("undefined", "godot chessboard", () => {
return RPClient.RegionAdd("server");
});
};
Viewport root = GetTree().Root; Viewport root = GetTree().Root;
CurrentScene = root.GetChild(root.GetChildCount() - 1); CurrentScene = root.GetChild(root.GetChildCount() - 1);
GlobalConfig.LoadConfig("Global", GlobalConfigDict);
SetProcess(false); SetProcess(false);
} }
public void ConfigFlush()
{
int font_size = (int)GlobalConfigDict["font_size"];
GlobalTheme.DefaultFontSize = font_size;
// GlobalTheme?.SetFontSize("font_size", "Label", font_size);
// GlobalTheme?.SetFontSize("font_size", "Button", font_size);
// GlobalTheme?.SetFontSize("font_size", "TextEdit", font_size);
// GlobalTheme?.SetFontSize("font_size", "LineEdit", font_size);
// CurrentScene.GetWindow().AddThemeFontSizeOverride("Control", (int)GlobalConfigDict["font_size"]);
}
private void OnGotoScene()
{
ConfigFlush();
}
public void SaveConfig()
{
GlobalConfig.SaveConfig("Global", GlobalConfigDict);
}
// Called every frame. 'delta' is the elapsed time since the previous frame. // Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta) public override void _Process(double delta)
{ {
@ -36,6 +69,7 @@ public partial class Global : Node
public override void _Notification(int what) public override void _Notification(int what)
{ {
if (what == NotificationWMCloseRequest) { if (what == NotificationWMCloseRequest) {
SaveConfig();
RPClient.Close(); RPClient.Close();
GetTree().Quit(); // default behavior GetTree().Quit(); // default behavior
} }
@ -81,5 +115,7 @@ public partial class Global : Node
// Optionally, to make it compatible with the SceneTree.change_scene_to_file() API. // Optionally, to make it compatible with the SceneTree.change_scene_to_file() API.
GetTree().CurrentScene = CurrentScene; GetTree().CurrentScene = CurrentScene;
OnGotoScene();
} }
} }

View File

@ -1,5 +1,3 @@
using System;
using System.Threading;
using Godot; using Godot;
using Godot.Collections; using Godot.Collections;
@ -125,7 +123,7 @@ public partial class RPClientEDWS : RPClientBaseEDWS {
}; };
} }
public void ClearRPCClientFunc() { public static void ClearRPCClientFunc() {
} }
@ -133,7 +131,7 @@ public partial class RPClientEDWS : RPClientBaseEDWS {
return GetIsConnected() && userId != null; return GetIsConnected() && userId != null;
} }
public void ConnectServer(string url) { public static void ConnectServer(string url) {
} }

View File

View File

@ -1,10 +1,13 @@
using Godot; using Vector2 = Godot.Vector2;
using System;
using System.Collections;
public class Player public class Player {
{ private readonly VirtualBoard board;
private VirtualBoard board; private readonly SelectedPiece selectedNode;
private SelectedPiece selectedNode; private readonly MoveRecords<VirtualPiece> moveRecords;
private MoveRecords<VirtualPiece> moveRecords; public EventHandler<VirtualBoard.MoveEventArgs> OnMove;
public ArrayList pieces = new();
public enum PlayerType { public enum PlayerType {
Human, Human,
@ -16,7 +19,7 @@ public class Player
this.board = board; this.board = board;
this.selectedNode = new SelectedPiece(board); this.selectedNode = new SelectedPiece(board);
this.moveRecords = new MoveRecords<VirtualPiece>(onUndoRecordCallback: (newNode, oldNode, newPos, oldPos) => { this.moveRecords = new MoveRecords<VirtualPiece>(onUndoRecordCallback: (newNode, oldNode, newPos, oldPos) => {
GD.Print("Undo: ", newNode, "->", oldNode, ":", newPos, "->", oldPos); // GD.Print("Undo: ", newNode, "->", oldNode, ":", newPos, "->", oldPos);
VirtualPiece newPiece = newNode; VirtualPiece newPiece = newNode;
VirtualPiece oldPiece = oldNode; VirtualPiece oldPiece = oldNode;
this.board.MovePiece(newPos, oldPos); this.board.MovePiece(newPos, oldPos);
@ -28,7 +31,7 @@ public class Player
public void HandleBoardPosClick(Vector2 clickPos) { public void HandleBoardPosClick(Vector2 clickPos) {
if (board.ArrPosOutOfRange(clickPos)) return; if (board.ArrPosOutOfRange(clickPos)) return;
GD.Print($"VirtualBoard {clickPos} clicked"); // GD.Print($"VirtualBoard {clickPos} clicked");
VirtualPiece clickChess = board.GetPiece(clickPos); VirtualPiece clickChess = board.GetPiece(clickPos);
if (!selectedNode.HasSelected()) { if (!selectedNode.HasSelected()) {
@ -43,13 +46,13 @@ public class Player
selectedNode.Clear(); selectedNode.Clear();
} else { } else {
// Move piece // Move piece
GD.Print("default MoveFunc Move: ", selectedNode.GetPos(), "->", clickPos); // GD.Print("default MoveFunc Move: ", selectedNode.GetPos(), "->", clickPos);
MoveAndRecord(clickPos, selectedNode.GetPos()); MoveAndRecord(clickPos, selectedNode.GetPos());
} }
} }
public void MoveAndRecord(Vector2 toPos, Vector2 fromPos) { public void MoveAndRecord(Vector2 toPos, Vector2 fromPos) {
GD.Print($"{fromPos} move to {toPos}"); // GD.Print($"{fromPos} move to {toPos}");
VirtualPiece toChess = board.GetPiece(toPos); VirtualPiece toChess = board.GetPiece(toPos);
VirtualPiece fromChess = board.GetPiece(fromPos); VirtualPiece fromChess = board.GetPiece(fromPos);
fromChess?.Selected(false); fromChess?.Selected(false);
@ -62,6 +65,8 @@ public class Player
NowNode = toChess; NowNode = toChess;
} }
moveRecords.AddRecord(NowNode, fromChess, toPos, fromPos); moveRecords.AddRecord(NowNode, fromChess, toPos, fromPos);
OnMove?.Invoke(this, new VirtualBoard.MoveEventArgs { From = fromPos, To = toPos });
board.MovePiece(fromPos, toPos); board.MovePiece(fromPos, toPos);
selectedNode.Clear(); selectedNode.Clear();
@ -81,46 +86,39 @@ public class Player
// board.InitChessBoard(); // board.InitChessBoard();
} }
private class SelectedPiece private class SelectedPiece {
{
// Called when the node enters the scene tree for the first time. // Called when the node enters the scene tree for the first time.
private Vector2 selectedNodePos = Vector2.Inf; private Vector2 selectedNodePos = Vector2.Inf;
private VirtualPiece piece; private VirtualPiece piece;
private VirtualBoard board; private readonly VirtualBoard board;
public SelectedPiece(VirtualBoard board) public SelectedPiece(VirtualBoard board) {
{
this.board = board; this.board = board;
} }
public void Clear() public void Clear() {
{
if (selectedNodePos != Vector2.Inf) { if (selectedNodePos != Vector2.Inf) {
selectedNodePos = Vector2.Inf; selectedNodePos = Vector2.Inf;
piece.Selected(false); piece.Selected(false);
} }
} }
public void SetPos(Vector2 pos) public void SetPos(Vector2 pos) {
{
// piece = board.GetNodeFromBoard(pos) as VirtualPiece; // piece = board.GetNodeFromBoard(pos) as VirtualPiece;
selectedNodePos = pos; selectedNodePos = pos;
piece = board.GetPiece(selectedNodePos); piece = board.GetPiece(selectedNodePos);
piece.Selected(true); piece.Selected(true);
} }
public VirtualPiece GetPiece() public VirtualPiece GetPiece() {
{
return piece; return piece;
} }
public Vector2 GetPos() public Vector2 GetPos() {
{
return selectedNodePos; return selectedNodePos;
} }
public bool HasSelected() public bool HasSelected() {
{
return selectedNodePos != Vector2.Inf; return selectedNodePos != Vector2.Inf;
} }
} }

View File

@ -1,7 +1,5 @@
using System; using System;
// using System.Numerics; using Vector2 = Godot.Vector2;
// using System.Transactions;
using Godot;
public class VirtualBoard { public class VirtualBoard {
private readonly int Rows; private readonly int Rows;

View File

@ -1,12 +1,10 @@
// using System.Numerics; using Vector2 = Godot.Vector2;
using Godot;
using System; using System;
public class VirtualPiece { public class VirtualPiece {
private Vector2 pos; // 注意这个坐标的非像素坐标而是棋盘坐标 private Vector2 pos; // 注意这个坐标的非像素坐标而是棋盘坐标
private string name; private readonly string name;
private bool isSelected; private bool isSelected;
public object data; public object data;

View File

@ -0,0 +1,59 @@
using Godot;
using System.Collections.Generic;
using System.IO;
class GodotConfigManager {
private readonly string ConfigFilePath;
private readonly ConfigFile config = new();
private readonly bool successful;
public GodotConfigManager(string ConfigFilePath) {
this.ConfigFilePath = ConfigFilePath;
Error err = config.Load(ConfigFilePath);
if (err == Error.Ok) {
successful = true;
} else {
successful = false;
GD.PrintErr("config.Load", err);
// OS.Alert("配置文件加载失败!", "错误");
return;
}
}
public void LoadConfig(string SessionName,
Dictionary<string, Variant> data) {
// 如果文件没有加载,忽略它。
if (!successful) {
return;
}
// 迭代所有小节。
foreach (string session in config.GetSections()) {
if (session == SessionName) {
foreach (var key in config.GetSectionKeys(session)) {
if (data.ContainsKey(key)) {
data[key] = config.GetValue(session, key);
}
}
}
}
}
public void SaveConfig(string SessionName,
Dictionary<string, Variant> data) {
// 将 GlobalConfig 中的键值对写入配置文件
foreach (var key in data.Keys)
{
GD.Print(data[key]);
config.SetValue(SessionName, key, data[key]);
}
// 保存配置文件
if (config.Save(ConfigFilePath) != Error.Ok) {
OS.Alert("配置文件保存失败!", "错误");
}
}
}

View File

@ -7,8 +7,8 @@ using System;
public class MoveRecords<T> { public class MoveRecords<T> {
private readonly LinkedList<MoveRecord> records = new LinkedList<MoveRecord>(); // 使用队列替换栈 private readonly LinkedList<MoveRecord> records = new LinkedList<MoveRecord>(); // 使用队列替换栈
private readonly int maxRecords; // 记录上限 private readonly int maxRecords; // 记录上限
private Action<T, T, Vector2, Vector2> onAddRecordCallback; // 添加记录时的回调 private readonly Action<T, T, Vector2, Vector2> onAddRecordCallback; // 添加记录时的回调
private Action<T, T, Vector2, Vector2> onUndoRecordCallback; // 撤销记录时的回调 private readonly Action<T, T, Vector2, Vector2> onUndoRecordCallback; // 撤销记录时的回调
public MoveRecords( public MoveRecords(
Action<T, T, Vector2, Vector2> onAddRecordCallback = null, Action<T, T, Vector2, Vector2> onAddRecordCallback = null,

View File

@ -23,6 +23,8 @@ Global="*res://Scripts/Global.cs"
window/size/viewport_width=720 window/size/viewport_width=720
window/size/viewport_height=1280 window/size/viewport_height=1280
window/stretch/mode="viewport"
window/handheld/orientation=1
[dotnet] [dotnet]