bugfix 重新提交暂存区

This commit is contained in:
ZZY 2024-11-03 21:15:33 +08:00
parent d1dea9a89d
commit d323a0bee7
52 changed files with 5229 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

27
.gitignore vendored Normal file
View File

@ -0,0 +1,27 @@
# Godot 4+ specific ignores
.godot/
# Godot-specific
*.import
.import/
export.cfg
export_presets.cfg
# Imported translations (automatically generated from CSV files)
*.translation
# Mono-specific ignores
.mono/
data_*/
mono_crash.*.json
# MyProject specific ignores
.vscode/
.vs/
Bin/
bin/
*.aseprite
*.csproj
*.sln
*.error
*.key*

38
Asserts/Chessboard.tres Normal file
View File

@ -0,0 +1,38 @@
[gd_resource type="TileSet" load_steps=7 format=3 uid="uid://bibjj3ay65ral"]
[ext_resource type="Texture2D" uid="uid://p060studh7ph" path="res://Asserts/pic/chessboard.png" id="2_5i53i"]
[ext_resource type="Texture2D" uid="uid://dwjo6wa85r4il" path="res://Asserts/pic/cross_set_plus.png" id="3_ouwnc"]
[sub_resource type="TileMapPattern" id="TileMapPattern_s62cf"]
tile_data = PackedInt32Array(0, 36, 1610612737, 131072, 37, 1073741824, 262144, 196644, 1073741824, 393216, 196644, 1073741824, 524288, 36, 805306369, 2, 196644, 0, 131074, 131108, 0, 262146, 196644, 1, 393218, 131108, 0, 524290, 196644, 536870912, 4, 196644, 0, 131076, 196644, 1, 262148, 131108, 0, 393220, 131108, 0, 524292, 196644, 536870912, 6, 196644, 0, 131078, 131108, 0, 262150, 65572, 1, 393222, 65572, 2, 524294, 131108, 536870913, 8, 196644, 0, 131080, 196644, 1, 262152, 65572, 1342177282, 393224, 262180, 1, 524296, 262180, 536870912, 10, 196644, 0, 131082, 131108, 0, 262154, 65572, 1342177281, 393226, 65572, 268435458, 524298, 131108, 805306369, 12, 196644, 0, 131084, 196644, 1, 262156, 131108, 0, 393228, 131108, 0, 524300, 196644, 536870912, 14, 196644, 0, 131086, 131108, 0, 262158, 196644, 1, 393230, 131108, 0, 524302, 196644, 536870912, 16, 36, 1879048193, 131088, 37, 1342177280, 262160, 196644, 1342177280, 393232, 196644, 1342177280, 524304, 36, 536870913)
[sub_resource type="TileMapPattern" id="TileMapPattern_3yn03"]
tile_data = PackedInt32Array(0, 36, 268435457, 131072, 196644, 1610612736, 262144, 196644, 1610612736, 393216, 37, 1610612736, 524288, 36, 1073741825, 655360, 36, 1610612737, 786432, 37, 1073741824, 917504, 196644, 1073741824, 1048576, 196644, 1073741824, 1179648, 36, 805306369, 2, 196644, 0, 131074, 131108, 536870912, 262146, 196644, 536870913, 393218, 131108, 536870912, 524290, 196644, 536870912, 655362, 196644, 0, 786434, 131108, 0, 917506, 196644, 1, 1048578, 131108, 0, 1179650, 196644, 536870912, 4, 196644, 0, 131076, 131108, 536870912, 262148, 131108, 536870912, 393220, 196644, 536870913, 524292, 196644, 536870912, 655364, 196644, 0, 786436, 196644, 1, 917508, 131108, 0, 1048580, 131108, 0, 1179652, 196644, 536870912, 6, 131108, 1, 131078, 65572, 536870914, 262150, 65572, 536870913, 393222, 131108, 536870912, 524294, 196644, 536870912, 655366, 196644, 0, 786438, 131108, 0, 917510, 65572, 1, 1048582, 65572, 2, 1179654, 131108, 536870913, 8, 262180, 0, 131080, 262180, 536870913, 262152, 65572, 1879048194, 393224, 196644, 536870913, 524296, 196644, 536870912, 655368, 196644, 0, 786440, 196644, 1, 917512, 65572, 1342177282, 1048584, 262180, 1, 1179656, 262180, 536870912, 10, 131108, 268435457, 131082, 65572, 805306370, 262154, 65572, 1879048193, 393226, 131108, 536870912, 524298, 196644, 536870912, 655370, 196644, 0, 786442, 131108, 0, 917514, 65572, 1342177281, 1048586, 65572, 268435458, 1179658, 131108, 805306369, 12, 196644, 0, 131084, 131108, 536870912, 262156, 131108, 536870912, 393228, 196644, 536870913, 524300, 196644, 536870912, 655372, 196644, 0, 786444, 196644, 1, 917516, 131108, 0, 1048588, 131108, 0, 1179660, 196644, 536870912, 14, 196644, 0, 131086, 131108, 536870912, 262158, 196644, 536870913, 393230, 131108, 536870912, 524302, 196644, 536870912, 655374, 196644, 0, 786446, 131108, 0, 917518, 196644, 1, 1048590, 131108, 0, 1179662, 196644, 536870912, 16, 36, 1, 131088, 196644, 1879048192, 262160, 196644, 1879048192, 393232, 37, 1879048192, 524304, 36, 1342177281, 655376, 36, 1879048193, 786448, 37, 1342177280, 917520, 196644, 1342177280, 1048592, 196644, 1342177280, 1179664, 36, 536870913)
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_7ihb1"]
texture = ExtResource("2_5i53i")
texture_region_size = Vector2i(32, 32)
0:0/0 = 0
1:0/0 = 0
2:0/0 = 0
3:0/0 = 0
4:0/0 = 0
0:1/0 = 0
1:1/0 = 0
2:1/0 = 0
3:1/0 = 0
4:1/0 = 0
0:2/0 = 0
1:2/0 = 0
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_je1ok"]
texture = ExtResource("3_ouwnc")
texture_region_size = Vector2i(32, 32)
0:0/0 = 0
[resource]
sources/36 = SubResource("TileSetAtlasSource_7ihb1")
sources/37 = SubResource("TileSetAtlasSource_je1ok")
tile_proxies/coords_level = [[0, Vector2i(0, 0)], [10, Vector2i(0, 0)], [0, Vector2i(0, 1)], [10, Vector2i(0, 1)], [0, Vector2i(1, 0)], [10, Vector2i(1, 0)], [0, Vector2i(1, 1)], [10, Vector2i(1, 1)], [1, Vector2i(0, 0)], [10, Vector2i(2, 0)], [1, Vector2i(0, 1)], [10, Vector2i(2, 1)], [1, Vector2i(1, 0)], [10, Vector2i(3, 0)], [1, Vector2i(1, 1)], [10, Vector2i(3, 1)], [2, Vector2i(0, 0)], [10, Vector2i(4, 0)], [2, Vector2i(0, 1)], [10, Vector2i(4, 1)], [2, Vector2i(1, 0)], [10, Vector2i(5, 0)], [2, Vector2i(1, 1)], [10, Vector2i(5, 1)], [3, Vector2i(0, 0)], [10, Vector2i(6, 0)], [3, Vector2i(0, 1)], [10, Vector2i(6, 1)], [3, Vector2i(1, 0)], [10, Vector2i(7, 0)], [3, Vector2i(1, 1)], [10, Vector2i(7, 1)], [4, Vector2i(0, 0)], [10, Vector2i(8, 0)], [4, Vector2i(0, 1)], [10, Vector2i(8, 1)], [4, Vector2i(1, 0)], [10, Vector2i(9, 0)], [4, Vector2i(1, 1)], [10, Vector2i(9, 1)], [5, Vector2i(0, 0)], [10, Vector2i(0, 2)], [5, Vector2i(0, 1)], [10, Vector2i(0, 3)], [5, Vector2i(1, 0)], [10, Vector2i(1, 2)], [5, Vector2i(1, 1)], [10, Vector2i(1, 3)], [6, Vector2i(0, 0)], [10, Vector2i(2, 2)], [6, Vector2i(0, 1)], [10, Vector2i(2, 3)], [6, Vector2i(1, 0)], [10, Vector2i(3, 2)], [6, Vector2i(1, 1)], [10, Vector2i(3, 3)], [8, Vector2i(0, 0)], [10, Vector2i(4, 2)], [8, Vector2i(0, 1)], [10, Vector2i(4, 3)], [8, Vector2i(1, 0)], [10, Vector2i(5, 2)], [8, Vector2i(1, 1)], [10, Vector2i(5, 3)], [9, Vector2i(0, 0)], [10, Vector2i(6, 2)], [9, Vector2i(0, 1)], [10, Vector2i(6, 3)], [9, Vector2i(1, 0)], [10, Vector2i(7, 2)], [9, Vector2i(1, 1)], [10, Vector2i(7, 3)], [11, Vector2i(0, 0)], [22, Vector2i(0, 0)], [11, Vector2i(0, 1)], [22, Vector2i(0, 1)], [11, Vector2i(1, 0)], [22, Vector2i(1, 0)], [11, Vector2i(1, 1)], [22, Vector2i(1, 1)], [12, Vector2i(0, 0)], [22, Vector2i(2, 0)], [12, Vector2i(0, 1)], [22, Vector2i(2, 1)], [12, Vector2i(1, 0)], [22, Vector2i(3, 0)], [12, Vector2i(1, 1)], [22, Vector2i(3, 1)], [13, Vector2i(0, 0)], [22, Vector2i(4, 0)], [13, Vector2i(0, 1)], [22, Vector2i(4, 1)], [13, Vector2i(1, 0)], [22, Vector2i(5, 0)], [13, Vector2i(1, 1)], [22, Vector2i(5, 1)], [14, Vector2i(0, 0)], [22, Vector2i(6, 0)], [14, Vector2i(0, 1)], [22, Vector2i(6, 1)], [14, Vector2i(1, 0)], [22, Vector2i(7, 0)], [14, Vector2i(1, 1)], [22, Vector2i(7, 1)], [15, Vector2i(0, 0)], [22, Vector2i(8, 0)], [15, Vector2i(0, 1)], [22, Vector2i(8, 1)], [15, Vector2i(1, 0)], [22, Vector2i(9, 0)], [15, Vector2i(1, 1)], [22, Vector2i(9, 1)], [16, Vector2i(0, 0)], [22, Vector2i(0, 2)], [16, Vector2i(0, 1)], [22, Vector2i(0, 3)], [16, Vector2i(1, 0)], [22, Vector2i(1, 2)], [16, Vector2i(1, 1)], [22, Vector2i(1, 3)], [17, Vector2i(0, 0)], [22, Vector2i(2, 2)], [17, Vector2i(0, 1)], [22, Vector2i(2, 3)], [17, Vector2i(1, 0)], [22, Vector2i(3, 2)], [17, Vector2i(1, 1)], [22, Vector2i(3, 3)], [18, Vector2i(0, 0)], [22, Vector2i(4, 2)], [18, Vector2i(0, 1)], [22, Vector2i(4, 3)], [18, Vector2i(1, 0)], [22, Vector2i(5, 2)], [18, Vector2i(1, 1)], [22, Vector2i(5, 3)], [19, Vector2i(0, 0)], [22, Vector2i(6, 2)], [19, Vector2i(0, 1)], [22, Vector2i(6, 3)], [19, Vector2i(1, 0)], [22, Vector2i(7, 2)], [19, Vector2i(1, 1)], [22, Vector2i(7, 3)], [20, Vector2i(0, 0)], [22, Vector2i(8, 2)], [20, Vector2i(0, 1)], [22, Vector2i(8, 3)], [20, Vector2i(1, 0)], [22, Vector2i(9, 2)], [20, Vector2i(1, 1)], [22, Vector2i(9, 3)], [21, Vector2i(0, 0)], [22, Vector2i(0, 4)], [21, Vector2i(0, 1)], [22, Vector2i(0, 5)], [21, Vector2i(1, 0)], [22, Vector2i(1, 4)], [21, Vector2i(1, 1)], [22, Vector2i(1, 5)]]
pattern_0 = SubResource("TileMapPattern_s62cf")
pattern_1 = SubResource("TileMapPattern_3yn03")

View File

@ -0,0 +1,4 @@
[gd_resource type="CompressedTexture2D" format=3 uid="uid://bthav6cae4fni"]
[resource]
load_path = "res://.godot/imported/base.png-b2215abe8c7e720db36c2fb00d361b79.ctex"

2315
Asserts/defaultTheme.tres Normal file

File diff suppressed because one or more lines are too long

1
Asserts/icon.svg Normal file
View File

@ -0,0 +1 @@
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg>

After

Width:  |  Height:  |  Size: 949 B

BIN
Asserts/pic/base.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

BIN
Asserts/pic/chessboard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
Asserts/pic/col.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

1027
Asserts/pic/col.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 58 KiB

BIN
Asserts/pic/cross.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

BIN
Asserts/pic/cross_0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

BIN
Asserts/pic/cross_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

BIN
Asserts/pic/cross_1_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

BIN
Asserts/pic/cross_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

BIN
Asserts/pic/cross_plus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

BIN
Asserts/pic/cross_set.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

BIN
Asserts/pic/eight_cross.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

BIN
Asserts/pic/row.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

67
Main.cs Normal file
View File

@ -0,0 +1,67 @@
using Godot;
using System;
public partial class Main : Node2D
{
// public void ResizeChessboardToFitScreen()
// {
// var viewportSize = GetViewportRect().Size;
// var designSize = new Vector2(800, 800); // 设计时棋盘的尺寸,这里假设为正方形
// var screenAspectRatio = viewportSize.X / viewportSize.Y;
// var boardAspectRatio = designSize.X / designSize.Y;
// // 计算保持棋盘比例的缩放因子
// float scaleFactor;
// if (screenAspectRatio > boardAspectRatio)
// {
// // 屏幕更宽,按高度缩放
// scaleFactor = viewportSize.Y / designSize.Y;
// }
// else
// {
// // 屏幕更高或相等,按宽度缩放
// scaleFactor = viewportSize.X / designSize.X;
// }
// // 应用缩放
// GetNode<Node2D>("Chessboard").Scale = new Vector2(scaleFactor, scaleFactor);
// }
// Called when the node enters the scene tree for the first time.
Global global = null;
public override void _Ready() {
// GetTree().Connect("screen_resized", ResizeChessboardToFitScreen);
// Button undo = GetNode<Button>("Undo");
// undo.Connect("pressed", (event) => {
// });
// ChessBoard board = GetNodeAndResource("res://res/ChessBoard.tscn");
// ChessBoard board1 = GetChild<ChessBoard>(0);
// board.Visible = false;
// board.Can
global = GetNode<Global>("/root/Global");
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta) {
}
private void GoToSignlePlayer() {
// global.GotoScene("res://Scenes/SinglePlayer.tscn");
global.GotoScene("res://Scenes/ChessGame.tscn");
}
private void GoToMultiPlayer() {
// global.GotoScene("res://Scenes/MultiPlayer.tscn");
global.GotoScene("res://Scenes/Menu.tscn");
}
private void GoToSetting() {
global.GotoScene("res://Scenes/Setting.tscn");
}
// private void goToMenu() {
// global.GotoScene("res://Scenes/Menu.tscn");
// }
}

51
Main.tscn Normal file
View File

@ -0,0 +1,51 @@
[gd_scene load_steps=3 format=3 uid="uid://boa4od72355o4"]
[ext_resource type="Script" path="res://Main.cs" id="1_h4cv2"]
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/defaultTheme.tres" id="2_afihr"]
[node name="Main" type="Node2D"]
script = ExtResource("1_h4cv2")
[node name="Control" type="Control" parent="."]
layout_mode = 3
anchors_preset = 0
theme = ExtResource("2_afihr")
[node name="SignlePlayer" type="Button" parent="Control"]
layout_mode = 0
offset_left = 83.0
offset_top = 671.0
offset_right = 298.0
offset_bottom = 850.0
text = "单人"
[node name="MultiPlayer" type="Button" parent="Control"]
layout_mode = 0
offset_left = 406.0
offset_top = 670.0
offset_right = 612.0
offset_bottom = 852.0
text = "多人"
[node name="Label" type="Label" parent="Control"]
layout_mode = 0
offset_left = 191.0
offset_top = 265.0
offset_right = 501.0
offset_bottom = 451.0
theme_override_font_sizes/font_size = 48
text = "中国象棋"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Setting" type="Button" parent="Control"]
layout_mode = 0
offset_left = 239.0
offset_top = 967.0
offset_right = 450.0
offset_bottom = 1150.0
text = "设置"
[connection signal="pressed" from="Control/SignlePlayer" to="." method="GoToSignlePlayer"]
[connection signal="pressed" from="Control/MultiPlayer" to="." method="GoToMultiPlayer"]
[connection signal="pressed" from="Control/Setting" to="." method="GoToSetting"]

57
Scenes/ChessGame.tscn Normal file
View File

@ -0,0 +1,57 @@
[gd_scene load_steps=4 format=3 uid="uid://g40y10iaf7qb"]
[ext_resource type="Script" path="res://Scripts/Controllers/ChessGame.cs" id="1_3x8ac"]
[ext_resource type="PackedScene" uid="uid://b1tx7v3230wab" path="res://Scenes/Entities/Chessboard.tscn" id="1_yheur"]
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/defaultTheme.tres" id="3_rcfhx"]
[node name="ChessGame" type="Node2D"]
script = ExtResource("1_3x8ac")
[node name="Chessboard" parent="." instance=ExtResource("1_yheur")]
position = Vector2(360, 660)
scale = Vector2(2.5, 2.5)
[node name="Control" type="Control" parent="."]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
theme = ExtResource("3_rcfhx")
[node name="Over" type="Button" parent="Control"]
layout_mode = 0
offset_left = 270.0
offset_top = 1105.0
offset_right = 449.0
offset_bottom = 1209.0
text = "结束回合
(提示对方结束)"
[node name="Home" type="Button" parent="Control"]
layout_mode = 0
offset_left = 55.0
offset_top = 56.0
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,18 @@
[gd_scene load_steps=4 format=4 uid="uid://b1tx7v3230wab"]
[ext_resource type="Script" path="res://Scripts/Entities/ChessBoard.cs" id="1_pjakt"]
[ext_resource type="TileSet" uid="uid://bibjj3ay65ral" path="res://Asserts/Chessboard.tres" id="1_ws3cq"]
[ext_resource type="Script" path="res://Scripts/Entities/ChessPiece.cs" id="3_26g24"]
[node name="Chessboard" type="Node2D"]
script = ExtResource("1_pjakt")
[node name="Sprite2D" type="Sprite2D" parent="."]
visible = false
script = ExtResource("3_26g24")
[node name="Layer0" type="TileMapLayer" parent="."]
use_parent_material = true
position = Vector2(-8, 184)
tile_map_data = PackedByteArray("AAAAAPv/JAAEAAEAAAD+//v/JAABAAIAAAACAPv/JAABAAIAABAAAPn/JAABAAIAAFD+//n/JAABAAEAAAACAPn/JAABAAEAAFAAAP3/JAAEAAAAACD+//3/JAACAAEAACACAP3/JAACAAEAADAEAP3/JAADAAAAACAGAP3/JAADAAAAACAIAP3/JAAAAAEAACD8//3/JAADAAAAACD6//3/JAADAAAAACD4//3/JAAAAAEAADAEAPv/JAACAAAAAAAGAPv/JAACAAAAAAAEAPn/JAACAAAAAAD8//v/JAACAAAAAAD8//n/JAACAAAAAAD6//v/JAACAAAAAAD6//f/JAACAAAAAAD+//f/JAACAAAAAAACAPf/JAACAAAAAAAGAPf/JAACAAAAAAAAAPX/JAADAAAAAAACAPX/JAADAAAAAAAEAPX/JAADAAAAAAAGAPX/JAADAAAAAAD+//X/JAADAAAAAAD8//X/JAADAAAAAAD6//X/JAADAAAAAAAIAPn/JAADAAAAAFD4//v/JAADAAAAAED4//n/JAADAAAAAED4//X/JAAAAAEAAGAIAPX/JAAAAAEAAHD6//n/JAADAAEAAAAGAPn/JAADAAEAAAAIAPv/JAADAAAAAFD8//f/JAADAAEAAAAAAPf/JAADAAEAAAAEAPf/JAADAAEAAAAIAPf/JQAAAAAAAFD4//f/JQAAAAAAAED4//P/JAAAAAEAAED6//P/JAADAAAAACD8//P/JAADAAAAACD+//P/JAADAAAAACAAAPP/JAADAAAAACACAPP/JAADAAAAACAEAPP/JAADAAAAACAGAPP/JAADAAAAACAIAPP/JAAAAAEAAFD4//H/JQAAAAAAAGD6//H/JAACAAAAACD8//H/JAADAAEAACD+//H/JAACAAAAACAAAPH/JAADAAEAACACAPH/JAACAAAAACAEAPH/JAADAAEAACAGAPH/JAACAAAAACAIAPH/JQAAAAAAAHD4/+//JAADAAAAAGD6/+//JAADAAEAACD8/+//JAACAAAAACD+/+//JAABAAEAACAAAO//JAABAAIAAHACAO//JAABAAEAAHAEAO//JAACAAAAACAGAO//JAADAAEAACAIAO//JAADAAAAAHD4/+3/JAADAAAAAGD6/+3/JAACAAAAACD8/+3/JAACAAAAACD+/+3/JAABAAIAACAAAO3/JAAEAAEAACACAO3/JAABAAIAADAEAO3/JAACAAAAACAGAO3/JAACAAAAACAIAO3/JAADAAAAAHD4/+v/JAAAAAEAABD6/+v/JAADAAAAAAD8/+v/JAADAAAAAAD+/+v/JAACAAEAAAAAAOv/JAAEAAAAAAACAOv/JAACAAEAABAEAOv/JAADAAAAAAAGAOv/JAADAAAAAAAIAOv/JAAAAAEAAAA=")
tile_set = ExtResource("1_ws3cq")

View File

@ -0,0 +1,10 @@
[gd_scene load_steps=3 format=3 uid="uid://gkbtavjf2273"]
[ext_resource type="Texture2D" uid="uid://bthav6cae4fni" path="res://Asserts/ChesspieceBase.tres" id="1_8v1j6"]
[ext_resource type="Script" path="res://Scripts/Entities/ChessPiece.cs" id="2_y54gx"]
[node name="Chesspiece" type="Node2D"]
[node name="Sprite2D" type="Sprite2D" parent="."]
texture = ExtResource("1_8v1j6")
script = ExtResource("2_y54gx")

126
Scenes/Menu.tscn Normal file
View File

@ -0,0 +1,126 @@
[gd_scene load_steps=3 format=3 uid="uid://cl8nkm6j8s8jh"]
[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]
[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="."]
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"]

3
Scenes/web.tscn Normal file
View File

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

View File

@ -0,0 +1,146 @@
using Godot;
using Godot.Collections;
public partial class ChessGame : Node2D
{
ChessBoard board;
Global global;
ConfirmationDialog dialog;
private bool isSession = false;
private Vector2 from;
private Vector2 to;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
// Init.Call();
global = GetNode<Global>("/root/Global");
board = GetNode<ChessBoard>("Chessboard");
dialog = new ConfirmationDialog {
DialogAutowrap = true,
MinSize = new Vector2I(400, 200),
Position = new Vector2I(200, 400),
};
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()) {
return;
}
isSession = true;
GD.Print("ws is connected");
global.RPClient.OnPRCSessionExit += (cmd, code) => {
GoHome();
};
// board.Set("Hello", Callable.From(() => {GD.PrintErr("hello");}));
board.board.OnMove += (sender, args) => {
Vector2 newPos = args.To;
Vector2 fromPos = args.From;
if (from.X == fromPos.X && from.Y == fromPos.Y && to.X == newPos.X && to.Y == newPos.Y) {
return;
}
from = fromPos;
to = newPos;
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}");
};
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) {
}
private void SessionMsgHandle(Dictionary msg) {
GD.PrintErr($"session msg: {msg}");
switch (msg["type"].AsString()) {
case "over":
if (global.RPClient.GetUserId() == msg["id"].AsString()) {
break;
}
dialog.Title = "Opponent Finished";
dialog.DialogText = "Turn On You\n";
dialog.Visible = true;
break;
case "move":
Vector2 _to = new(GD.StrToVar(msg["toX"].ToString()).AsInt32(),
GD.StrToVar(msg["toY"].ToString()).AsInt32());
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;
case "undo":
_Undo();
break;
case "reInit":
_ReInit();
break;
}
}
private void _Undo() {
board.playerSelf.Undo();
}
private void _ReInit() {
board.playerSelf.ReInit();
board.InitChessBoard();
}
private void BtnOver() {
GD.PrintErr($"BtnOver {isSession}");
if (isSession == false) {
return;
}
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
{"type", "over"},
{"id", global.RPClient.GetUserId()},
});
}
public void GoHome() {
if (global.RPClient.IsOnline()) {
global.RPClient.ExitServer();
}
global.GotoScene("res://Main.tscn");
}
public void Undo() {
GD.PrintErr($"Undo {isSession}");
if (isSession == false) {
_Undo();
}
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
{"type", "undo"},
});
}
public void ReInit() {
GD.PrintErr($"ReInit {isSession}");
if (isSession == false) {
_ReInit();
}
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
{"type", "reInit"},
});
}
}

136
Scripts/Controllers/Menu.cs Normal file
View File

@ -0,0 +1,136 @@
using Godot;
using Godot.Collections;
public partial class Menu : Control
{
Global global = null;
ItemList lists = null;
ConfirmationDialog dialog = null;
LineEdit nameLineEdit = null;
LineEdit urlLineEdit = null;
ColorRect colorRect = null;
Timer timer = null;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
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");
dialog = GetNode<ConfirmationDialog>("Dialogs/ConfirmationDialog");
colorRect = GetNode<ColorRect>("Server/ColorRect");
dialog.DialogAutowrap = true;
dialog.MinSize = new Vector2I(400, 200);
dialog.Canceled += () => {
if (dialog.Title == "Session Created")
global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), false);
};
dialog.Confirmed += () => {
// GD.PrintErr("confirm", dialog.GetLabel().Text);
// goToSignle();
if (dialog.Title == "Session Created")
global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), true);
};
global.RPClient.RegSessionAckCreateCallback((
sessionId,
res,
reqUserId,
reqUserName) => {
if (reqUserId != null) {
dialog.Title = "Session Created";
dialog.SetMeta("reqUserName", reqUserName);
dialog.SetMeta("reqUserId", reqUserId);
dialog.SetMeta("sessionId", sessionId);
// dialog.GetLabel==>Text = $"{sessdata["reqUserName"]}";
dialog.DialogText = $"username: {reqUserName}\n" +
$"reqUserId: {reqUserId}\n";
dialog.Visible = true;
} else {
if (res) {
global.sessionId = sessionId;
global.GotoScene("res://Scenes/ChessGame.tscn");
} else {
dialog.Title = "Failed";
dialog.DialogText = $"session create failed";
dialog.Visible = true;
}
}
return true;
});
timer = new Timer();
AddChild(timer);
timer.Connect("timeout", Callable.From(() => {
if (global.RPClient.GetIsConnected()) {
colorRect.Color = Colors.Green;
} else {
colorRect.Color = Colors.Red;
}
}));
timer.Start(1);
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta) {
}
private void OnItemSelected(int index) {
Dictionary item = lists.GetItemMetadata(index).AsGodotDictionary();
GD.Print($"Item {index} selected, {item}");
string[] strings = { item["id"].ToString() };
global.RPClient.SessionCreate(strings);
}
private void FlushData()
{
global.RPClient.RegionInspect("server", (data) => {
GD.Print(data);
lists.Clear();
foreach (Dictionary<string, string> user in data) {
string userId = user["id"].ToString();
string userName = user["name"].ToString();
if (userId == global.RPClient.GetUserId()) {
lists.SetItemDisabled(
lists.AddItem($"Name: {userName}"),
true);
continue;
}
var idx = lists.AddItem($"Name: {userName}");
lists.SetItemMetadata(idx, user);
lists.SetItemTooltip(idx, $"User ID: {userId}");
}
return true;
});
}
public void Connect()
{
GD.Print("Connect");
global.RPClient.ExitServer();
global.RPClient.ConnectToUrlEx(urlLineEdit.Text);
global.SetProcess(true);
}
public void EnterName() {
var newLine = nameLineEdit.Text;
global.RPClient.UserRename(newLine);
nameLineEdit.Text = newLine;
}
private void goToHome() {
global.RPClient.ExitServer();
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,127 @@
using Godot;
public class Player
{
private VirtualBoard board;
private SelectedPiece selectedNode;
private MoveRecords<VirtualPiece> moveRecords;
public enum PlayerType {
Human,
AI
}
public Player(VirtualBoard board, PlayerType type = PlayerType.Human)
{
this.board = 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) {
if (board.ArrPosOutOfRange(clickPos)) return;
GD.Print($"VirtualBoard {clickPos} clicked");
VirtualPiece clickChess = board.GetPiece(clickPos);
if (!selectedNode.HasSelected()) {
// Select piece
if (clickChess == null) {
// selectedNode.Clear();
return;
}
selectedNode.SetPos(clickPos);
} else if (clickChess == selectedNode.GetPiece()) {
// Unselect piece
selectedNode.Clear();
} else {
// Move piece
GD.Print("default MoveFunc Move: ", selectedNode.GetPos(), "->", clickPos);
MoveAndRecord(clickPos, selectedNode.GetPos());
}
}
public void MoveAndRecord(Vector2 toPos, Vector2 fromPos) {
GD.Print($"{fromPos} move to {toPos}");
VirtualPiece toChess = board.GetPiece(toPos);
VirtualPiece fromChess = board.GetPiece(fromPos);
fromChess?.Selected(false);
VirtualPiece NowNode;
if (toChess != null) {
NowNode = toChess;
board.RemovePiece(toPos);
} else {
NowNode = toChess;
}
moveRecords.AddRecord(NowNode, fromChess, toPos, fromPos);
board.MovePiece(fromPos, toPos);
selectedNode.Clear();
}
public void Undo() {
// ChessPiece selected = selectedNode.GetPiece();
// selected?.DeSelected();
selectedNode.Clear();
moveRecords.Undo();
}
public void ReInit() {
moveRecords.Clear();
board.Clear();
selectedNode.Clear();
// board.InitChessBoard();
}
private class SelectedPiece
{
// Called when the node enters the scene tree for the first time.
private Vector2 selectedNodePos = Vector2.Inf;
private VirtualPiece piece;
private VirtualBoard board;
public SelectedPiece(VirtualBoard board)
{
this.board = board;
}
public void Clear()
{
if (selectedNodePos != Vector2.Inf) {
selectedNodePos = Vector2.Inf;
piece.Selected(false);
}
}
public void SetPos(Vector2 pos)
{
// piece = board.GetNodeFromBoard(pos) as VirtualPiece;
selectedNodePos = pos;
piece = board.GetPiece(selectedNodePos);
piece.Selected(true);
}
public VirtualPiece GetPiece()
{
return piece;
}
public Vector2 GetPos()
{
return selectedNodePos;
}
public bool HasSelected()
{
return selectedNodePos != Vector2.Inf;
}
}
}

View File

@ -0,0 +1,138 @@
// Chessboard.cs
using Godot;
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 override void _Ready() {
board = new VirtualBoard(9, 10);
playerSelf = new Player(board);
board.OnRemove += (sender, piece) => {
if (piece.data != null) {
RemoveChild(piece.data as Node);
}
};
board.OnInsert += (sender, piece) => {
if (piece.data != null) {
AddChild(piece.data as Node);
}
};
// board.OnMove += (sender, args) => {
// // chessMoveFunc.Call(args.To, args.From);
// };
InitChessBoard();
}
public override void _Input(InputEvent @event) {
if (@event is InputEventMouseButton mouseEvent &&
mouseEvent.Pressed &&
mouseEvent.ButtonIndex == MouseButton.Left) {
// HandleMouseClick(GetGlobalTransformWithCanvas().AffineInverse() * mouseButton.Position);
HandleMouseClick(GetLocalMousePosition());
}
}
private void HandleMouseClick(Vector2 clickPosition) {
Vector2 clickBoardPos = (PosTrans.transArrToPix.AffineInverse() *
clickPosition).Round();
playerSelf.HandleBoardPosClick(clickBoardPos);
}
public void InsertNode(ChessPiece node, Vector2 arrayPos) {
AddChild(node);
VirtualPiece piece = node.GetVirtualPiece();
// 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) {
InsertNode(new ChessPiece {
PieceLabel = label,
LabelColor = new Color(color)
}, 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

@ -0,0 +1,74 @@
// Chesspiece.cs
using Godot;
public partial class ChessPiece : Sprite2D {
// 文字内容
[Export]
public string PieceLabel { get; set; } = null;
// 文字颜色(可导出以编辑器调整)
[Export]
public Color LabelColor { get; set; } = new Color("black");
private Vector2 textureSize;
private Label labelOfChessName;
private VirtualPiece piece;
public VirtualPiece GetVirtualPiece() {
return piece;
}
private void OnMove(Vector2 newPos) {
Position = PosTrans.transArrToPix * new Vector2(newPos.X, newPos.Y);
}
public void OnSelected(bool isSelected) {
if (isSelected) {
GD.Print($"{piece.Pos()} is selected");
Transform *= transToSeleted;
} else {
GD.Print($"{piece.Pos()} is deselected");
Transform *= transToSeleted.AffineInverse();
}
}
Transform2D transToSeleted = new Transform2D(
new Vector2(1.2f, 0),
new Vector2(0, 1.2f),
new Vector2(0, 0)
);
public ChessPiece() : this("", Vector2.Zero){
}
public ChessPiece(string name, Vector2 pos) {
PieceLabel = name;
piece = new VirtualPiece(name, pos);
piece.OnMove += OnMove;
piece.OnSelected += OnSelected;
piece.data = this;
}
// Called when the node enters the scene tree for the first time.
public override void _Ready() {
InitLabel();
}
private void InitLabel() {
// this.Texture.ResourcePath = "res://Asserts/ChesspieceBase.tres";
Texture ??= (Texture2D)ResourceLoader.Load("res://Asserts/ChesspieceBase.tres");
textureSize = Texture.GetSize();
Vector2 labalPosition = new(
-textureSize.X / 2,
-textureSize.Y / 2);
labelOfChessName = new Label {
Text = PieceLabel,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Modulate = LabelColor,
Position = labalPosition,
Size = textureSize,
};
// labelOfChessName.SetAnchorsPreset(Control.LayoutPreset.FullRect);
AddChild(labelOfChessName);
}
}

View File

@ -0,0 +1,20 @@
// 帅/将 (General) - 代表双方的最高统帅。
// 子类名ChessGeneral
// 仕/士 (Advisor) - 保护帅/将的近身侍卫。
// 子类名ChessAdvisor
// 相/象 (Elephant) - 行动受限,走田字格,不能过河。
// 子类名ChessElephant
// 車/车 (Chariot) - 横竖移动,威力巨大。
// 子类名ChessChariot
// 馬/马 (Horse) - 走日字形,跳跃式移动。
// 子类名ChessHorse
// 砲/炮 (Cannon) - 需要隔子才能吃子,直线移动。
// 子类名ChessCannon
// 兵/卒 (Pawn) - 最基础的棋子,过河后可横移。
// 子类名ChessPawn

85
Scripts/Global.cs Normal file
View File

@ -0,0 +1,85 @@
using Godot;
using RPPackage;
public partial class Global : Node
{
public RPClientEDWS RPClient = new();
public string sessionId;
public string URL = "wss://game.zzyxyz.com/";
public Node CurrentScene { get; set; }
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
RPClient.OnRPCError += (string errCode, string type, string cmd, string errMsg) => {
GD.PrintErr($"errCode {errCode}, type/cmd {type}/{cmd}, errMsg {errMsg}");
};
RPClient.OnClose += (string eventName, object[] args) => {
SetProcess(false);
};
RPClient.OnOpen += (string eventName, object[] args) => {
RPClient.UserInit("undefined", "godot chessboard", () => {
return RPClient.RegionAdd("server");
});
};
Viewport root = GetTree().Root;
CurrentScene = root.GetChild(root.GetChildCount() - 1);
SetProcess(false);
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
RPClient.PollEx(delta);
}
public override void _Notification(int what)
{
if (what == NotificationWMCloseRequest) {
RPClient.Close();
GetTree().Quit(); // default behavior
}
}
public delegate void ChangeSceneCallback(Node newSence);
private static ChangeSceneCallback changeSceneCallback = null;
public void GotoScene(string path, ChangeSceneCallback callback = null)
{
// This function will usually be called from a signal callback,
// or some other function from the current scene.
// Deleting the current scene at this point is
// a bad idea, because it may still be executing code.
// This will result in a crash or unexpected behavior.
// The solution is to defer the load to a later time, when
// we can be sure that no code from the current scene is running:
if (callback != null) {
changeSceneCallback = callback;
}
Callable callbackWrapper = new(null, nameof(changeSceneCallback));
CallDeferred(MethodName.DeferredGotoScene, path, callbackWrapper);
changeSceneCallback = null;
}
public void DeferredGotoScene(string path, Callable onLoaded)
{
// It is now safe to remove the current scene.
CurrentScene.Free();
// Load a new scene.
var nextScene = GD.Load<PackedScene>(path);
// Instance the new scene.
CurrentScene = nextScene.Instantiate();
if (changeSceneCallback != null) {
onLoaded.Call(CurrentScene);
}
// Add it to the active scene, as child of root.
GetTree().Root.AddChild(CurrentScene);
// Optionally, to make it compatible with the SceneTree.change_scene_to_file() API.
GetTree().CurrentScene = CurrentScene;
}
}

320
Scripts/Lib/RPClient.cs Normal file
View File

@ -0,0 +1,320 @@
using System;
using System.Threading;
using Godot;
using Godot.Collections;
namespace RPPackage {
public partial class RPClientBaseEDWS : EventDrivenWebSocket {
public delegate void RPClientEventHandler(string cmd, Dictionary data);
public delegate void RPClientErrorHandler(string errCode, string type, string cmd, string errMsg);
public event RPClientEventHandler OnRPCUser;
public event RPClientEventHandler OnRPCRegion;
public event RPClientEventHandler OnRPCSession;
public event RPClientEventHandler OnRPCMsg;
public event RPClientErrorHandler OnRPCError;
public RPClientBaseEDWS() : base() {
OnText += (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());
return;
}
switch (msg.Type) {
case "user":
OnRPCUser?.Invoke(msg.Cmd, msg.Data);
break;
case "region":
OnRPCRegion?.Invoke(msg.Cmd, msg.Data);
break;
case "session":
OnRPCSession?.Invoke(msg.Cmd, msg.Data);
break;
case "msg":
OnRPCMsg?.Invoke(msg.Cmd, msg.Data);
break;
default:
OnRPCError?.Invoke(msg.Code, "unknown", msg.Cmd, msg.Data.ToString());
break;
}
};
}
protected void MakeRPCError(string errCode, string type, string cmd, string errMsg) {
this.OnRPCError?.Invoke(errCode, type, cmd, errMsg ?? "null");
}
}
public partial class RPClientEDWS : RPClientBaseEDWS {
string userName;
string userId;
string userToken;
string regionId;
public string GetUserId() { return userId; }
public delegate void SessionRecvHandle(Dictionary msg);
public event SessionRecvHandle OnPRCSessionRecv;
public event RPClientEventHandler OnPRCSessionExit;
public RPClientEDWS() : base() {
OnRPCUser += (cmd, msg) => {
switch (cmd) {
case "init":
userId = msg["userId"].AsString();
userToken = msg["token"].AsString();
_userInitCallback?.Invoke();
break;
case "rename":
userName = msg["_"].AsString();
break;
default:
MakeRPCError("0000", "user", "unknown", msg?.ToString());
break;
}
};
OnRPCRegion += (cmd, msg) => {
switch (cmd) {
case "add":
break;
case "inspect":
// var regions = msg["_"].AsGodotArray<Dictionary>();
_regionRecvCallback?.Invoke(cmd, msg);
break;
case "list":
// var users = msg["_"].AsGodotArray<Dictionary>();
_regionRecvCallback?.Invoke(cmd, msg);
break;
default:
MakeRPCError("0000", "region", "unknown", msg?.ToString());
break;
}
};
OnRPCSession += (cmd, msg) => {
switch (cmd) {
case "sendAll":
OnPRCSessionRecv?.Invoke(msg);
break;
case "create":
break;
case "ackCreate":
// GD.PrintErr($"{cmd} {msg} {__SessionAckCreateCallback__ == null}");
_sessionAckCreateCallback?.Invoke(cmd, msg);
break;
case "exit":
OnPRCSessionExit?.Invoke(cmd, msg);
break;
default:
break;
}
};
OnRPCMsg += (cmd, msg) => {
switch(cmd) {
case "echo":
GD.Print(msg["_"].AsString());
break;
default:
break;
}
};
OnRPCError += (code, type, cmd, msg) => {
};
}
public void ClearRPCClientFunc() {
}
public bool IsOnline() {
return GetIsConnected() && userId != null;
}
public void ConnectServer(string url) {
}
public void ExitServer() {
this.SendRPMessage(new RPMessage {
Type = "user",
Cmd = "exit",
Uid = userId,
Token = userToken,
});
userId = null;
userToken = null;
this.Close();
}
public delegate bool UserInitCallback();
private UserInitCallback _userInitCallback;
public bool UserInit(string userName, string fingerPrint, UserInitCallback callback) {
if (this.GetIsConnected() == false) {
return false;
}
this.SendRPMessage(new RPMessage{
Type = "user",
Cmd = "init",
Data = new Dictionary {
{ "userName", userName },
{ "fingerPrint", fingerPrint }
}
});
_userInitCallback = null;
if (callback != null) _userInitCallback += callback;
return true;
}
public bool UserRename(string newName) {
if (this.GetIsConnected() == false) {
return false;
}
this.SendRPMessage(new RPMessage{
Type = "user",
Cmd = "rename",
Uid = userId,
Token = userToken,
Data = new Dictionary {
{ "_", newName }
}
});
return true;
}
public bool RegionAdd(string regionId) {
if (this.GetIsConnected() == false || this.userId == null) {
return false;
}
this.SendRPMessage(new RPMessage{
Type = "region",
Cmd = "add",
Uid = userId,
Token = userToken,
Data = new Dictionary {
{ "regionId", regionId }
}
});
return true;
}
public delegate bool RegionInspectCallback(
Array<Dictionary<string, string>> _
);
private RPClientEventHandler _regionRecvCallback;
public bool RegionInspect(string regionId, RegionInspectCallback callback) {
if (this.GetIsConnected() == false || this.userId == null) {
return false;
}
_regionRecvCallback = null;
_regionRecvCallback += (cmd, msg) => {
if (cmd != "inspect") {
return;
}
callback(msg["_"].AsGodotArray<Dictionary<string, string>>());
};
this.SendRPMessage(new RPMessage{
Type = "region",
Cmd = "inspect",
Uid = userId,
Token = userToken,
Data = new Dictionary {
{ "regionId", regionId }
}
});
return true;
}
public delegate bool SessionAckCreateCallback(
string sessionId,
bool res,
string reqUserId,
string reqUserName
);
private RPClientEventHandler _sessionAckCreateCallback;
public void RegSessionAckCreateCallback(SessionAckCreateCallback recvCallback) {
_sessionAckCreateCallback = null;
_sessionAckCreateCallback += (cmd, msg) => {
string sessionId = msg["sessionId"].AsString();
bool res = msg.ContainsKey("res") && msg["res"].AsBool();
string reqUserId = msg.ContainsKey("reqUserId") ? msg["reqUserId"].AsString() : null;
string reqUserName = msg.ContainsKey("reqUserName") ? msg["reqUserName"].AsString() : null;
recvCallback(sessionId, res, reqUserId, reqUserName);
};
}
public bool SessionCreate(string[] usersId) {
if (this.GetIsConnected() == false || this.userId == null) {
return false;
}
this.SendRPMessage(new RPMessage {
Type = "session",
Cmd = "create",
Uid = userId,
Token = userToken,
Data = new Dictionary {
{ "_", usersId }
}
});
return true;
}
public bool SessionAckCreate(string sessionId, bool response)
{
if (this.GetIsConnected() == false || this.userId == null) {
return false;
}
// 根据响应情况发送确认消息给服务器
string code = response ? "0000" : "0001";
this.SendRPMessage(new RPMessage {
Type = "session",
Cmd = "ackCreate",
Uid = userId,
Token = userToken,
Code = code,
Data = new Dictionary {
{ "sessionId", sessionId },
{ "res", response }
}
});
return true;
}
public bool SendSessionToAll(string sessionId, Variant data) {
if (this.GetIsConnected() == false || this.userId == null || sessionId == null) {
return false;
}
this.SendRPMessage(new RPMessage{
Type = "session",
Cmd = "sendAll",
Uid = userId,
Token = userToken,
Data = new Dictionary {
{ "sessionId", sessionId },
{ "msg", data },
}
});
return true;
}
// ws.OnOpen += (eventName, args) => {
// ws.SendRPMessage(new RPMessage{
// Type = "user",
// Cmd = "tmp",
// });
// };
// ws.OnError += (eventName, args) => {
// GD.PrintErr(args);
// // SetProcess(false);
// };
// ws.OnClose += (eventName, args) => {
// // GD.Print("close");
// SetProcess(false);
// };
}
}

45
Scripts/Lib/RPHelper.cs Normal file
View File

@ -0,0 +1,45 @@
using Godot;
using Godot.Collections;
namespace RPPackage {
public static class RPHelper
{
public static Dictionary SerializeRPMessage(RPMessage message)
{
return message.ToDictionary();
}
public static RPMessage DeserializeRPMessage(Dictionary data)
{
return new RPMessage
{
Type = data.ContainsKey("type") ? (string)data["type"] : null,
Cmd = data.ContainsKey("cmd") ? (string)data["cmd"] : null,
Code = data.ContainsKey("code") ? (string)data["code"] : null,
Uid = data.ContainsKey("uid") ? (string)data["uid"] : null,
Token = data.ContainsKey("token") ? (string)data["token"] : null,
Data = data.ContainsKey("data") ? data["data"].AsGodotDictionary() : null,
};
}
// 假设你有WebSocket通信的实现这里仅展示如何使用上述方法
public static void SendRPMessage(this EventDrivenWebSocket ws, RPMessage message)
{
ws.SendJsonEx(RPHelper.SerializeRPMessage(message));
}
public static RPMessage HandleIncomingMessage(string jsonMessage)
{
var dataDict = Json.ParseString(jsonMessage).AsGodotDictionary();
if (dataDict != null)
{
return RPHelper.DeserializeRPMessage(dataDict);
}
else
{
GD.PrintErr("Failed to parse incoming message.");
return null;
}
}
}
}

33
Scripts/Lib/RPMessage.cs Normal file
View File

@ -0,0 +1,33 @@
using Godot;
using Godot.Collections;
namespace RPPackage {
public class RPMessage
{
public string Type { get; set; }
public string Cmd { get; set; }
public Dictionary Data { get; set; }
public string Uid { get; set; }
public string Token { get; set; }
public string Code { get; set; }
public Dictionary ToDictionary()
{
var dict = new Dictionary();
if (Type != null)
dict.Add("type", Type);
if (Cmd != null)
dict.Add("cmd", Cmd);
if (Data != null)
dict.Add("data", Data);
if (Uid != null)
dict.Add("uid", Uid);
if (Token != null)
dict.Add("token", Token);
if (Code != null)
dict.Add("code", Code);
return dict;
}
}
}

114
Scripts/Lib/gdws.cs Normal file
View File

@ -0,0 +1,114 @@
using Godot;
using Godot.Collections;
public partial class EventDrivenWebSocket : WebSocketPeer {
public delegate void WebSocketEventHandler(string eventName, params object[] args);
public delegate void WSBinMsgEventHandler(byte[] args);
public delegate void WSMsgEventHandler(string args);
public event WebSocketEventHandler OnOpen;
public event WSBinMsgEventHandler OnMessage;
public event WSMsgEventHandler OnText;
public event WSBinMsgEventHandler OnBinary;
public event WebSocketEventHandler OnClose;
public event WebSocketEventHandler OnError;
private bool isConnected = false;
private bool isCloseEventFired = false;
private double connectingTime = double.NegativeInfinity;
public EventDrivenWebSocket() : base() {
isConnected = false;
}
public bool GetIsConnected() {
return isConnected;
}
public void PollEx(double delta) {
base.Poll();
CheckAndDispatchEvents(delta);
}
public void ConnectToUrlEx(string url, double delayTime = 3,
TlsOptions tlsClientOptions = null) {
if (connectingTime >= 0) {
return;
}
Error err = ConnectToUrl(url, tlsClientOptions);
if (err != Error.Ok) {
OnError?.Invoke("error", err);
}
connectingTime = delayTime;
}
protected void CheckAndDispatchEvents(double delta) {
var state = GetReadyState();
switch (state) {
case State.Open when !isConnected:
isConnected = true;
OnOpen?.Invoke("open", null);
break;
case State.Open:
while (GetAvailablePacketCount() > 0) {
byte[] packet = GetPacket();
OnMessage?.Invoke(packet);
if (WasStringPacket()) {
OnText?.Invoke(packet.GetStringFromUtf8());
} else {
OnBinary?.Invoke(packet);
}
}
break;
case State.Closed:
connectingTime = double.NegativeInfinity;
OnClose?.Invoke("closed", GetCloseCode(), GetCloseReason());
isConnected = false;
break;
case State.Closing:
// OnClose?.Invoke("closing");
break;
case State.Connecting:
if (connectingTime >= 0) {
connectingTime -= delta;
} else if (connectingTime != double.NegativeInfinity){
connectingTime = double.NegativeInfinity;
Close();
OnError?.Invoke("connectTimeOut", Error.Timeout);
}
break;
default:
// 可以在这里处理其他状态或错误
OnError?.Invoke("error", "Unknown WebSocket state.");
break;
}
}
public void SendBinaryEx(byte[] data) {
SendEx(data);
}
public void SendJsonEx(Dictionary msg) {
SendTextEx(Json.Stringify(msg));
}
public Error SendTextEx(string message) {
if (isConnected) {
return SendText(message);
} else {
OnError?.Invoke("error", "Attempt to send on a closed connection.");
return Error.ConnectionError;
}
}
public Error SendEx(byte[] message, WriteMode writeMode = WriteMode.Binary) {
if (isConnected) {
return Send(message, writeMode);
} else {
OnError?.Invoke("error", "Attempt to send on a closed connection.");
return Error.ConnectionError;
}
}
}

View File

@ -0,0 +1,59 @@
// using System.Numerics;
using Godot;
using System.Collections.Generic;
using System;
public class MoveRecords<T> {
private readonly LinkedList<MoveRecord> records = new LinkedList<MoveRecord>(); // 使用队列替换栈
private readonly int maxRecords; // 记录上限
private Action<T, T, Vector2, Vector2> onAddRecordCallback; // 添加记录时的回调
private Action<T, T, Vector2, Vector2> onUndoRecordCallback; // 撤销记录时的回调
public MoveRecords(
Action<T, T, Vector2, Vector2> onAddRecordCallback = null,
Action<T, T, Vector2, Vector2> onUndoRecordCallback = null,
int maxRecords = 32) {
this.maxRecords = maxRecords;
this.onAddRecordCallback = onAddRecordCallback;
this.onUndoRecordCallback = onUndoRecordCallback;
}
public void AddRecord(T newNode, T oldNode, Vector2 newPos, Vector2 oldPos) {
// 达到记录上限时,移除最远的记录(队首元素)
if (records.Count >= maxRecords) {
records.RemoveFirst();
}
var record = new MoveRecord(newNode, oldNode, newPos, oldPos);
// 触发添加记录的回调
onAddRecordCallback?.Invoke(newNode, oldNode, newPos, oldPos);
// GD.Print("In func Addrecord: ", record.NewNode, "->", record.OldNode, ":", record.NewPos, "->", record.OldPos);
records.AddLast(record); // 将新记录加入队尾
}
public void Undo() {
if (records.Count == 0) return;
MoveRecord record = records.Last.Value; // 移除并获取队首的记录以执行撤销操作
records.RemoveLast();
// 触发撤销记录的回调
onUndoRecordCallback?.Invoke(record.NewNode, record.OldNode, record.NewPos, record.OldPos);
}
public void Clear() {
records.Clear();
}
private class MoveRecord {
public T NewNode { get; }
public T OldNode { get; }
public Vector2 NewPos { get; }
public Vector2 OldPos { get; }
public MoveRecord(T newNode, T oldNode, Vector2 newPos, Vector2 oldPos) {
NewNode = newNode;
OldNode = oldNode;
OldPos = oldPos;
NewPos = newPos;
}
}
}

View File

@ -0,0 +1,10 @@
using Godot;
public static class PosTrans {
private static readonly int pixGripSize = 32;
public static Transform2D transArrToPix = new(
new Vector2(pixGripSize, 0),
new Vector2(0, pixGripSize),
new Vector2(-4, -4.5f) * pixGripSize
);
}

View File

@ -0,0 +1,101 @@
using System;
// using System.Numerics;
// using System.Transactions;
using Godot;
public class VirtualBoard {
private readonly int Rows;
private readonly int Cols;
private readonly VirtualPiece[,] pieces;
public class SetPiecePosEventArgs : EventArgs
{
public VirtualPiece OldPiece { get; set; }
public VirtualPiece NewPiece { get; set; }
}
public class MoveEventArgs : EventArgs
{
public Vector2 From { get; set; }
public Vector2 To { get; set; }
}
public event EventHandler<SetPiecePosEventArgs> OnSetPiecePos;
public event EventHandler<VirtualPiece> OnInsert;
public event EventHandler<VirtualPiece> OnRemove;
public event EventHandler<MoveEventArgs> OnMove;
public VirtualBoard(int rows, int cols) {
this.Rows = rows;
this.Cols = cols;
pieces = new VirtualPiece[rows, cols];
}
public bool ArrPosOutOfRange(Vector2 arrayPos) {
return arrayPos.X < 0 || arrayPos.X >= Rows || arrayPos.Y < 0 || arrayPos.Y >= Cols;
}
public VirtualPiece GetPiece(Vector2 arrayPos) {
if (ArrPosOutOfRange(arrayPos)) return null;
return pieces[(int)arrayPos.X, (int)arrayPos.Y];
}
public VirtualPiece SetPiecePos(VirtualPiece piece, Vector2 arrayPos) {
if (ArrPosOutOfRange(arrayPos)) return null;
VirtualPiece oldPiece = pieces[(int)arrayPos.X, (int)arrayPos.Y];
pieces[(int)arrayPos.X, (int)arrayPos.Y] = piece;
OnSetPiecePos?.Invoke(this, new SetPiecePosEventArgs { OldPiece = oldPiece, NewPiece = piece });
piece?.Move(arrayPos);
return oldPiece;
}
public bool InsertPiece(VirtualPiece piece, Vector2 arrayPos) {
if (GetPiece(arrayPos) != null) {
return false;
}
OnInsert?.Invoke(this, piece);
SetPiecePos(piece, arrayPos);
return true;
}
public bool MovePiece(Vector2 from, Vector2 to) {
if (ArrPosOutOfRange(to) || ArrPosOutOfRange(from)) {
return false;
}
if (GetPiece(to) != null) {
return false;
}
OnMove?.Invoke(this, new MoveEventArgs { From = from, To = to });
SetPiecePos(SetPiecePos(null, from), to);
return true;
}
public bool RemovePiece(Vector2 pos) {
VirtualPiece piece = GetPiece(pos);
if (piece == null) {
return false;
}
OnRemove?.Invoke(this, piece);
return SetPiecePos(null, pos) != null;
}
public void Clear() {
for (int i = 0; i < Rows; i++) {
for (int j = 0; j < Cols; j++) {
RemovePiece(new Vector2(i, j));
}
}
}
}

View File

@ -0,0 +1,40 @@
// using System.Numerics;
using Godot;
using System;
public class VirtualPiece {
private Vector2 pos; // 注意这个坐标的非像素坐标而是棋盘坐标
private string name;
private bool isSelected;
public object data;
public event Action<Vector2> OnMove;
public event Action<bool> OnSelected;
public void Move(Vector2 pos) {
this.pos = pos;
OnMove?.Invoke(pos);
}
public Vector2 Pos() {
return pos;
}
public void Selected(bool isSelected) {
if (this.isSelected != isSelected) {
OnSelected?.Invoke(isSelected);
this.isSelected = isSelected;
}
}
public bool IsSelected() {
return isSelected;
}
public VirtualPiece(string name = "", Vector2 pos = new Vector2()) {
this.name = name;
this.pos = pos;
}
}

1
icon.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 994 B

34
project.godot Normal file
View File

@ -0,0 +1,34 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="Chinese_Chess"
run/main_scene="res://Main.tscn"
config/features=PackedStringArray("4.3", "C#", "Mobile")
config/icon="res://icon.svg"
[autoload]
Global="*res://Scripts/Global.cs"
[display]
window/size/viewport_width=720
window/size/viewport_height=1280
[dotnet]
project/assembly_name="Chinese_Chess"
[rendering]
renderer/rendering_method="mobile"
textures/vram_compression/import_etc2_astc=true