feat(chess): 初始化棋盘和玩家颜色,优化代码结构,重构多人游戏代码

- 在 ChessGame 中初始化棋盘,根据玩家颜色设置棋子
- 更新 UI 显示玩家颜色
- 调整棋盘位置和 UI 布局
- 重构部分代码以提高可读性和维护性
This commit is contained in:
ZZY 2024-11-07 15:28:03 +08:00
parent d6cbb5e11d
commit 6daf09b300
11 changed files with 161 additions and 220 deletions

View File

@ -8,7 +8,7 @@
script = ExtResource("1_3x8ac")
[node name="Chessboard" parent="." instance=ExtResource("1_yheur")]
position = Vector2(360, 600)
position = Vector2(360, 650)
scale = Vector2(2.5, 2.5)
[node name="Control" type="Control" parent="."]
@ -19,41 +19,69 @@ offset_right = 720.0
offset_bottom = 1280.0
theme = ExtResource("3_rcfhx")
[node name="MarginContainer" type="MarginContainer" parent="Control"]
[node name="VBoxContainer" type="VBoxContainer" parent="Control"]
layout_mode = 1
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 81.0
offset_bottom = 133.0
grow_horizontal = 2
[node name="HBoxContainer" type="HBoxContainer" parent="Control/MarginContainer"]
[node name="MarginContainer" type="MarginContainer" parent="Control/VBoxContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="Control/MarginContainer/HBoxContainer"]
[node name="HBoxContainer" type="HBoxContainer" parent="Control/VBoxContainer/MarginContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="Control/VBoxContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Home" type="Button" parent="Control/MarginContainer/HBoxContainer/MarginContainer"]
[node name="Home" type="Button" parent="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer"]
layout_mode = 2
text = "返回主页"
[node name="MarginContainer2" type="MarginContainer" parent="Control/MarginContainer/HBoxContainer"]
[node name="MarginContainer2" type="MarginContainer" parent="Control/VBoxContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Undo" type="Button" parent="Control/MarginContainer/HBoxContainer/MarginContainer2"]
[node name="Undo" type="Button" parent="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer2"]
layout_mode = 2
size_flags_vertical = 4
text = "撤回"
[node name="MarginContainer3" type="MarginContainer" parent="Control/MarginContainer/HBoxContainer"]
[node name="MarginContainer3" type="MarginContainer" parent="Control/VBoxContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="ReInit" type="Button" parent="Control/MarginContainer/HBoxContainer/MarginContainer3"]
[node name="ReInit" type="Button" parent="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer3"]
layout_mode = 2
text = "重开"
[node name="MarginContainer3" type="MarginContainer" parent="Control/VBoxContainer"]
layout_mode = 2
[node name="HFlowContainer" type="HFlowContainer" parent="Control/VBoxContainer/MarginContainer3"]
layout_mode = 2
[node name="Label" type="Label" parent="Control/VBoxContainer/MarginContainer3/HFlowContainer"]
layout_mode = 2
text = "You Are
"
[node name="LineEdit" type="LineEdit" parent="Control/VBoxContainer/MarginContainer3/HFlowContainer"]
layout_mode = 2
size_flags_horizontal = 3
editable = false
[node name="Label2" type="Label" parent="Control/VBoxContainer/MarginContainer3/HFlowContainer"]
layout_mode = 2
text = "Turns On"
[node name="LineEdit2" type="LineEdit" parent="Control/VBoxContainer/MarginContainer3/HFlowContainer"]
layout_mode = 2
size_flags_horizontal = 3
editable = false
[node name="MarginContainer2" type="MarginContainer" parent="Control"]
layout_mode = 1
anchors_preset = 12
@ -69,7 +97,7 @@ layout_mode = 2
text = "结束回合
(提示对方结束)"
[connection signal="pressed" from="Control/MarginContainer/HBoxContainer/MarginContainer/Home" to="." method="GoHome"]
[connection signal="pressed" from="Control/MarginContainer/HBoxContainer/MarginContainer2/Undo" to="." method="Undo"]
[connection signal="pressed" from="Control/MarginContainer/HBoxContainer/MarginContainer3/ReInit" to="." method="ReInit"]
[connection signal="pressed" from="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer/Home" to="." method="GoHome"]
[connection signal="pressed" from="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer2/Undo" to="." method="Undo"]
[connection signal="pressed" from="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer3/ReInit" to="." method="ReInit"]
[connection signal="pressed" from="Control/MarginContainer2/Over" to="." method="BtnOver"]

View File

@ -1,128 +0,0 @@
[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="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/defaultTheme.tres" id="1_mkeko"]
[node name="Menu" 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_mkeko")
script = ExtResource("1_chiyi")
metadata/_edit_horizontal_guides_ = [141.0]
metadata/_edit_use_anchors_ = true
[node name="Home" type="Button" parent="."]
layout_mode = 0
offset_left = 49.0
offset_top = 100.0
offset_right = 171.0
offset_bottom = 170.0
text = "返回主页"
[node name="Name" type="Control" parent="."]
anchors_preset = 0
offset_left = 215.0
offset_top = 109.0
offset_right = 697.0
offset_bottom = 168.0
[node name="Label" type="Label" parent="Name"]
layout_mode = 2
offset_left = 2.0
offset_top = 1.0
offset_right = 80.0
offset_bottom = 47.0
text = "名字"
horizontal_alignment = 1
vertical_alignment = 1
[node name="LineEdit" type="LineEdit" parent="Name"]
layout_mode = 2
offset_left = 93.0
offset_right = 320.0
offset_bottom = 50.0
[node name="Button" type="Button" parent="Name"]
layout_mode = 0
offset_left = 340.0
offset_top = 3.0
offset_right = 428.0
offset_bottom = 55.0
text = "确认修改
"
[node name="Server" type="Control" parent="."]
anchors_preset = 0
offset_left = 19.0
offset_top = 184.0
offset_right = 705.0
offset_bottom = 1198.0
[node name="ItemList" type="ItemList" parent="Server"]
layout_mode = 0
offset_left = 15.0
offset_top = 214.0
offset_right = 678.0
offset_bottom = 1059.0
[node name="ConnectServer" type="Button" parent="Server"]
layout_mode = 0
offset_left = 297.0
offset_top = 17.0
offset_right = 517.0
offset_bottom = 90.0
text = "重连服务器"
[node name="Flush" type="Button" parent="Server"]
layout_mode = 0
offset_left = 535.0
offset_top = 17.0
offset_right = 652.0
offset_bottom = 81.0
text = "Flush"
[node name="ColorRect" type="ColorRect" parent="Server"]
layout_mode = 0
offset_left = 236.0
offset_top = 35.0
offset_right = 276.0
offset_bottom = 75.0
[node name="Label" type="Label" parent="Server"]
layout_mode = 0
offset_left = 19.0
offset_top = 37.0
offset_right = 229.0
offset_bottom = 79.0
text = "服务器连接状态"
[node name="Dialogs" type="Control" parent="."]
anchors_preset = 0
[node name="AcceptDialog" type="AcceptDialog" parent="Dialogs"]
initial_position = 2
size = Vector2i(100, 118)
[node name="PopupMenu" type="PopupMenu" parent="Dialogs"]
[node name="ConfirmationDialog" type="ConfirmationDialog" parent="Dialogs"]
initial_position = 2
size = Vector2i(200, 118)
[node name="URL" type="LineEdit" parent="."]
visible = false
layout_mode = 0
offset_left = 37.0
offset_top = 290.0
offset_right = 677.0
offset_bottom = 371.0
[connection signal="pressed" from="Home" to="." method="goToHome"]
[connection signal="pressed" from="Name/Button" to="." method="EnterName"]
[connection signal="item_activated" from="Server/ItemList" to="." method="OnItemSelected"]
[connection signal="pressed" from="Server/ConnectServer" to="." method="Connect"]
[connection signal="pressed" from="Server/Flush" to="." method="FlushData"]

View File

@ -147,6 +147,7 @@ size_flags_horizontal = 3
text = "GetUserDataDir"
[connection signal="pressed" from="BoxContainer/MarginContainer/Back" to="." method="OnBack"]
[connection signal="pressed" from="BoxContainer/MarginContainer7/Button" to="." method="OnSave"]
[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"]

View File

@ -1,8 +1,8 @@
using System.Collections;
using Godot;
using Godot.Collections;
public partial class ChessGame : Node2D
{
public partial class ChessGame : Node2D {
ChessBoard board;
Global global;
ConfirmationDialog dialog;
@ -17,17 +17,14 @@ public partial class ChessGame : Node2D
// Init.Call();
global = GetNode<Global>("/root/Global");
board = GetNode<ChessBoard>("Chessboard");
isSession = global.RPClient.IsOnline();
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);
};
InitChessBoard();
GetNode<LineEdit>("Control/VBoxContainer/MarginContainer3/HFlowContainer/LineEdit")
.Text = global.GlobalData["player_color"].AsString();
GD.PrintErr("ChessGame ", global.RPClient.GetUserId(), ":",global.GlobalData["player_color"]);
dialog = new ConfirmationDialog {
DialogAutowrap = true,
@ -36,37 +33,76 @@ public partial class ChessGame : Node2D
};
AddChild(dialog);
if (!global.RPClient.GetIsConnected()) {
return;
board.OnPosClicked += (sender, pos) => {
if (isSession) {
var res = global.RPClient.SendSessionToAll(global.sessionId, new Dictionary {
{"type", "mouseClicked"},
{"X", pos.X},
{"Y", pos.Y},
{"id", global.RPClient.GetUserId()}
});
playerSelf.HandleBoardPosClick(pos);
} else {
playerSelf.HandleBoardPosClick(pos);
playerSelf.SetAllowedPieces(null);
}
};
if (isSession) {
GD.Print("ws is connected");
global.RPClient.OnPRCSessionExit += (cmd, code) => {
GoHome();
};
global.RPClient.OnPRCSessionRecv += (msg) => {
SessionMsgHandle(msg["msg"].AsGodotDictionary());
};
}
isSession = true;
GD.Print("ws is connected");
global.RPClient.OnPRCSessionExit += (cmd, code) => {
GoHome();
};
board.OnMouseClicked += (sender, clickPosition) => {
Vector2 clickBoardPos = (PosTrans.transArrToPix.AffineInverse() *
clickPosition).Round();
var res = global.RPClient.SendSessionToAll(global.sessionId, new Dictionary {
{"type", "mouseClicked"},
{"X", clickBoardPos.X},
{"Y", clickBoardPos.Y},
});
// GD.Print($"chessMoveFunc Callback {fromPos} -> {newPos} {res}");
};
global.RPClient.OnPRCSessionRecv += (msg) => {
SessionMsgHandle(msg["msg"].AsGodotDictionary());
};
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta) {
}
public void InitChessBoard() {
ArrayList black = InitializePieces("black", 0, new[] {
("车", 0, 0), ("马", 1, 0), ("象", 2, 0),
("士", 3, 0), ("将", 4, 0), ("士", 5, 0),
("象", 6, 0), ("马", 7, 0), ("车", 8, 0),
("炮", 1, 2), ("炮", 7, 2),
("卒", 0, 3), ("卒", 2, 3), ("卒", 4, 3), ("卒", 6, 3), ("卒", 8, 3)
});
ArrayList red = InitializePieces("red", 9, new[] {
("车", 0, -0), ("马", 1, -0), ("象", 2, -0),
("士", 3, -0), ("将", 4, -0), ("士", 5, -0),
("象", 6, -0), ("马", 7, -0), ("车", 8, -0),
("炮", 1, -2), ("炮", 7, -2),
("卒", 0, -3), ("卒", 2, -3), ("卒", 4, -3), ("卒", 6, -3), ("卒", 8, -3)
});
if (global.GlobalData["player_color"].AsString() == "red") {
playerSelf.SetAllowedPieces(red);
playerOpponent.SetAllowedPieces(black);
} else {
playerSelf.SetAllowedPieces(black);
playerOpponent.SetAllowedPieces(red);
}
}
private ArrayList InitializePieces(string color, int baseY, (string label, int x, int y)[] positions) {
ArrayList list = new();
foreach (var (label, x, y) in positions) {
ChessPiece piece = new ChessPiece {
PieceLabel = label,
LabelColor = new Color(color)
};
list.Add(piece.GetVirtualPiece());
board.InsertNode(piece, new Vector2(x, baseY + y));
}
return list;
}
private void SessionMsgHandle(Dictionary msg) {
GD.PrintErr($"session msg: {msg}");
switch (msg["type"].AsString()) {
@ -79,12 +115,18 @@ public partial class ChessGame : Node2D
dialog.Visible = true;
break;
case "mouseClicked":
if (msg["id"].ToString() == global.RPClient.GetUserId()) {
break;
}
Vector2 mouseClicked = new(GD.StrToVar(msg["X"].ToString()).AsInt32(),
GD.StrToVar(msg["Y"].ToString()).AsInt32());
playerOpponent.HandleBoardPosClick(mouseClicked);
break;
case "undo":
_Undo();
if (msg["id"].ToString() == global.RPClient.GetUserId()) {
break;
}
playerOpponent.Undo();
break;
case "reInit":
_ReInit();
@ -92,13 +134,9 @@ public partial class ChessGame : Node2D
}
}
private void _Undo() {
playerSelf.Undo();
}
private void _ReInit() {
playerSelf.ReInit();
board.InitChessBoard();
InitChessBoard();
}
private void BtnOver() {
@ -123,11 +161,13 @@ public partial class ChessGame : Node2D
GD.Print($"Undo {isSession}");
if (isSession) {
playerSelf.Undo();
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
{"type", "undo"},
{"id", global.RPClient.GetUserId()},
});
} else {
_Undo();
playerSelf.Undo();
}
}

View File

@ -10,6 +10,7 @@ public partial class GameLobby : Control {
string URL;
string userName;
bool isAcceptedPart = false;
// Called when the node enters the scene tree for the first time.
public override void _Ready() {
@ -26,8 +27,11 @@ public partial class GameLobby : Control {
global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), false);
};
dialog.Confirmed += () => {
if (dialog.Title == "Session Created")
global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), true);
if (dialog.Title == "Session Created") {
// FIXME
isAcceptedPart = true;
global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), true);
}
};
global.RPClient.OnOpen += (string eventName, object[] args) => {
@ -56,7 +60,14 @@ public partial class GameLobby : Control {
dialog.Visible = true;
} else {
if (res) {
// TODO FIXME
global.sessionId = sessionId;
if (!isAcceptedPart) {
global.GlobalData["player_color"] = "red";
} else {
global.GlobalData["player_color"] = "black";
}
// GD.PrintErr("sessionId: ", reqUserId, "color: ", global.GlobalData["player_color"].AsString());
global.GotoScene("res://Scenes/ChessGame.tscn");
} else {
dialog.Title = "Failed";

View File

@ -33,9 +33,13 @@ public partial class Setting : Control
}
private void OnBack() {
global.SaveConfig();
global.GotoScene("res://Main.tscn", null);
}
private void OnSave() {
global.SaveConfig();
// OS.Alert("Saved", "Setting");
}
void OnNameChanged(string Value)
{

View File

@ -9,6 +9,7 @@ public partial class ChessBoard : Node2D {
public delegate bool ChessMoveFunc(Vector2 toPos, Vector2 fromPos);
// public Callable chessMoveFunc { get; set; }
public event EventHandler<Vector2> OnMouseClicked;
public event EventHandler<Vector2> OnPosClicked;
public override void _Ready() {
board = new VirtualBoard(9, 10);
@ -29,8 +30,6 @@ public partial class ChessBoard : Node2D {
// board.OnMove += (sender, args) => {
// // chessMoveFunc.Call(args.To, args.From);
// };
InitChessBoard();
}
public override void _Input(InputEvent @event) {
@ -40,6 +39,8 @@ public partial class ChessBoard : Node2D {
// HandleMouseClick(GetGlobalTransformWithCanvas().AffineInverse() * mouseButton.Position);
OnMouseClicked?.Invoke(this, GetLocalMousePosition());
OnPosClicked?.Invoke(this, (PosTrans.transArrToPix.AffineInverse() *
GetLocalMousePosition()).Round());
}
}
@ -49,32 +50,4 @@ public partial class ChessBoard : Node2D {
// piece.Move(vector);
board.SetPiecePos(piece, arrayPos);
}
public void InitChessBoard() {
InitializePieces("black", 0, new[] {
("车", 0, 0), ("马", 1, 0), ("象", 2, 0),
("士", 3, 0), ("将", 4, 0), ("士", 5, 0),
("象", 6, 0), ("马", 7, 0), ("车", 8, 0),
("炮", 1, 2), ("炮", 7, 2),
("卒", 0, 3), ("卒", 2, 3), ("卒", 4, 3), ("卒", 6, 3), ("卒", 8, 3)
});
InitializePieces("red", 9, new[] {
("车", 0, -0), ("马", 1, -0), ("象", 2, -0),
("士", 3, -0), ("将", 4, -0), ("士", 5, -0),
("象", 6, -0), ("马", 7, -0), ("车", 8, -0),
("炮", 1, -2), ("炮", 7, -2),
("卒", 0, -3), ("卒", 2, -3), ("卒", 4, -3), ("卒", 6, -3), ("卒", 8, -3)
});
}
private void InitializePieces(string color, int baseY, (string label, int x, int y)[] positions) {
foreach (var (label, x, y) in positions) {
ChessPiece piece = new ChessPiece {
PieceLabel = label,
LabelColor = new Color(color)
};
InsertNode(piece, new Vector2(x, baseY + y));
}
}
}

View File

@ -31,7 +31,7 @@ public partial class ChessPiece : Sprite2D {
}
}
Transform2D transToSeleted = new Transform2D(
Transform2D transToSeleted = new(
new Vector2(1.2f, 0),
new Vector2(0, 1.2f),
new Vector2(0, 0)

View File

@ -16,6 +16,10 @@ public partial class Global : Node
{"user_name", "undefined"}
};
public Dictionary<string, Variant> GlobalData = new() {
{"player_color", "red"},
};
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
@ -69,7 +73,7 @@ public partial class Global : Node
public override void _Notification(int what)
{
if (what == NotificationWMCloseRequest) {
SaveConfig();
// SaveConfig();
RPClient.Close();
GetTree().Quit(); // default behavior
}

View File

@ -15,7 +15,7 @@ public partial class RPClientBaseEDWS : EventDrivenWebSocket {
public RPClientBaseEDWS() : base() {
OnText += (text) => {
GD.Print($"response: {text}");
// GD.Print($"response: {text}");
RPMessage msg = RPHelper.HandleIncomingMessage(text);
if (msg.Code != "0000") {
OnRPCError?.Invoke(msg.Code, msg.Type, msg.Cmd, msg.Data.ToString());

View File

@ -7,7 +7,7 @@ public class Player {
private readonly SelectedPiece selectedNode;
private readonly MoveRecords<VirtualPiece> moveRecords;
public EventHandler<VirtualBoard.MoveEventArgs> OnMove;
public ArrayList pieces = new();
public enum PlayerType {
Human,
@ -86,11 +86,16 @@ public class Player {
// board.InitChessBoard();
}
public void SetAllowedPieces(ArrayList allowedPieces) {
selectedNode.allowedPieces = allowedPieces;
}
private class SelectedPiece {
// Called when the node enters the scene tree for the first time.
private Vector2 selectedNodePos = Vector2.Inf;
private VirtualPiece piece;
private readonly VirtualBoard board;
public ArrayList allowedPieces = null;
public SelectedPiece(VirtualBoard board) {
this.board = board;
@ -105,8 +110,11 @@ public class Player {
public void SetPos(Vector2 pos) {
// piece = board.GetNodeFromBoard(pos) as VirtualPiece;
piece = board.GetPiece(pos);
if (allowedPieces != null && allowedPieces.Contains(piece) == false) {
return;
}
selectedNodePos = pos;
piece = board.GetPiece(selectedNodePos);
piece.Selected(true);
}