feat(chinese-chess): 实现中国象棋核心逻辑和基本功能
- 抽象出 ChessCore 类,包含游戏初始化、行棋逻辑、悔棋等功能 - 重构 Player 类,优化行棋和记录逻辑 - 更新 ChessBoard 和 ChessPiece 类,适应新逻辑 - 移除冗余代码,提高代码可读性和可维护性
This commit is contained in:
parent
6daf09b300
commit
8ee9732a6f
@ -113,6 +113,7 @@ size_flags_horizontal = 3
|
|||||||
[node name="Button" type="Button" parent="BoxContainer/HBoxContainer/MarginContainer"]
|
[node name="Button" type="Button" parent="BoxContainer/HBoxContainer/MarginContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
|
disabled = true
|
||||||
text = "Clear Config"
|
text = "Clear Config"
|
||||||
|
|
||||||
[node name="MarginContainer2" type="MarginContainer" parent="BoxContainer/HBoxContainer"]
|
[node name="MarginContainer2" type="MarginContainer" parent="BoxContainer/HBoxContainer"]
|
||||||
@ -121,6 +122,7 @@ size_flags_horizontal = 3
|
|||||||
|
|
||||||
[node name="Button2" type="Button" parent="BoxContainer/HBoxContainer/MarginContainer2"]
|
[node name="Button2" type="Button" parent="BoxContainer/HBoxContainer/MarginContainer2"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
disabled = true
|
||||||
text = "Clear User Data"
|
text = "Clear User Data"
|
||||||
|
|
||||||
[node name="HFlowContainer" type="HFlowContainer" parent="BoxContainer"]
|
[node name="HFlowContainer" type="HFlowContainer" parent="BoxContainer"]
|
||||||
@ -129,21 +131,25 @@ layout_mode = 2
|
|||||||
[node name="Button" type="Button" parent="BoxContainer/HFlowContainer"]
|
[node name="Button" type="Button" parent="BoxContainer/HFlowContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
|
disabled = true
|
||||||
text = "GetCacheDir"
|
text = "GetCacheDir"
|
||||||
|
|
||||||
[node name="Button2" type="Button" parent="BoxContainer/HFlowContainer"]
|
[node name="Button2" type="Button" parent="BoxContainer/HFlowContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
|
disabled = true
|
||||||
text = "GetConfigDir"
|
text = "GetConfigDir"
|
||||||
|
|
||||||
[node name="Button3" type="Button" parent="BoxContainer/HFlowContainer"]
|
[node name="Button3" type="Button" parent="BoxContainer/HFlowContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
|
disabled = true
|
||||||
text = "GetDataDir"
|
text = "GetDataDir"
|
||||||
|
|
||||||
[node name="Button4" type="Button" parent="BoxContainer/HFlowContainer"]
|
[node name="Button4" type="Button" parent="BoxContainer/HFlowContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
|
disabled = true
|
||||||
text = "GetUserDataDir"
|
text = "GetUserDataDir"
|
||||||
|
|
||||||
[connection signal="pressed" from="BoxContainer/MarginContainer/Back" to="." method="OnBack"]
|
[connection signal="pressed" from="BoxContainer/MarginContainer/Back" to="." method="OnBack"]
|
||||||
|
@ -1,29 +1,27 @@
|
|||||||
using System.Collections;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
|
using ChineseChess;
|
||||||
|
|
||||||
public partial class ChessGame : Node2D {
|
public partial class ChessGame : Node2D {
|
||||||
ChessBoard board;
|
ChessBoard board;
|
||||||
Global global;
|
Global global;
|
||||||
ConfirmationDialog dialog;
|
ConfirmationDialog dialog;
|
||||||
private bool isSession = false;
|
private bool isSession = false;
|
||||||
|
ChessCore Game;
|
||||||
private Player playerSelf;
|
ChessCore.TurnsSideType sideSelf;
|
||||||
private Player playerOpponent;
|
ChessCore.TurnsSideType sideOpposite;
|
||||||
|
|
||||||
// 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() {
|
||||||
{
|
|
||||||
// Init.Call();
|
// Init.Call();
|
||||||
global = GetNode<Global>("/root/Global");
|
global = GetNode<Global>("/root/Global");
|
||||||
board = GetNode<ChessBoard>("Chessboard");
|
board = GetNode<ChessBoard>("Chessboard");
|
||||||
isSession = global.RPClient.IsOnline();
|
isSession = global.RPClient.IsOnline();
|
||||||
|
|
||||||
playerSelf = new Player(board.board, Player.PlayerType.Human);
|
|
||||||
playerOpponent = new Player(board.board, Player.PlayerType.Human);
|
|
||||||
InitChessBoard();
|
|
||||||
GetNode<LineEdit>("Control/VBoxContainer/MarginContainer3/HFlowContainer/LineEdit")
|
GetNode<LineEdit>("Control/VBoxContainer/MarginContainer3/HFlowContainer/LineEdit")
|
||||||
.Text = global.GlobalData["player_color"].AsString();
|
.Text = global.GlobalData["player_color"].AsString();
|
||||||
|
LineEdit turnSideEdit = GetNode<LineEdit>("Control/VBoxContainer/MarginContainer3/HFlowContainer/LineEdit2");
|
||||||
|
turnSideEdit.Text = "red";
|
||||||
GD.PrintErr("ChessGame ", global.RPClient.GetUserId(), ":",global.GlobalData["player_color"]);
|
GD.PrintErr("ChessGame ", global.RPClient.GetUserId(), ":",global.GlobalData["player_color"]);
|
||||||
|
|
||||||
dialog = new ConfirmationDialog {
|
dialog = new ConfirmationDialog {
|
||||||
@ -33,18 +31,37 @@ public partial class ChessGame : Node2D {
|
|||||||
};
|
};
|
||||||
AddChild(dialog);
|
AddChild(dialog);
|
||||||
|
|
||||||
|
if (global.GlobalData["player_color"].AsString() == "red") {
|
||||||
|
sideSelf = ChessCore.TurnsSideType.Red;
|
||||||
|
sideOpposite = ChessCore.TurnsSideType.Black;
|
||||||
|
} else {
|
||||||
|
sideSelf = ChessCore.TurnsSideType.Black;
|
||||||
|
sideOpposite = ChessCore.TurnsSideType.Red;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSession) {
|
||||||
|
Game = new(ChessCore.Mode.MultiMode, sideSelf);
|
||||||
|
} else {
|
||||||
|
Game = new(ChessCore.Mode.SingleMode, sideSelf);
|
||||||
|
}
|
||||||
|
board.LoadBoard(Game.board);
|
||||||
|
Game.InitGame();
|
||||||
|
|
||||||
|
Game.board.OnMove += (sender, e) => {
|
||||||
|
turnSideEdit.Text = Game.GetTurnsType() == ChessCore.TurnsSideType.Red ? "red" : "black";
|
||||||
|
};
|
||||||
|
|
||||||
board.OnPosClicked += (sender, pos) => {
|
board.OnPosClicked += (sender, pos) => {
|
||||||
if (isSession) {
|
if (isSession) {
|
||||||
|
Game.OnPosClicked(pos, ChessCore.PlayerSideType.Self);
|
||||||
var res = global.RPClient.SendSessionToAll(global.sessionId, new Dictionary {
|
var res = global.RPClient.SendSessionToAll(global.sessionId, new Dictionary {
|
||||||
{"type", "mouseClicked"},
|
{"type", "mouseClicked"},
|
||||||
{"X", pos.X},
|
{"X", pos.X},
|
||||||
{"Y", pos.Y},
|
{"Y", pos.Y},
|
||||||
{"id", global.RPClient.GetUserId()}
|
{"id", global.RPClient.GetUserId()}
|
||||||
});
|
});
|
||||||
playerSelf.HandleBoardPosClick(pos);
|
|
||||||
} else {
|
} else {
|
||||||
playerSelf.HandleBoardPosClick(pos);
|
Game.OnPosClicked(pos);
|
||||||
playerSelf.SetAllowedPieces(null);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,44 +82,6 @@ public partial class ChessGame : Node2D {
|
|||||||
public override void _Process(double delta) {
|
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) {
|
private void SessionMsgHandle(Dictionary msg) {
|
||||||
GD.PrintErr($"session msg: {msg}");
|
GD.PrintErr($"session msg: {msg}");
|
||||||
switch (msg["type"].AsString()) {
|
switch (msg["type"].AsString()) {
|
||||||
@ -120,25 +99,17 @@ public partial class ChessGame : Node2D {
|
|||||||
}
|
}
|
||||||
Vector2 mouseClicked = new(GD.StrToVar(msg["X"].ToString()).AsInt32(),
|
Vector2 mouseClicked = new(GD.StrToVar(msg["X"].ToString()).AsInt32(),
|
||||||
GD.StrToVar(msg["Y"].ToString()).AsInt32());
|
GD.StrToVar(msg["Y"].ToString()).AsInt32());
|
||||||
playerOpponent.HandleBoardPosClick(mouseClicked);
|
Game.OnPosClicked(mouseClicked, ChessCore.PlayerSideType.Opponent);
|
||||||
break;
|
break;
|
||||||
case "undo":
|
case "undo":
|
||||||
if (msg["id"].ToString() == global.RPClient.GetUserId()) {
|
Game.Undo();
|
||||||
break;
|
|
||||||
}
|
|
||||||
playerOpponent.Undo();
|
|
||||||
break;
|
break;
|
||||||
case "reInit":
|
case "reInit":
|
||||||
_ReInit();
|
Game.ReInit();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _ReInit() {
|
|
||||||
playerSelf.ReInit();
|
|
||||||
InitChessBoard();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BtnOver() {
|
private void BtnOver() {
|
||||||
GD.Print($"BtnOver {isSession}");
|
GD.Print($"BtnOver {isSession}");
|
||||||
if (isSession == false) {
|
if (isSession == false) {
|
||||||
@ -161,13 +132,12 @@ public partial class ChessGame : Node2D {
|
|||||||
GD.Print($"Undo {isSession}");
|
GD.Print($"Undo {isSession}");
|
||||||
|
|
||||||
if (isSession) {
|
if (isSession) {
|
||||||
playerSelf.Undo();
|
|
||||||
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
|
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
|
||||||
{"type", "undo"},
|
{"type", "undo"},
|
||||||
{"id", global.RPClient.GetUserId()},
|
{"id", global.RPClient.GetUserId()},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
playerSelf.Undo();
|
Game.Undo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +149,7 @@ public partial class ChessGame : Node2D {
|
|||||||
{"type", "reInit"},
|
{"type", "reInit"},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
_ReInit();
|
Game.ReInit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,13 @@ using System;
|
|||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public partial class ChessBoard : Node2D {
|
public partial class ChessBoard : Node2D {
|
||||||
public VirtualBoard board = null;
|
|
||||||
public Player playerSelf = null;
|
|
||||||
|
|
||||||
public delegate bool ChessMoveFunc(Vector2 toPos, Vector2 fromPos);
|
|
||||||
// public Callable chessMoveFunc { get; set; }
|
|
||||||
public event EventHandler<Vector2> OnMouseClicked;
|
public event EventHandler<Vector2> OnMouseClicked;
|
||||||
public event EventHandler<Vector2> OnPosClicked;
|
public event EventHandler<Vector2> OnPosClicked;
|
||||||
|
|
||||||
public override void _Ready() {
|
public override void _Ready() {
|
||||||
board = new VirtualBoard(9, 10);
|
}
|
||||||
playerSelf = new Player(board);
|
|
||||||
|
|
||||||
|
public void LoadBoard(VirtualBoard board) {
|
||||||
board.OnRemove += (sender, piece) => {
|
board.OnRemove += (sender, piece) => {
|
||||||
if (piece.data != null) {
|
if (piece.data != null) {
|
||||||
RemoveChild(piece.data as Node);
|
RemoveChild(piece.data as Node);
|
||||||
@ -22,32 +17,28 @@ public partial class ChessBoard : Node2D {
|
|||||||
};
|
};
|
||||||
|
|
||||||
board.OnInsert += (sender, piece) => {
|
board.OnInsert += (sender, piece) => {
|
||||||
if (piece.data != null) {
|
if (piece.data != null && piece.data is Node) {
|
||||||
AddChild(piece.data as Node);
|
AddChild(piece.data as Node);
|
||||||
|
} else {
|
||||||
|
ChessPiece chessPiece = new(piece.name, piece);
|
||||||
|
|
||||||
|
if (piece.Pos().Y >= 5) {
|
||||||
|
chessPiece.LabelColor = new Color("red");
|
||||||
|
} else {
|
||||||
|
chessPiece.LabelColor = new Color("black");
|
||||||
|
}
|
||||||
|
AddChild(chessPiece);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// board.OnMove += (sender, args) => {
|
|
||||||
// // chessMoveFunc.Call(args.To, args.From);
|
|
||||||
// };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Input(InputEvent @event) {
|
public override void _Input(InputEvent @event) {
|
||||||
if (@event is InputEventMouseButton mouseEvent &&
|
if (@event is InputEventMouseButton mouseEvent &&
|
||||||
mouseEvent.Pressed &&
|
mouseEvent.Pressed &&
|
||||||
mouseEvent.ButtonIndex == MouseButton.Left) {
|
mouseEvent.ButtonIndex == MouseButton.Left) {
|
||||||
// HandleMouseClick(GetGlobalTransformWithCanvas().AffineInverse() * mouseButton.Position);
|
|
||||||
|
|
||||||
OnMouseClicked?.Invoke(this, GetLocalMousePosition());
|
OnMouseClicked?.Invoke(this, GetLocalMousePosition());
|
||||||
OnPosClicked?.Invoke(this, (PosTrans.transArrToPix.AffineInverse() *
|
OnPosClicked?.Invoke(this, (PosTrans.transArrToPix.AffineInverse() *
|
||||||
GetLocalMousePosition()).Round());
|
GetLocalMousePosition()).Round());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InsertNode(ChessPiece node, Vector2 arrayPos) {
|
|
||||||
AddChild(node);
|
|
||||||
VirtualPiece piece = node.GetVirtualPiece();
|
|
||||||
// piece.Move(vector);
|
|
||||||
board.SetPiecePos(piece, arrayPos);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ public partial class ChessPiece : Sprite2D {
|
|||||||
public string PieceLabel { get; set; } = null;
|
public string PieceLabel { get; set; } = null;
|
||||||
// 文字颜色(可导出以编辑器调整)
|
// 文字颜色(可导出以编辑器调整)
|
||||||
[Export]
|
[Export]
|
||||||
public Color LabelColor { get; set; } = new Color("black");
|
public Color LabelColor { get; set; } = new Color("white");
|
||||||
private Vector2 textureSize;
|
private Vector2 textureSize;
|
||||||
|
|
||||||
private Label labelOfChessName;
|
private Label labelOfChessName;
|
||||||
@ -37,12 +37,12 @@ public partial class ChessPiece : Sprite2D {
|
|||||||
new Vector2(0, 0)
|
new Vector2(0, 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
public ChessPiece() : this("", Vector2.Zero){
|
public ChessPiece() : this("", new()){
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChessPiece(string name, Vector2 pos) {
|
public ChessPiece(string name, VirtualPiece piece) {
|
||||||
PieceLabel = name;
|
PieceLabel = name;
|
||||||
piece = new VirtualPiece(name, pos);
|
this.piece = piece;
|
||||||
piece.OnMove += OnMove;
|
piece.OnMove += OnMove;
|
||||||
piece.OnSelected += OnSelected;
|
piece.OnSelected += OnSelected;
|
||||||
piece.data = this;
|
piece.data = this;
|
||||||
|
@ -0,0 +1,154 @@
|
|||||||
|
using Vector2 = Godot.Vector2;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
namespace ChineseChess;
|
||||||
|
|
||||||
|
class ChessCore {
|
||||||
|
public enum Mode {
|
||||||
|
SingleMode,
|
||||||
|
MultiMode,
|
||||||
|
DebugMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum TurnsSideType {
|
||||||
|
Red,
|
||||||
|
Black,
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum PlayerSideType {
|
||||||
|
Self,
|
||||||
|
Opponent,
|
||||||
|
Any,
|
||||||
|
};
|
||||||
|
|
||||||
|
private TurnsSideType sideType = TurnsSideType.Red;
|
||||||
|
private readonly TurnsSideType selfSide;
|
||||||
|
public readonly VirtualBoard board = new(9, 10);
|
||||||
|
private readonly Player playerSelf;
|
||||||
|
private readonly Player playerOpponent;
|
||||||
|
private readonly MoveRecords<VirtualPiece> moveRecords;
|
||||||
|
public EventHandler<VirtualBoard.MoveEventArgs> OnMove;
|
||||||
|
|
||||||
|
public ChessCore(Mode mode, TurnsSideType selfSide) {
|
||||||
|
this.selfSide = selfSide;
|
||||||
|
|
||||||
|
playerSelf = new(board, Player.PlayerType.Human);
|
||||||
|
playerOpponent = new(board, Player.PlayerType.Human);
|
||||||
|
|
||||||
|
playerSelf.OnMove += (sender, args) => {
|
||||||
|
moveRecords.AddRecord(board.GetPiece(args.To), board.GetPiece(args.From),
|
||||||
|
args.To, args.From);
|
||||||
|
};
|
||||||
|
playerOpponent.OnMove += (sender, args) => {
|
||||||
|
moveRecords.AddRecord(board.GetPiece(args.To), board.GetPiece(args.From),
|
||||||
|
args.To, args.From);
|
||||||
|
};
|
||||||
|
|
||||||
|
moveRecords = new MoveRecords<VirtualPiece>(
|
||||||
|
onAddRecordCallback: (newNode, oldNode, newPos, oldPos) => {
|
||||||
|
playerSelf.SelectedClear();
|
||||||
|
playerOpponent.SelectedClear();
|
||||||
|
},
|
||||||
|
onUndoRecordCallback: (newNode, oldNode, newPos, oldPos) => {
|
||||||
|
// GD.Print("Undo: ", newNode, "->", oldNode, ":", newPos, "->", oldPos);
|
||||||
|
VirtualPiece newPiece = newNode;
|
||||||
|
VirtualPiece oldPiece = oldNode;
|
||||||
|
board.MovePiece(newPos, oldPos);
|
||||||
|
if (newPiece != null) {
|
||||||
|
board.InsertPiece(newPiece, newPos);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case Mode.SingleMode:
|
||||||
|
break;
|
||||||
|
case Mode.MultiMode:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case Mode.DebugMode:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitGame() {
|
||||||
|
ArrayList blackPart = InitOnePartPieces(TurnsSideType.Black, 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 redPart = InitOnePartPieces(TurnsSideType.Red, 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 (selfSide == TurnsSideType.Red) {
|
||||||
|
playerSelf.SetAllowedPieces(redPart);
|
||||||
|
playerOpponent.SetAllowedPieces(blackPart);
|
||||||
|
} else {
|
||||||
|
playerSelf.SetAllowedPieces(blackPart);
|
||||||
|
playerOpponent.SetAllowedPieces(redPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList InitOnePartPieces(TurnsSideType side, (string label, int x, int y)[] positions) {
|
||||||
|
ArrayList list = new();
|
||||||
|
foreach (var (label, x, y) in positions) {
|
||||||
|
// FIXME: use a better way to initialize pieces
|
||||||
|
Vector2 pos = new(x, y + (TurnsSideType.Red == side ? 9 : 0));
|
||||||
|
VirtualPiece piece = new(label, pos);
|
||||||
|
list.Add(piece);
|
||||||
|
board.InsertPiece(piece, pos);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnPosClicked(Vector2 pos, PlayerSideType clickedSide = PlayerSideType.Any) {
|
||||||
|
if (sideType == selfSide) {
|
||||||
|
playerSelf.CanMove = true;
|
||||||
|
playerOpponent.CanMove = false;
|
||||||
|
} else {
|
||||||
|
playerSelf.CanMove = false;
|
||||||
|
playerOpponent.CanMove = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (clickedSide) {
|
||||||
|
case PlayerSideType.Any:
|
||||||
|
playerSelf.HandleBoardPosClick(pos);
|
||||||
|
playerOpponent.HandleBoardPosClick(pos);
|
||||||
|
break;
|
||||||
|
case PlayerSideType.Self:
|
||||||
|
playerSelf.HandleBoardPosClick(pos);
|
||||||
|
break;
|
||||||
|
case PlayerSideType.Opponent:
|
||||||
|
playerOpponent.HandleBoardPosClick(pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sideType = moveRecords.Count() % 2 == 0 ? TurnsSideType.Red : TurnsSideType.Black;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TurnsSideType GetTurnsType() {
|
||||||
|
sideType = moveRecords.Count() % 2 == 0 ? TurnsSideType.Red : TurnsSideType.Black;
|
||||||
|
return sideType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Undo() {
|
||||||
|
playerSelf.SelectedClear();
|
||||||
|
playerOpponent.SelectedClear();
|
||||||
|
moveRecords.Undo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReInit() {
|
||||||
|
playerSelf.SelectedClear();
|
||||||
|
playerOpponent.SelectedClear();
|
||||||
|
moveRecords.Clear();
|
||||||
|
board.Clear();
|
||||||
|
InitGame();
|
||||||
|
}
|
||||||
|
}
|
@ -5,9 +5,9 @@ using System.Collections;
|
|||||||
public class Player {
|
public class Player {
|
||||||
private readonly VirtualBoard board;
|
private readonly VirtualBoard board;
|
||||||
private readonly SelectedPiece selectedNode;
|
private readonly SelectedPiece selectedNode;
|
||||||
private readonly MoveRecords<VirtualPiece> moveRecords;
|
|
||||||
public EventHandler<VirtualBoard.MoveEventArgs> OnMove;
|
|
||||||
|
|
||||||
|
public EventHandler<VirtualBoard.MoveEventArgs> OnMove;
|
||||||
|
public bool CanMove { get; set; } = true;
|
||||||
|
|
||||||
public enum PlayerType {
|
public enum PlayerType {
|
||||||
Human,
|
Human,
|
||||||
@ -18,15 +18,6 @@ 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) => {
|
|
||||||
// GD.Print("Undo: ", newNode, "->", oldNode, ":", newPos, "->", oldPos);
|
|
||||||
VirtualPiece newPiece = newNode;
|
|
||||||
VirtualPiece oldPiece = oldNode;
|
|
||||||
this.board.MovePiece(newPos, oldPos);
|
|
||||||
if (newPiece != null) {
|
|
||||||
this.board.InsertPiece(newPiece, newPos);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleBoardPosClick(Vector2 clickPos) {
|
public void HandleBoardPosClick(Vector2 clickPos) {
|
||||||
@ -47,7 +38,7 @@ public class Player {
|
|||||||
} 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());
|
if (CanMove) MoveAndRecord(clickPos, selectedNode.GetPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +48,9 @@ public class Player {
|
|||||||
VirtualPiece fromChess = board.GetPiece(fromPos);
|
VirtualPiece fromChess = board.GetPiece(fromPos);
|
||||||
fromChess?.Selected(false);
|
fromChess?.Selected(false);
|
||||||
|
|
||||||
|
// MUST BE THERE !!! 防止删除节点后在启动回调导致错误
|
||||||
|
OnMove?.Invoke(this, new VirtualBoard.MoveEventArgs { From = fromPos, To = toPos });
|
||||||
|
|
||||||
VirtualPiece NowNode;
|
VirtualPiece NowNode;
|
||||||
if (toChess != null) {
|
if (toChess != null) {
|
||||||
NowNode = toChess;
|
NowNode = toChess;
|
||||||
@ -64,26 +58,13 @@ public class Player {
|
|||||||
} else {
|
} else {
|
||||||
NowNode = toChess;
|
NowNode = toChess;
|
||||||
}
|
}
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Undo() {
|
public void SelectedClear() {
|
||||||
// ChessPiece selected = selectedNode.GetPiece();
|
|
||||||
// selected?.DeSelected();
|
|
||||||
selectedNode.Clear();
|
selectedNode.Clear();
|
||||||
moveRecords.Undo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReInit() {
|
|
||||||
moveRecords.Clear();
|
|
||||||
board.Clear();
|
|
||||||
selectedNode.Clear();
|
|
||||||
// board.InitChessBoard();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetAllowedPieces(ArrayList allowedPieces) {
|
public void SetAllowedPieces(ArrayList allowedPieces) {
|
||||||
|
@ -55,10 +55,9 @@ public class VirtualBoard {
|
|||||||
if (GetPiece(arrayPos) != null) {
|
if (GetPiece(arrayPos) != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnInsert?.Invoke(this, piece);
|
OnInsert?.Invoke(this, piece);
|
||||||
SetPiecePos(piece, arrayPos);
|
|
||||||
|
|
||||||
|
SetPiecePos(piece, arrayPos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +73,6 @@ public class VirtualBoard {
|
|||||||
OnMove?.Invoke(this, new MoveEventArgs { From = from, To = to });
|
OnMove?.Invoke(this, new MoveEventArgs { From = from, To = to });
|
||||||
|
|
||||||
SetPiecePos(SetPiecePos(null, from), to);
|
SetPiecePos(SetPiecePos(null, from), to);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ using System;
|
|||||||
public class VirtualPiece {
|
public class VirtualPiece {
|
||||||
private Vector2 pos; // 注意这个坐标的非像素坐标而是棋盘坐标
|
private Vector2 pos; // 注意这个坐标的非像素坐标而是棋盘坐标
|
||||||
|
|
||||||
private readonly string name;
|
public readonly string name;
|
||||||
private bool isSelected;
|
private bool isSelected;
|
||||||
public object data;
|
public object data;
|
||||||
|
|
||||||
|
@ -31,6 +31,10 @@ public class MoveRecords<T> {
|
|||||||
records.AddLast(record); // 将新记录加入队尾
|
records.AddLast(record); // 将新记录加入队尾
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Count() {
|
||||||
|
return records.Count;
|
||||||
|
}
|
||||||
|
|
||||||
public void Undo() {
|
public void Undo() {
|
||||||
if (records.Count == 0) return;
|
if (records.Count == 0) return;
|
||||||
MoveRecord record = records.Last.Value; // 移除并获取队首的记录以执行撤销操作
|
MoveRecord record = records.Last.Value; // 移除并获取队首的记录以执行撤销操作
|
||||||
|
Loading…
x
Reference in New Issue
Block a user