Compare commits
10 Commits
d1dea9a89d
...
13450ea09a
Author | SHA1 | Date | |
---|---|---|---|
13450ea09a | |||
3fa39fc71e | |||
b27abb55a2 | |||
e16f76e11f | |||
327c2df94d | |||
9c619784af | |||
8ee9732a6f | |||
6daf09b300 | |||
d6cbb5e11d | |||
d323a0bee7 |
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Normalize EOL for all files that Git considers text files.
|
||||
* text=auto eol=lf
|
41
.gitignore
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
# 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/
|
||||
android/
|
||||
Bin/
|
||||
bin/
|
||||
*.aseprite
|
||||
*.csproj.old*
|
||||
*.sln
|
||||
*.error
|
||||
*.key*
|
||||
.editorconfig
|
||||
|
||||
# cs project files
|
||||
!*.csproj
|
||||
|
||||
# Test files
|
||||
Test/bin
|
||||
Test/obj
|
||||
|
||||
# temp ignores
|
||||
Lang/*
|
||||
*.zip
|
38
Asserts/Chessboard.tres
Normal 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")
|
4
Asserts/ChesspieceBase.tres
Normal file
@ -0,0 +1,4 @@
|
||||
[gd_resource type="CompressedTexture2D" format=3 uid="uid://bthav6cae4fni"]
|
||||
|
||||
[resource]
|
||||
load_path = "res://.godot/imported/base.png-b2215abe8c7e720db36c2fb00d361b79.ctex"
|
2603
Asserts/GameTheme.tres
Normal file
1
Asserts/icon.svg
Normal 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
After Width: | Height: | Size: 317 B |
BIN
Asserts/pic/chessboard.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
Asserts/pic/col.png
Normal file
After Width: | Height: | Size: 135 B |
1027
Asserts/pic/col.svg
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
Asserts/pic/cross.png
Normal file
After Width: | Height: | Size: 154 B |
BIN
Asserts/pic/cross_0.png
Normal file
After Width: | Height: | Size: 165 B |
BIN
Asserts/pic/cross_1.png
Normal file
After Width: | Height: | Size: 150 B |
BIN
Asserts/pic/cross_1_2.png
Normal file
After Width: | Height: | Size: 156 B |
BIN
Asserts/pic/cross_2.png
Normal file
After Width: | Height: | Size: 150 B |
BIN
Asserts/pic/cross_plus.png
Normal file
After Width: | Height: | Size: 220 B |
BIN
Asserts/pic/cross_plus_1.png
Normal file
After Width: | Height: | Size: 208 B |
BIN
Asserts/pic/cross_set.png
Normal file
After Width: | Height: | Size: 206 B |
BIN
Asserts/pic/cross_set_plus.png
Normal file
After Width: | Height: | Size: 177 B |
BIN
Asserts/pic/eight_cross.png
Normal file
After Width: | Height: | Size: 309 B |
BIN
Asserts/pic/row.png
Normal file
After Width: | Height: | Size: 137 B |
24
ChessGame.csproj
Normal file
@ -0,0 +1,24 @@
|
||||
<Project Sdk="Godot.NET.Sdk/4.4.0">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- <TreatWarningsAsErrors>true</TreatWarningsAsErrors> -->
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Test\**\*" />
|
||||
<Compile Remove="android\**\*" />
|
||||
<Compile Remove="Protos\**\*" />
|
||||
<!-- <Protobuf Include="Protos\chess.proto" GrpcServices="Client" /> -->
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.30.2" />
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.70.0" />
|
||||
<PackageReference Include="Grpc.Tools" Version="2.71.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="KeraLua" Version="1.4.5" />
|
||||
<PackageReference Include="NLua" Version="1.7.5" />
|
||||
</ItemGroup>
|
||||
</Project>
|
32
Main.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using Godot;
|
||||
|
||||
public partial class Main : Node2D {
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
GlobalManager global = null!;
|
||||
public override void _Ready() {
|
||||
// GetTree().Connect("screen_resized", ResizeChessboardToFitScreen);
|
||||
global = GlobalManager.Instance;
|
||||
global.GlobalTheme = GetChild<Control>(GetChildCount() - 1).Theme;
|
||||
global.GlobalThemeConfigFlush();
|
||||
}
|
||||
|
||||
// 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/ChessGame.tscn");
|
||||
}
|
||||
|
||||
private void GoToMultiPlayer() {
|
||||
global?.GotoScene("res://Scenes/GameLobby.tscn");
|
||||
}
|
||||
|
||||
private void GoToSetting() {
|
||||
global?.GotoScene("res://Scenes/Setting.tscn");
|
||||
}
|
||||
|
||||
private void GotoMods() {
|
||||
global?.GotoScene("res://Scenes/Mods.tscn");
|
||||
}
|
||||
}
|
1
Main.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://kdxc7ummin4b
|
59
Main.tscn
Normal file
@ -0,0 +1,59 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://boa4od72355o4"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://kdxc7ummin4b" path="res://Main.cs" id="1_h4cv2"]
|
||||
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/GameTheme.tres" id="2_afihr"]
|
||||
|
||||
[node name="Main" type="Node2D"]
|
||||
script = ExtResource("1_h4cv2")
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="."]
|
||||
offset_right = 720.0
|
||||
offset_bottom = 1280.0
|
||||
theme = ExtResource("2_afihr")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
|
||||
custom_minimum_size = Vector2(720, 720)
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 30
|
||||
|
||||
[node name="Label" type="Label" parent="CenterContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 6
|
||||
theme_override_font_sizes/font_size = 48
|
||||
text = "KEY_ChessGame"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="CenterContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 30
|
||||
theme_override_constants/margin_right = 30
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/VBoxContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="SignlePlayer" type="Button" parent="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "KEY_SinglePlayer"
|
||||
|
||||
[node name="MultiPlayer" type="Button" parent="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "KEY_MultiPlayer"
|
||||
|
||||
[node name="Setting" type="Button" parent="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "KEY_Setting"
|
||||
|
||||
[node name="Mod" type="Button" parent="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "KEY_Mode"
|
||||
|
||||
[connection signal="pressed" from="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/SignlePlayer" to="." method="GoToSignlePlayer"]
|
||||
[connection signal="pressed" from="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/MultiPlayer" to="." method="GoToMultiPlayer"]
|
||||
[connection signal="pressed" from="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/Setting" to="." method="GoToSetting"]
|
||||
[connection signal="pressed" from="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/Mod" to="." method="GotoMods"]
|
110
Scenes/ChessGame.tscn
Normal file
@ -0,0 +1,110 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://g40y10iaf7qb"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cqgctouhh8qok" 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/GameTheme.tres" id="3_rcfhx"]
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("3_rcfhx")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
offset_bottom = 133.0
|
||||
grow_horizontal = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/MarginContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Home" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer/MarginContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "KEY_BackHome"
|
||||
|
||||
[node name="MarginContainer2" type="MarginContainer" parent="VBoxContainer/MarginContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Undo" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer/MarginContainer2"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 4
|
||||
text = "KEY_GameUndo"
|
||||
|
||||
[node name="MarginContainer3" type="MarginContainer" parent="VBoxContainer/MarginContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="ReInit" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer/MarginContainer3"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "KEY_GameReInit"
|
||||
|
||||
[node name="MarginContainer3" type="MarginContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HFlowContainer" type="HFlowContainer" parent="VBoxContainer/MarginContainer3"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/MarginContainer3/HFlowContainer"]
|
||||
layout_mode = 2
|
||||
text = "KEY_Content_YouAre"
|
||||
|
||||
[node name="LineEdit_YouAre" type="LineEdit" parent="VBoxContainer/MarginContainer3/HFlowContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
editable = false
|
||||
|
||||
[node name="Label2" type="Label" parent="VBoxContainer/MarginContainer3/HFlowContainer"]
|
||||
layout_mode = 2
|
||||
text = "KEY_Content_TurnOn"
|
||||
|
||||
[node name="LineEdit_TurnSide" type="LineEdit" parent="VBoxContainer/MarginContainer3/HFlowContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
editable = false
|
||||
|
||||
[node name="MarginContainer2" type="MarginContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 12
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -114.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
|
||||
[node name="Over" type="Button" parent="MarginContainer2"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "KEY_OverThisTurn"
|
||||
|
||||
[node name="ChessGame" type="Node2D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
script = ExtResource("1_3x8ac")
|
||||
|
||||
[node name="Chessboard" parent="ChessGame" instance=ExtResource("1_yheur")]
|
||||
unique_name_in_owner = true
|
||||
position = Vector2(360, 650)
|
||||
scale = Vector2(2.5, 2.5)
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/MarginContainer/HBoxContainer/MarginContainer/Home" to="ChessGame" method="GoHome"]
|
||||
[connection signal="pressed" from="VBoxContainer/MarginContainer/HBoxContainer/MarginContainer2/Undo" to="ChessGame" method="Undo"]
|
||||
[connection signal="pressed" from="VBoxContainer/MarginContainer/HBoxContainer/MarginContainer3/ReInit" to="ChessGame" method="ReInit"]
|
||||
[connection signal="pressed" from="MarginContainer2/Over" to="ChessGame" method="BtnOver"]
|
22
Scenes/Entities/Chessboard.tscn
Normal file
@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=4 format=4 uid="uid://b1tx7v3230wab"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dmc012tt32dkl" 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" uid="uid://c8eafskfpuesm" 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="."]
|
||||
show_behind_parent = 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")
|
||||
collision_enabled = false
|
||||
collision_visibility_mode = 2
|
||||
navigation_enabled = false
|
||||
navigation_visibility_mode = 2
|
10
Scenes/Entities/Chesspiece.tscn
Normal 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" uid="uid://c8eafskfpuesm" 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")
|
23
Scenes/Entities/ServerStatus.tscn
Normal file
@ -0,0 +1,23 @@
|
||||
[gd_scene format=3 uid="uid://pc83bstfltn"]
|
||||
|
||||
[node name="ServerStatus" type="HBoxContainer"]
|
||||
anchors_preset = -1
|
||||
anchor_right = 0.176389
|
||||
anchor_bottom = 0.0179687
|
||||
offset_right = -126.0
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
text = "KEY_ServerConnectStatus"
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="."]
|
||||
custom_minimum_size = Vector2(15, 15)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TextureProgressBar" type="TextureProgressBar" parent="."]
|
||||
layout_mode = 2
|
78
Scenes/GameLobby.tscn
Normal file
@ -0,0 +1,78 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://00jxjgnmfbn7"]
|
||||
|
||||
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/GameTheme.tres" id="1_ge0tq"]
|
||||
[ext_resource type="Script" uid="uid://cn273e4u256r" path="res://Scripts/Controllers/GameLobby.cs" id="2_blx46"]
|
||||
|
||||
[node name="GameLobby" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("1_ge0tq")
|
||||
script = ExtResource("2_blx46")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Button" type="Button" parent="MarginContainer/VBoxContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
text = "KEY_BackHome"
|
||||
|
||||
[node name="MarginContainer2" type="HFlowContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/MarginContainer2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/MarginContainer2/MarginContainer"]
|
||||
layout_mode = 2
|
||||
text = "KEY_ServerConnectStatus"
|
||||
|
||||
[node name="MarginContainer2" type="MarginContainer" parent="MarginContainer/VBoxContainer/MarginContainer2"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="MarginContainer/VBoxContainer/MarginContainer2/MarginContainer2"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MarginContainer3" type="MarginContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ItemList_Users" type="ItemList" parent="MarginContainer/VBoxContainer/MarginContainer3"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Dialogs" type="Control" parent="."]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
|
||||
[node name="AcceptDialog" type="AcceptDialog" parent="Dialogs"]
|
||||
auto_translate_mode = 1
|
||||
initial_position = 2
|
||||
size = Vector2i(100, 118)
|
||||
|
||||
[node name="PopupMenu" type="PopupMenu" parent="Dialogs"]
|
||||
auto_translate_mode = 1
|
||||
|
||||
[node name="ConfirmationDialog" type="ConfirmationDialog" parent="Dialogs"]
|
||||
auto_translate_mode = 1
|
||||
initial_position = 2
|
||||
size = Vector2i(200, 118)
|
||||
|
||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/MarginContainer/Button" to="." method="OnBack"]
|
||||
[connection signal="item_activated" from="MarginContainer/VBoxContainer/MarginContainer3/ItemList_Users" to="." method="OnItemSelected"]
|
60
Scenes/Mods.tscn
Normal file
@ -0,0 +1,60 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://c2ov83uk7r6rq"]
|
||||
|
||||
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/GameTheme.tres" id="1_mhtia"]
|
||||
[ext_resource type="Script" uid="uid://c8t8d8e7inajy" path="res://Scripts/Controllers/Mods.cs" id="1_mnyng"]
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("1_mhtia")
|
||||
theme_override_constants/margin_left = 30
|
||||
theme_override_constants/margin_top = 30
|
||||
theme_override_constants/margin_right = 30
|
||||
theme_override_constants/margin_bottom = 30
|
||||
script = ExtResource("1_mnyng")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Button" type="Button" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "KEY_BackHome"
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="CheckButton" type="CheckButton" parent="VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "KEY_EnableMod"
|
||||
|
||||
[node name="Button2" type="Button" parent="VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "KEY_ReloadMod"
|
||||
|
||||
[node name="Button2" type="Button" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "KEY_OpenModDir"
|
||||
|
||||
[node name="VScrollBar" type="VScrollBar" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 1
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ItemList" type="ItemList" parent="VBoxContainer/VScrollBar"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/Button" to="." method="OnBack"]
|
||||
[connection signal="toggled" from="VBoxContainer/HBoxContainer/CheckButton" to="." method="OnEnableMods"]
|
||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/Button2" to="." method="OnReSearchMods"]
|
||||
[connection signal="pressed" from="VBoxContainer/Button2" to="." method="OnOpenModFileDir"]
|
211
Scenes/Setting.tscn
Normal file
@ -0,0 +1,211 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://c6gxufppw1fu3"]
|
||||
|
||||
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/GameTheme.tres" id="1_6yfoi"]
|
||||
[ext_resource type="Script" uid="uid://71ril3nh84rw" path="res://Scripts/Controllers/Setting.cs" id="1_xbvb3"]
|
||||
[ext_resource type="PackedScene" uid="uid://pc83bstfltn" path="res://Scenes/Entities/ServerStatus.tscn" id="3_e50hu"]
|
||||
|
||||
[sub_resource type="ButtonGroup" id="ButtonGroup_efio3"]
|
||||
|
||||
[node name="Setting" type="MarginContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("1_6yfoi")
|
||||
script = ExtResource("1_xbvb3")
|
||||
|
||||
[node name="BoxContainer" type="VBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Back" type="Button" parent="BoxContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
text = "KEY_BackHome"
|
||||
|
||||
[node name="MarginContainer7" type="MarginContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Button" type="Button" parent="BoxContainer/MarginContainer7"]
|
||||
layout_mode = 2
|
||||
text = "KEY_SaveConfigFile"
|
||||
|
||||
[node name="MarginContainer9" type="MarginContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Button" type="Button" parent="BoxContainer/MarginContainer9"]
|
||||
layout_mode = 2
|
||||
text = "KEY_GetConfigDir"
|
||||
|
||||
[node name="MarginContainer2" type="MarginContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Server" type="HFlowContainer" parent="BoxContainer/MarginContainer2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="BoxContainer/MarginContainer2/Server"]
|
||||
layout_mode = 2
|
||||
text = "KEY_ServerIP"
|
||||
|
||||
[node name="LineEdit_ServerIP" type="LineEdit" parent="BoxContainer/MarginContainer2/Server"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MarginContainer3" type="MarginContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Name" type="HFlowContainer" parent="BoxContainer/MarginContainer3"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="BoxContainer/MarginContainer3/Name"]
|
||||
layout_mode = 2
|
||||
text = "KEY_UserName"
|
||||
|
||||
[node name="LineEdit_UserName" type="LineEdit" parent="BoxContainer/MarginContainer3/Name"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Button" type="Button" parent="BoxContainer/MarginContainer3/Name"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "OK"
|
||||
|
||||
[node name="MarginContainer4" type="MarginContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HFlowContainer" type="HFlowContainer" parent="BoxContainer/MarginContainer4"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ServerStatus" parent="BoxContainer/MarginContainer4/HFlowContainer" instance=ExtResource("3_e50hu")]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="CheckButton" type="CheckButton" parent="BoxContainer/MarginContainer4/HFlowContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "Server Start"
|
||||
|
||||
[node name="MarginContainer5" type="MarginContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HFlowContainer" parent="BoxContainer/MarginContainer5"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="BoxContainer/MarginContainer5/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "KEY_GlobalFontSize"
|
||||
|
||||
[node name="FontSize" type="LineEdit" parent="BoxContainer/MarginContainer5/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
editable = false
|
||||
|
||||
[node name="MarginContainer6" type="MarginContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="FontSizeBar" type="HSlider" parent="BoxContainer/MarginContainer6"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 4
|
||||
min_value = 10.0
|
||||
max_value = 40.0
|
||||
value = 10.0
|
||||
|
||||
[node name="HBoxContainer2" type="HFlowContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="BoxContainer/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Button" type="Button" parent="BoxContainer/HBoxContainer2/MarginContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
toggle_mode = true
|
||||
button_group = SubResource("ButtonGroup_efio3")
|
||||
text = "简体中文"
|
||||
|
||||
[node name="MarginContainer2" type="MarginContainer" parent="BoxContainer/HBoxContainer2"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Button2" type="Button" parent="BoxContainer/HBoxContainer2/MarginContainer2"]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
button_group = SubResource("ButtonGroup_efio3")
|
||||
text = "English"
|
||||
|
||||
[node name="HBoxContainer" type="HFlowContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="BoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Button" type="Button" parent="BoxContainer/HBoxContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
disabled = true
|
||||
text = "Clear Config"
|
||||
|
||||
[node name="MarginContainer2" type="MarginContainer" parent="BoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Button2" type="Button" parent="BoxContainer/HBoxContainer/MarginContainer2"]
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "Clear User Data"
|
||||
|
||||
[node name="HFlowContainer" type="HFlowContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Button" type="Button" parent="BoxContainer/HFlowContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
disabled = true
|
||||
text = "GetCacheDir"
|
||||
|
||||
[node name="Button2" type="Button" parent="BoxContainer/HFlowContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
disabled = true
|
||||
text = "GetConfigDir"
|
||||
|
||||
[node name="Button3" type="Button" parent="BoxContainer/HFlowContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
disabled = true
|
||||
text = "GetDataDir"
|
||||
|
||||
[node name="Button4" type="Button" parent="BoxContainer/HFlowContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
disabled = true
|
||||
text = "GetUserDataDir"
|
||||
|
||||
[node name="MarginContainer8" type="MarginContainer" parent="BoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ColorPickerButton" type="ColorPickerButton" parent="BoxContainer/MarginContainer8"]
|
||||
layout_mode = 2
|
||||
text = "Trace Color"
|
||||
|
||||
[connection signal="pressed" from="BoxContainer/MarginContainer/Back" to="." method="OnBack"]
|
||||
[connection signal="pressed" from="BoxContainer/MarginContainer7/Button" to="." method="OnSave"]
|
||||
[connection signal="pressed" from="BoxContainer/MarginContainer9/Button" to="." method="OnGetSettingsFile"]
|
||||
[connection signal="text_changed" from="BoxContainer/MarginContainer2/Server/LineEdit_ServerIP" to="." method="OnServerUrlChanged"]
|
||||
[connection signal="text_changed" from="BoxContainer/MarginContainer3/Name/LineEdit_UserName" to="." method="OnNameChanged"]
|
||||
[connection signal="value_changed" from="BoxContainer/MarginContainer6/FontSizeBar" to="." method="OnFontSizeChanged"]
|
||||
[connection signal="toggled" from="BoxContainer/HBoxContainer2/MarginContainer/Button" to="." method="ChangeLangZHCN"]
|
||||
[connection signal="toggled" from="BoxContainer/HBoxContainer2/MarginContainer2/Button2" to="." method="ChangeLangEN"]
|
||||
[connection signal="pressed" from="BoxContainer/HBoxContainer/MarginContainer2/Button2" to="." method="OnClearUserData"]
|
||||
[connection signal="pressed" from="BoxContainer/HFlowContainer/Button" to="." method="OnGetCacheDir"]
|
||||
[connection signal="pressed" from="BoxContainer/HFlowContainer/Button2" to="." method="OnGetConfigDir"]
|
||||
[connection signal="pressed" from="BoxContainer/HFlowContainer/Button3" to="." method="OnGetDataDir"]
|
||||
[connection signal="pressed" from="BoxContainer/HFlowContainer/Button4" to="." method="OnGetUserDataDir"]
|
74
Scripts/Controllers/ChessGame.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using Godot;
|
||||
using ChineseChess;
|
||||
|
||||
public partial class ChessGame : Node2D {
|
||||
GlobalManager global = GlobalManager.Instance;
|
||||
readonly Logging.Logger logger = Logging.GetLogger("ChessGame");
|
||||
ChessBoard board = null!;
|
||||
ConfirmationDialog dialog = null!;
|
||||
ChessCore Game = null!;
|
||||
private bool isSession = false;
|
||||
ChessCore.TurnsSideType sideSelf;
|
||||
ChessCore.TurnsSideType sideOpposite;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready() {
|
||||
board = GetNode<ChessBoard>("%Chessboard");
|
||||
GetNode<LineEdit>("%LineEdit_YouAre").Text = global.GlobalData["player_color"].AsString();
|
||||
LineEdit turnSideEdit = GetNode<LineEdit>("%LineEdit_TurnSide");
|
||||
turnSideEdit.Text = "red";
|
||||
|
||||
dialog = new ConfirmationDialog {
|
||||
DialogAutowrap = true,
|
||||
MinSize = new Vector2I(400, 200),
|
||||
Position = new Vector2I(200, 400),
|
||||
};
|
||||
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;
|
||||
}
|
||||
|
||||
Game = new(isSession ? ChessCore.Mode.MultiMode : ChessCore.Mode.SingleMode, sideSelf, board);
|
||||
|
||||
board.OnStepsChanged += (sender, e) => {
|
||||
turnSideEdit.Text = Game.GetTurnsType() == ChessCore.TurnsSideType.Red ? "red" : "black";
|
||||
};
|
||||
|
||||
board.OnPosClicked += (sender, pos) => {
|
||||
int posX = (int)pos.X;
|
||||
int posY = (int)pos.Y;
|
||||
Vector.Vector2I vector = new(posX, posY);
|
||||
Game.OnPosClicked(vector);
|
||||
};
|
||||
}
|
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _Process(double delta) {
|
||||
}
|
||||
|
||||
private void BtnOver() {
|
||||
logger.Info($"BtnOver");
|
||||
}
|
||||
|
||||
public void GoHome() {
|
||||
// TODO ClearServer();
|
||||
global.GotoScene("res://Main.tscn");
|
||||
}
|
||||
|
||||
public void Undo() {
|
||||
logger.Info($"Undo");
|
||||
if (Game.board.Steps == 0) board.Clear();
|
||||
Game.Undo();
|
||||
}
|
||||
|
||||
public void ReInit() {
|
||||
// TODO using dialog to confirm
|
||||
logger.Info($"ReInit");
|
||||
Game.ReInit();
|
||||
}
|
||||
}
|
1
Scripts/Controllers/ChessGame.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cqgctouhh8qok
|
60
Scripts/Controllers/GameLobby.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
public partial class GameLobby : Control {
|
||||
GlobalManager global = GlobalManager.Instance;
|
||||
readonly Logging.Logger logger = Logging.GetLogger("GameLobby");
|
||||
Timer timer = null!;
|
||||
|
||||
ItemList lists = null!;
|
||||
ConfirmationDialog dialog = null!;
|
||||
string URL = null!;
|
||||
string userName = null!;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready() {
|
||||
lists = GetNode<ItemList>("%ItemList_Users");
|
||||
// TODO using %
|
||||
dialog = GetNode<ConfirmationDialog>("Dialogs/ConfirmationDialog");
|
||||
|
||||
URL = global.ConfigManager.GetValue<string>("server_addr");
|
||||
userName = global.ConfigManager.GetValue<string>("user_name");
|
||||
|
||||
dialog.MinSize = new Vector2I(400, 200);
|
||||
dialog.DialogAutowrap = true;
|
||||
dialog.Canceled += () => {
|
||||
// TODO Cancel to Accept Session Create
|
||||
};
|
||||
dialog.Confirmed += () => {
|
||||
if (dialog.Title == "Session Created") {
|
||||
// TODO Create Session
|
||||
}
|
||||
};
|
||||
|
||||
// TODO using new State Shower And Using Heartbeat to calucate the delay time
|
||||
ColorRect colorRect = GetNode<ColorRect>("MarginContainer/VBoxContainer/MarginContainer2/MarginContainer2/ColorRect");
|
||||
Connect();
|
||||
}
|
||||
|
||||
public void Connect() {
|
||||
logger.Info("Connect To Server");
|
||||
// TODO connet to server
|
||||
global.SetProcess(true);
|
||||
}
|
||||
|
||||
private void OnItemSelected(int index) {
|
||||
Dictionary item = lists.GetItemMetadata(index).AsGodotDictionary();
|
||||
logger.Debug($"Item {index} selected, {item}");
|
||||
string[] _ = [item["id"].ToString()];
|
||||
// TODO new a Session
|
||||
}
|
||||
|
||||
private void FlushUserData() {
|
||||
// TODO Flush user data or heartbeat flush
|
||||
}
|
||||
|
||||
private void OnBack() {
|
||||
// TODO ExitServer();
|
||||
global.GotoScene("res://Main.tscn");
|
||||
}
|
||||
}
|
1
Scripts/Controllers/GameLobby.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cn273e4u256r
|
43
Scripts/Controllers/Mods.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public partial class Mods : Control {
|
||||
GlobalManager global = GlobalManager.Instance;
|
||||
ItemList modsItemList = null!;
|
||||
|
||||
public override void _Ready() {
|
||||
// TODO
|
||||
modsItemList = GetNode<ItemList>("VBoxContainer/VScrollBar/ItemList");
|
||||
FlushModState();
|
||||
}
|
||||
|
||||
private void FlushModState() {
|
||||
modsItemList.Clear();
|
||||
foreach (var mod in global.Mods.ModList) {
|
||||
var item = modsItemList.AddItem(mod.Key);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnableMods(bool enable) {
|
||||
if (enable) {
|
||||
global.Mods.LoadAllMods();
|
||||
}
|
||||
else {
|
||||
global.Mods.ClearAllMods();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReSearchMods() {
|
||||
global.Mods.SearchAllMods(true);
|
||||
}
|
||||
|
||||
public void OnOpenModFileDir() {
|
||||
string path = global.ConfigManager.GetValue<string>("mods_fpath") ?? "user://mods";
|
||||
OS.ShellOpen(ProjectSettings.GlobalizePath(path));
|
||||
}
|
||||
|
||||
public void OnBack() {
|
||||
ArgumentNullException.ThrowIfNull(global);
|
||||
global.GotoScene("res://Main.tscn");
|
||||
}
|
||||
}
|
1
Scripts/Controllers/Mods.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c8t8d8e7inajy
|
91
Scripts/Controllers/Setting.cs
Normal file
@ -0,0 +1,91 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
public partial class Setting : Control {
|
||||
private GlobalManager global = GlobalManager.Instance;
|
||||
private readonly IConfigManager config = GlobalManager.Instance.ConfigManager;
|
||||
private int font_size;
|
||||
private LineEdit fontOut = null!;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready() {
|
||||
fontOut = GetNode<LineEdit>("%FontSize");
|
||||
font_size = config.GetValue<int>("font_size");
|
||||
GetNode<HSlider>("%FontSizeBar")
|
||||
.Value = font_size;
|
||||
fontOut.Text = font_size.ToString();
|
||||
|
||||
GetNode<LineEdit>("%LineEdit_ServerIP")
|
||||
.Text = config.GetValue<string>("server_addr");
|
||||
GetNode<LineEdit>("%LineEdit_UserName")
|
||||
.Text = config.GetValue<string>("user_name");
|
||||
}
|
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _Process(double delta) {
|
||||
}
|
||||
|
||||
private void OnBack() {
|
||||
global.GotoScene("res://Main.tscn", null);
|
||||
}
|
||||
|
||||
private void OnSave() {
|
||||
global.SaveConfig();
|
||||
}
|
||||
|
||||
void OnNameChanged(string Value) {
|
||||
config.SetValue("user_name", Value);
|
||||
}
|
||||
|
||||
private void OnServerUrlChanged(string Value) {
|
||||
config.SetValue("server_url", Value);
|
||||
}
|
||||
|
||||
private void OnFontSizeChanged(float Value) {
|
||||
font_size = (int)Value;
|
||||
config.SetValue("font_size", font_size);
|
||||
global.GlobalThemeConfigFlush();
|
||||
fontOut.Text = font_size.ToString();
|
||||
}
|
||||
|
||||
private static void OnClearData() {
|
||||
// ProjectSettings.GlobalizePath("user://");
|
||||
// DirAccess.CopyAbsolute("res://userdata", "user://");
|
||||
}
|
||||
|
||||
private static void OnClearUserData() {
|
||||
string path = ProjectSettings.GlobalizePath("user://");
|
||||
|
||||
// DirAccess dirAccess = DirAccess.Open(path);
|
||||
// dirAccess.Remove(path);
|
||||
if (DirAccess.RemoveAbsolute(path) != Error.Ok) {
|
||||
FormattableString msg = $"Failed to delete user data at {path}";
|
||||
OS.Alert(msg.ToString(), "Error");
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnGetSettingsFile() {
|
||||
string path = ProjectSettings.GlobalizePath(GlobalManager.ConfigPath);
|
||||
OS.ShellOpen(Path.GetDirectoryName(path));
|
||||
}
|
||||
|
||||
private static void OnGetCacheDir() {
|
||||
OS.Alert(OS.GetCacheDir(), "Cache Dir");
|
||||
}
|
||||
|
||||
private static void OnGetConfigDir() {
|
||||
OS.Alert(OS.GetConfigDir(), "Config Dir");
|
||||
}
|
||||
|
||||
private static void OnGetDataDir() {
|
||||
OS.Alert(OS.GetDataDir(), "Data Dir");
|
||||
}
|
||||
|
||||
private static void OnGetUserDataDir() {
|
||||
OS.Alert(OS.GetUserDataDir(), "User Data Dir");
|
||||
}
|
||||
|
||||
private static void ChangeLangZHCN(bool _) => TranslationServer.SetLocale("zh_CN");
|
||||
private static void ChangeLangEN(bool _) => TranslationServer.SetLocale("en");
|
||||
}
|
1
Scripts/Controllers/Setting.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://71ril3nh84rw
|
87
Scripts/Entities/ChessBoard.cs
Normal file
@ -0,0 +1,87 @@
|
||||
// Chessboard.cs
|
||||
using System;
|
||||
using Godot;
|
||||
using ChineseChess;
|
||||
using Godot.Collections;
|
||||
|
||||
using static IBoard;
|
||||
public partial class ChessBoard : Node2D, ICCBoardOn {
|
||||
public event EventHandler<Vector2>? OnMouseClicked;
|
||||
public event EventHandler<Vector2>? OnPosClicked;
|
||||
public event EventHandler<int>? OnStepsChanged;
|
||||
|
||||
public Vector2 from = Vector2.Inf, to = Vector2.Inf;
|
||||
public Array<Vector2> canMovePos = [];
|
||||
|
||||
public override void _Ready() {
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
from = to = Vector2.Inf;
|
||||
QueueRedraw();
|
||||
}
|
||||
|
||||
void IBoardOn.OnInsert(object self, IPiece piece) {
|
||||
ChessPiece? node = piece.On as ChessPiece;
|
||||
// throw new InvalidOperationException();
|
||||
node ??= new ChessPiece((CCPiece)piece);
|
||||
node.ShowBehindParent = true;
|
||||
AddChild(node);
|
||||
|
||||
// ChessPiece chessPiece = null;
|
||||
// if (piece.Data.TryGetValue("Godot", out object node)) {
|
||||
// chessPiece = node as ChessPiece;
|
||||
// } else {
|
||||
// chessPiece = new((CCPiece)piece);
|
||||
// }
|
||||
// chessPiece.ShowBehindParent = true;
|
||||
// AddChild(chessPiece);
|
||||
}
|
||||
|
||||
void IBoardOn.OnRemove(object self, IPiece piece) {
|
||||
if (piece.On is not ChessPiece node) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
RemoveChild(node);
|
||||
}
|
||||
|
||||
void IBoardOn.OnMove(object self, IBoardOn.MoveEventArgs vals) {
|
||||
from = PosTrans.transArrToPix * new Vector2(vals.From.X, vals.From.Y);
|
||||
to = PosTrans.transArrToPix * new Vector2(vals.To.X, vals.To.Y);
|
||||
QueueRedraw();
|
||||
}
|
||||
|
||||
void ICCBoardOn.OnSteps(object _self, int oldSteps) {
|
||||
if (_self is not CCBoard self) return;
|
||||
OnStepsChanged?.Invoke(self, self.Steps);
|
||||
}
|
||||
|
||||
public override void _Draw() {
|
||||
Color color = new(0.7f, 0.7f, 0.7f, 0.5f);
|
||||
DrawLine(from, to, color, PosTrans.pixGripSize / 5);
|
||||
DrawCircle(from, PosTrans.pixGripSize / 2.2f, color);
|
||||
foreach (Vector2 pos in canMovePos) {
|
||||
DrawCircle(pos, PosTrans.pixGripSize / 2.2f,
|
||||
color.Inverted());
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event) {
|
||||
if (@event is InputEventMouseButton mouseEvent &&
|
||||
mouseEvent.Pressed &&
|
||||
mouseEvent.ButtonIndex == MouseButton.Left) {
|
||||
OnMouseClicked?.Invoke(this, GetLocalMousePosition());
|
||||
OnPosClicked?.Invoke(this, (PosTrans.transArrToPix.AffineInverse() *
|
||||
GetLocalMousePosition()).Round());
|
||||
}
|
||||
}
|
||||
|
||||
public static class PosTrans {
|
||||
public static readonly int pixGripSize = 32;
|
||||
public static readonly Transform2D transArrToPix = new(
|
||||
new Vector2(pixGripSize, 0),
|
||||
new Vector2(0, pixGripSize),
|
||||
new Vector2(-4, -4.5f) * pixGripSize
|
||||
);
|
||||
}
|
||||
}
|
1
Scripts/Entities/ChessBoard.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dmc012tt32dkl
|
78
Scripts/Entities/ChessPiece.cs
Normal file
@ -0,0 +1,78 @@
|
||||
// Chesspiece.cs
|
||||
using Godot;
|
||||
using ChineseChess;
|
||||
|
||||
using static IPiece;
|
||||
public partial class ChessPiece : Sprite2D, IPieceOn {
|
||||
[Export]
|
||||
public string? PieceLabel { get; set; } = null;
|
||||
// Text Color (Can Export for Editor Adjust)
|
||||
[Export]
|
||||
public Color LabelColor { get; set; } = new Color("white");
|
||||
private Vector2 textureSize;
|
||||
private Label? labelOfChessName;
|
||||
|
||||
void IPieceOn.OnPos(object _self, Vector.Vector2I oldPos) {
|
||||
if (_self is not CCPiece self) return;
|
||||
Position = ChessBoard.PosTrans.transArrToPix * new Vector2(self.Pos.X, self.Pos.Y);
|
||||
}
|
||||
|
||||
void IPieceOn.OnSelected(object _self, bool oldIsSelected) {
|
||||
if (GetParent() is not ChessBoard chessBoard || _self is not CCPiece self) return;
|
||||
if (self.IsSelected) {
|
||||
GD.Print($"{self.Pos} is selected");
|
||||
Transform *= transToSeleted;
|
||||
foreach (var item in self.CanMoveAllPos()) {
|
||||
chessBoard.canMovePos.Add(ChessBoard.PosTrans.transArrToPix * new Vector2(item.X, item.Y));
|
||||
}
|
||||
} else {
|
||||
GD.Print($"{self.Pos} is deselected");
|
||||
Transform *= transToSeleted.AffineInverse();
|
||||
foreach (var item in self.CanMoveAllPos()) {
|
||||
chessBoard.canMovePos.Remove(ChessBoard.PosTrans.transArrToPix * new Vector2(item.X, item.Y));
|
||||
}
|
||||
}
|
||||
chessBoard.QueueRedraw();
|
||||
}
|
||||
|
||||
Transform2D transToSeleted = new(
|
||||
new Vector2(1.2f, 0),
|
||||
new Vector2(0, 1.2f),
|
||||
new Vector2(0, 0)
|
||||
);
|
||||
|
||||
public ChessPiece() : this(new CCPiece()) {
|
||||
}
|
||||
|
||||
public ChessPiece(CCPiece piece) {
|
||||
PieceLabel = piece.CNName;
|
||||
LabelColor = piece.TurnsSide == ChessCore.TurnsSideType.Red ? new Color("red") : new Color("black");
|
||||
piece.On = this;
|
||||
// Must Be Call for init Pos
|
||||
piece.On.OnPos(piece, piece.Pos);
|
||||
piece.Data.TryAdd("Godot", this);
|
||||
}
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready() {
|
||||
InitLabel();
|
||||
}
|
||||
|
||||
private void InitLabel() {
|
||||
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);
|
||||
}
|
||||
}
|
1
Scripts/Entities/ChessPiece.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c8eafskfpuesm
|
133
Scripts/GlobalManager.cs
Normal file
@ -0,0 +1,133 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
public partial class GlobalManager : Node {
|
||||
private static readonly Logging.Logger logger = Logging.GetLogger("GlobalManager");
|
||||
public static GlobalManager Instance { get; private set; } = null!;
|
||||
public static string ConfigPath { get; private set; } = "user://config.json";
|
||||
private GlobalManager() {
|
||||
ConfigManager.SetFilePath(ProjectSettings.GlobalizePath(ConfigPath));
|
||||
ConfigManager.SetDefault(_default_config);
|
||||
ConfigManager.LoadFromFile();
|
||||
|
||||
Mods = new GlobalModManager(ConfigManager.GetValue<string>("mods_fpath"));
|
||||
Mods.SearchAllMods();
|
||||
}
|
||||
|
||||
public readonly GlobalModManager Mods = null!;
|
||||
public readonly IConfigManager ConfigManager = new JsonConfigManager();
|
||||
private static readonly Dictionary<string, object> _default_config = new() {
|
||||
{"font_size", 20},
|
||||
{"server_addr", "wss://game.zzyxyz.com/"},
|
||||
{"user_name", "undefined"},
|
||||
|
||||
{"mods_fpath", "user://mods"},
|
||||
{"mods_allowed", false},
|
||||
};
|
||||
|
||||
public string sessionId = "";
|
||||
public Node CurrentScene { get; set; } = null!;
|
||||
public Theme GlobalTheme = null!;
|
||||
|
||||
// readonly GodotConfigManager GlobalConfig = new("user://config.cfg");
|
||||
|
||||
// TODO will remove this
|
||||
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() {
|
||||
if (Instance == null) {
|
||||
Instance = this;
|
||||
}
|
||||
else {
|
||||
logger.Error("GlobalManager already exists");
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
if (OS.GetName() == "Android") {
|
||||
bool ret = OS.RequestPermissions();
|
||||
logger.Warning($"RequestPermissions ret is {ret}");
|
||||
}
|
||||
|
||||
Viewport root = GetTree().Root;
|
||||
CurrentScene = root.GetChild(root.GetChildCount() - 1);
|
||||
|
||||
SetProcess(false);
|
||||
}
|
||||
|
||||
public void GlobalThemeConfigFlush() {
|
||||
int font_size = ConfigManager.GetValue<int>("font_size");
|
||||
GlobalTheme.DefaultFontSize = font_size;
|
||||
// GlobalTheme?.SetFontSize("font_size", "Label", font_size);
|
||||
// GlobalTheme?.SetFontSize("font_size", "Button", font_size);
|
||||
// GlobalTheme?.SetFontSize("font_size", "TextEdit", font_size);
|
||||
// GlobalTheme?.SetFontSize("font_size", "LineEdit", font_size);
|
||||
// CurrentScene.GetWindow().AddThemeFontSizeOverride("Control", (int)GlobalConfigDict["font_size"]);
|
||||
}
|
||||
|
||||
private void OnGotoScene() {
|
||||
GlobalThemeConfigFlush();
|
||||
}
|
||||
|
||||
public void SaveConfig() {
|
||||
ConfigManager.SaveToFile();
|
||||
// GlobalConfig.SaveConfig("Global", _conf_dict);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// SaveConfig();
|
||||
// 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;
|
||||
|
||||
OnGotoScene();
|
||||
}
|
||||
}
|
1
Scripts/GlobalManager.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://gfwgyu7p8hoi
|
175
Scripts/Logger.cs
Normal file
@ -0,0 +1,175 @@
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
/// <summary>
|
||||
/// 仿照 Python logging 的 日志系统
|
||||
/// </summary>
|
||||
public static class Logging {
|
||||
// ========== 日志级别 ==========
|
||||
public enum Level {
|
||||
NOSET = 0,
|
||||
DEBUG = 10,
|
||||
INFO = 20,
|
||||
WARNING = 30,
|
||||
ERROR = 40,
|
||||
CRITICAL = 50
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录器
|
||||
/// </summary>
|
||||
public class Logger(string name) {
|
||||
public string Name { get; } = name;
|
||||
public Level LogLevel { get; set; } = Level.INFO;
|
||||
private readonly List<Action<Level, string, string, string>> _handlers = [];
|
||||
|
||||
public void AddHandler(Action<Level, string, string, string> handler) =>
|
||||
_handlers.Add(handler);
|
||||
|
||||
// ===== 日志方法 =====
|
||||
public void Debug(string fmt, params object[] args) =>
|
||||
Log(Level.DEBUG, fmt, false, args);
|
||||
|
||||
public void Info(string fmt, params object[] args) =>
|
||||
Log(Level.INFO, fmt, false, args);
|
||||
|
||||
public void Warning(string fmt, params object[] args) =>
|
||||
Log(Level.WARNING, fmt, false, args);
|
||||
|
||||
public void Error(string fmt, params object[] args) =>
|
||||
Log(Level.ERROR, fmt, false, args);
|
||||
|
||||
public void Critical(string fmt, params object[] args) =>
|
||||
Log(Level.CRITICAL, fmt, true, args);
|
||||
|
||||
public void Exception(string fmt, Exception e, params object[] args) {
|
||||
// TODO for godot not support /r/n yet
|
||||
string stackTrace = e.StackTrace?.Replace("\r\n", "\n") ?? "";
|
||||
string exceptionMessage = $"{fmt}\n{e.Message}\n{stackTrace}";
|
||||
|
||||
Log(Level.ERROR, exceptionMessage, false, args);
|
||||
}
|
||||
|
||||
// ===== 核心Log方法 =====
|
||||
private void Log(Level level, string fmt, bool isExec = false, params object[] args) {
|
||||
if (level < LogLevel) return;
|
||||
|
||||
// 格式化消息
|
||||
string message = args.Length > 0 ?
|
||||
string.Format(fmt, args) : fmt;
|
||||
|
||||
// 添加执行堆栈信息
|
||||
string stackInfo = isExec ?
|
||||
$"\nExecution Stack:\n{System.Environment.StackTrace}" : "";
|
||||
|
||||
// 构建前缀
|
||||
string prefix = $"[{DateTime.Now:HH:mm:ss}] [{level}] [{Name}]";
|
||||
|
||||
// 调用所有处理器
|
||||
foreach (var handler in _handlers) {
|
||||
handler(level, prefix, message, stackInfo);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public void Assert(bool condition, string fmt, params object[] args) {
|
||||
if (condition) return;
|
||||
string message = args.Length > 0 ?
|
||||
string.Format(fmt, args) : fmt;
|
||||
Error("Assertion Failed: " + message, true);
|
||||
|
||||
if (Debugger.IsAttached)
|
||||
Debugger.Break();
|
||||
|
||||
System.Diagnostics.Debug.Assert(condition, message);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 全局管理器 ==========
|
||||
private static readonly Dictionary<string, Logger> _loggers = [];
|
||||
private static readonly Logger _root = GetLogger("root");
|
||||
|
||||
/// <summary>
|
||||
/// 获取或创建日志记录器
|
||||
/// </summary>
|
||||
public static Logger GetLogger(string name = "root") {
|
||||
if (!_loggers.TryGetValue(name, out var logger)) {
|
||||
logger = new Logger(name);
|
||||
logger.AddHandler(DefaultHandler);
|
||||
_loggers[name] = logger;
|
||||
}
|
||||
return logger;
|
||||
}
|
||||
|
||||
// ========== 优化的默认处理器 ==========
|
||||
private static void DefaultHandler(Level level, string prefix, string message, string stackInfo) {
|
||||
// 构建完整日志消息
|
||||
string fullMessage = $"{prefix} {message}{stackInfo}";
|
||||
|
||||
switch (level) {
|
||||
case Level.DEBUG:
|
||||
// DEBUG级别:使用GD.Print + OS条件
|
||||
if (OS.IsStdOutVerbose())
|
||||
GD.Print(fullMessage);
|
||||
break;
|
||||
|
||||
case Level.INFO:
|
||||
// INFO级别:使用GD.Print
|
||||
GD.Print(fullMessage);
|
||||
break;
|
||||
|
||||
case Level.WARNING:
|
||||
// WARNING级别:使用PrintRich + 黄色
|
||||
GD.PrintRich($"[color=yellow]{fullMessage}[/color]");
|
||||
break;
|
||||
|
||||
case Level.ERROR:
|
||||
// ERROR级别:使用GD.PrintErr
|
||||
GD.PrintRich($"[color=red][b]{fullMessage}[/b][/color]");
|
||||
// GD.PrintErr(fullMessage);
|
||||
break;
|
||||
|
||||
case Level.CRITICAL:
|
||||
// CRITICAL级别:使用GD.PushError
|
||||
GD.PushError(fullMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 快捷操作方式 ==========
|
||||
public static void Debug(string fmt, params object[] args) =>
|
||||
_root.Debug(fmt, args);
|
||||
|
||||
public static void Info(string fmt, params object[] args) =>
|
||||
_root.Info(fmt, args);
|
||||
|
||||
public static void Warning(string fmt, params object[] args) =>
|
||||
_root.Warning(fmt, args);
|
||||
|
||||
public static void Error(string fmt, params object[] args) =>
|
||||
_root.Error(fmt, args);
|
||||
|
||||
public static void Critical(string fmt, params object[] args) =>
|
||||
_root.Critical(fmt, args);
|
||||
|
||||
// ===== C语言风格的宏断言快捷方式 =====
|
||||
[Conditional("DEBUG")]
|
||||
public static void Assert(bool condition, string fmt, params object[] args) =>
|
||||
_root.Assert(condition, fmt, args);
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public static void TestPrint() {
|
||||
GD.Print("GameSystem Singleton Initialized");
|
||||
GD.PrintErr("This is a print error");
|
||||
GD.PushWarning("This is a warning");
|
||||
GD.PushError("This is a error");
|
||||
Debug("This is a debug");
|
||||
Info("This is a info");
|
||||
Warning("This is a warn");
|
||||
Error("This is a error");
|
||||
Critical("This is a critical");
|
||||
Assert(true, "This is a assert");
|
||||
}
|
||||
}
|
1
Scripts/Logger.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bud682vprk1w6
|
72
Scripts/Mods/GlobalModManager.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
public class GlobalModManager(string modPath = "user://mods") {
|
||||
public static GlobalModManager Instance { get; } = new();
|
||||
private readonly Dictionary<string, LuaModManager> _mods = [];
|
||||
public ReadOnlyDictionary<string, LuaModManager> Mods => new(_mods);
|
||||
private readonly Dictionary<string, string> _modList = [];
|
||||
public ReadOnlyDictionary<string, string> ModList => new(_modList);
|
||||
private readonly string modPath = modPath;
|
||||
private static readonly Logging.Logger logger = Logging.GetLogger("GlobalMod");
|
||||
|
||||
public void SearchAllMods(bool isFlush = false) {
|
||||
if (isFlush) {
|
||||
_modList.Clear();
|
||||
}
|
||||
if (!DirAccess.DirExistsAbsolute(modPath))
|
||||
return;
|
||||
|
||||
using var dir = DirAccess.Open(modPath);
|
||||
if (dir == null) return;
|
||||
|
||||
dir.ListDirBegin();
|
||||
string fileName = dir.GetNext();
|
||||
while (!string.IsNullOrEmpty(fileName)) {
|
||||
string fullPath = $"{modPath}/{fileName}";
|
||||
const string entryFileName = "main.lua";
|
||||
|
||||
if (dir.CurrentIsDir() && !fileName.StartsWith('.') &&
|
||||
FileAccess.FileExists($"{fullPath}/{entryFileName}")) {
|
||||
_modList.Add($"{fullPath}/{entryFileName}", fullPath);
|
||||
}
|
||||
fileName = dir.GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadAllMods(bool isFlush = false) {
|
||||
if (isFlush) {
|
||||
_mods.Clear();
|
||||
}
|
||||
foreach (var mod in _modList) {
|
||||
try {
|
||||
LoadMod(mod.Key, mod.Value);
|
||||
}
|
||||
catch (System.Exception e) {
|
||||
logger.Exception("Failed to load mod {0}", e, mod.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearAllMods() {
|
||||
_mods.Clear();
|
||||
}
|
||||
|
||||
private void LoadMod(string filePath, string modPath) {
|
||||
string _filePath = ProjectSettings.GlobalizePath(filePath);
|
||||
string _modPath = ProjectSettings.GlobalizePath(modPath);
|
||||
_mods.Add(filePath, new LuaModManager(_filePath, _modPath));
|
||||
}
|
||||
|
||||
private static void SaveFile(string path, string content) {
|
||||
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Write);
|
||||
file.StoreString(content);
|
||||
}
|
||||
|
||||
private static string LoadFile(string path) {
|
||||
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
||||
string content = file.GetAsText();
|
||||
return content;
|
||||
}
|
||||
}
|
1
Scripts/Mods/GlobalModManager.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://c45a7ldunixnh
|
44
Scripts/Mods/LuaModManager.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLua;
|
||||
|
||||
public class LuaModManager : IDisposable {
|
||||
private readonly Lua lua = new();
|
||||
private static readonly Logging.Logger logger = Logging.GetLogger("LuaMod");
|
||||
|
||||
public LuaModManager(string path, string? package_path = null) {
|
||||
lua.LoadCLRPackage();
|
||||
lua.State.Encoding = System.Text.Encoding.UTF8;
|
||||
lua["package.path"] = package_path ?? Path.GetDirectoryName(path) + "/?.lua;";
|
||||
lua.RegisterFunction("print", new Action<object[]>(Godot.GD.Print).Method);
|
||||
|
||||
logger.Info("Loading Lua Mod: " + path);
|
||||
lua.DoFile(path);
|
||||
}
|
||||
|
||||
public void BindFunc(ModManager mod) {
|
||||
foreach (var api in mod.GetAPIs()) {
|
||||
lua.RegisterFunction(api.Key, api.Value.Target, api.Value.Method);
|
||||
}
|
||||
foreach (var hook in mod.GetHooks()) {
|
||||
if (lua[hook.Key] is LuaFunction func) {
|
||||
mod.AddHook(hook.Key, (args) => {
|
||||
var rets = func.Call(args).FirstOrDefault();
|
||||
if (rets is bool b) return b;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
lua?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public static void WriteComment(Delegate @delegate) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
1
Scripts/Mods/LuaModManager.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dtqaboju24vmn
|
45
Scripts/Mods/ModManager.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
|
||||
public class ModManager {
|
||||
private readonly Dictionary<string, Delegate> _api = [];
|
||||
private readonly Dictionary<string, Delegate> _hooks = [];
|
||||
public delegate bool OnCallback(params object[] args);
|
||||
private readonly Dictionary<string, List<OnCallback>> _callbackList = [];
|
||||
|
||||
public ReadOnlyDictionary<string, Delegate> GetAPIs() => new(_api);
|
||||
public ReadOnlyDictionary<string, Delegate> GetHooks() => new(_hooks);
|
||||
|
||||
public ModManager RegistryFunc<TDelegate>(string name, TDelegate handler, bool isHook = false)
|
||||
where TDelegate : Delegate {
|
||||
MethodInfo _ = handler.Method;
|
||||
Dictionary<string, Delegate> dict = isHook ? _hooks : _api;
|
||||
dict.Add(name, handler);
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool AddHook(string name, OnCallback handler) {
|
||||
if (_hooks.ContainsKey(name)) {
|
||||
if (!_callbackList.TryGetValue(name, out var list)) {
|
||||
list = [];
|
||||
_callbackList[name] = list;
|
||||
}
|
||||
list.Add(handler);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool InvokeFunc<TDelegate>(string name, params object[] args)
|
||||
where TDelegate : Delegate {
|
||||
List<object> res = [];
|
||||
if (_callbackList.TryGetValue(name, out var callback)) {
|
||||
foreach (var func in callback) {
|
||||
func?.Invoke(args);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
1
Scripts/Mods/ModManager.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://lmuddan86bi8
|
117
Scripts/Src/AbstractBoard.cs
Normal file
@ -0,0 +1,117 @@
|
||||
using System.Collections.Generic;
|
||||
using Vector2I = Vector.Vector2I;
|
||||
|
||||
using static IBoard;
|
||||
public abstract class AbstractBoard(int rows, int cols, int maxRecords = int.MaxValue,
|
||||
IBoardOn? on = null) : IBoard {
|
||||
private readonly int rows = rows;
|
||||
private readonly int cols = cols;
|
||||
protected readonly IPiece?[,] pieces = new IPiece[rows, cols];
|
||||
protected readonly List<MoveRecord> moveRecords = [];
|
||||
protected readonly int MAX_RECORDS = maxRecords;
|
||||
|
||||
public int Rows => rows;
|
||||
public int Cols => cols;
|
||||
protected IBoardOn? on = on;
|
||||
|
||||
public virtual IBoardOn? On { get => on; set => on = value; }
|
||||
|
||||
public virtual bool IsPosOutOfRange(Vector2I arrayPos) {
|
||||
return arrayPos.X < 0 || arrayPos.X >= Rows || arrayPos.Y < 0 || arrayPos.Y >= Cols;
|
||||
}
|
||||
|
||||
public virtual IPiece? GetPiece(Vector2I arrayPos) {
|
||||
if (IsPosOutOfRange(arrayPos)) return null;
|
||||
return pieces[arrayPos.X, arrayPos.Y];
|
||||
}
|
||||
|
||||
public virtual IPiece? SetPiece(IPiece? piece, Vector2I pos) {
|
||||
if (IsPosOutOfRange(pos)) return null;
|
||||
|
||||
IPiece? oldPiece = pieces[pos.X, pos.Y];
|
||||
pieces[pos.X, pos.Y] = piece;
|
||||
if (piece is not null) piece.Pos = pos;
|
||||
// if (oldPiece != null) oldPiece.Pos = Vector2I.Zero;
|
||||
|
||||
on?.OnSetPieceInteral(this, new IBoardOn.SetPieceEventArgs
|
||||
(oldPiece, piece, pos));
|
||||
return oldPiece;
|
||||
}
|
||||
|
||||
public virtual bool InsertPiece(IPiece piece, Vector2I pos) {
|
||||
if (GetPiece(pos) is not null && piece == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
on?.OnInsert(this, piece);
|
||||
SetPiece(piece, pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool MovePiece(Vector2I from, Vector2I to) {
|
||||
if (IsPosOutOfRange(to) || IsPosOutOfRange(from)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IPiece? piece = GetPiece(from);
|
||||
if (GetPiece(to) is not null || piece is null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
on?.OnMove(this, new IBoardOn.MoveEventArgs(piece, from, to));
|
||||
SetPiece(null, from);
|
||||
SetPiece(piece, to);
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual IPiece? RemovePiece(Vector2I pos) {
|
||||
IPiece? piece = GetPiece(pos);
|
||||
if (piece is null) return null;
|
||||
|
||||
on?.OnRemove(this, piece);
|
||||
return SetPiece(null, pos);
|
||||
}
|
||||
|
||||
public virtual void Clear() { Clear(true); }
|
||||
|
||||
public virtual void Clear(bool clearRecords) {
|
||||
for (int i = 0; i < Rows; i++) {
|
||||
for (int j = 0; j < Cols; j++) {
|
||||
RemovePiece(new Vector2I(i, j));
|
||||
}
|
||||
}
|
||||
if (clearRecords) ClearRecords();
|
||||
}
|
||||
|
||||
public virtual void ClearRecords() {
|
||||
moveRecords.Clear();
|
||||
}
|
||||
|
||||
public virtual void AddRecord(IPiece? From, IPiece? To, Vector2I FromPos, Vector2I ToPos) {
|
||||
if (moveRecords.Count >= MAX_RECORDS) {
|
||||
moveRecords.RemoveAt(0);
|
||||
}
|
||||
MoveRecord record = new(From, To, FromPos, ToPos);
|
||||
|
||||
on?.OnAddRecord(this, record);
|
||||
moveRecords.Add(record);
|
||||
}
|
||||
|
||||
public virtual void UndoRecord() {
|
||||
if (moveRecords.Count == 0) return;
|
||||
MoveRecord record = moveRecords[^1];
|
||||
moveRecords.RemoveAt(moveRecords.Count - 1);
|
||||
|
||||
// 恢复新位置的棋子,order is very inmportant
|
||||
if (record.From is not null) {
|
||||
MovePiece(record.ToPos, record.FromPos);
|
||||
}
|
||||
|
||||
// 恢复旧位置的棋子
|
||||
if (record.To is not null) {
|
||||
InsertPiece(record.To, record.ToPos);
|
||||
}
|
||||
|
||||
on?.OnUndoRecord(this, record);
|
||||
}
|
||||
}
|
1
Scripts/Src/AbstractBoard.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://d1xim7v5bes7j
|
67
Scripts/Src/AbstractPiece.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System.Collections.Generic;
|
||||
using Vector2I = Vector.Vector2I;
|
||||
|
||||
using static IPiece;
|
||||
public abstract class AbstractPiece(string name = "", Vector2I? pos = null,
|
||||
IPieceOn? on = null) : IPiece {
|
||||
private Vector2I pos = pos ?? new(); // 注意这个坐标的非像素坐标而是棋盘坐标
|
||||
private bool isSelected = false;
|
||||
protected string name = name;
|
||||
private Dictionary<string, object> data = [];
|
||||
protected IPieceOn? on = on;
|
||||
|
||||
public virtual IPieceOn? On { get => on; set => on = value; }
|
||||
|
||||
public virtual Vector2I Pos {
|
||||
get => pos;
|
||||
set {
|
||||
if (pos != value) {
|
||||
var oldPos = pos;
|
||||
pos = value;
|
||||
on?.OnPos(this, oldPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool IsSelected {
|
||||
get => isSelected;
|
||||
set {
|
||||
if (isSelected != value) {
|
||||
var oldIsSelected = isSelected;
|
||||
isSelected = value;
|
||||
on?.OnSelected(this, oldIsSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string Name {
|
||||
get => name;
|
||||
set {
|
||||
if (name != value) {
|
||||
var oldName = name;
|
||||
name = value;
|
||||
on?.OnName(this, oldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Dictionary<string, object> Data {
|
||||
get => data;
|
||||
set => data = value;
|
||||
}
|
||||
|
||||
public virtual bool Move(Vector2I pos) {
|
||||
if (!CanMove(pos)) {
|
||||
return false;
|
||||
}
|
||||
Pos = pos;
|
||||
on?.OnMove(this, pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract bool CanMove(Vector2I to);
|
||||
|
||||
public override string ToString() {
|
||||
return $"{Name} at {pos}";
|
||||
}
|
||||
}
|
1
Scripts/Src/AbstractPiece.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cxlgd4kjfae7i
|
89
Scripts/Src/ChineseChess/CCBoard.cs
Normal file
@ -0,0 +1,89 @@
|
||||
using System.Collections;
|
||||
using static ChineseChess.ChessCore;
|
||||
using Vector2I = Vector.Vector2I;
|
||||
|
||||
namespace ChineseChess;
|
||||
public interface ICCBoardOn : IBoard.IBoardOn {
|
||||
void OnSteps(object self, int oldSteps) {}
|
||||
}
|
||||
|
||||
public class CCBoard(ICCBoardOn? on = null) : AbstractBoard(9, 10, on: on) {
|
||||
private int steps = 0;
|
||||
protected new ICCBoardOn? on = on;
|
||||
// public virtual IPieceOn? On { get => on; set => on = value; }
|
||||
public new ICCBoardOn? On { get => on; set {
|
||||
on = value; base.on = value;} }
|
||||
|
||||
public int Steps {
|
||||
get => steps;
|
||||
protected set {
|
||||
if (steps != value) {
|
||||
var oldSteps = steps;
|
||||
steps = value;
|
||||
on?.OnSteps(this, oldSteps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddRecord(IPiece? From, IPiece? To, Vector2I FromPos, Vector2I ToPos) {
|
||||
base.AddRecord(From, To, FromPos, ToPos);
|
||||
Steps += 1;
|
||||
}
|
||||
|
||||
public override void UndoRecord() {
|
||||
base.UndoRecord();
|
||||
if (Steps > 0) Steps -= 1;
|
||||
}
|
||||
|
||||
public (ArrayList, ArrayList) InitGame() {
|
||||
Steps = 0;
|
||||
ArrayList blackPart = InitOnePartPieces(TurnsSideType.Black, [
|
||||
new CCChariot (this, TurnsSideType.Black, new Vector2I( 4, 0)),
|
||||
new CCHorse (this, TurnsSideType.Black, new Vector2I( 3, 0)),
|
||||
new CCElephant(this, TurnsSideType.Black, new Vector2I( 2, 0)),
|
||||
new CCAdvisor (this, TurnsSideType.Black, new Vector2I( 1, 0)),
|
||||
new CCGeneral (this, TurnsSideType.Black, new Vector2I( 0, 0)),
|
||||
new CCAdvisor (this, TurnsSideType.Black, new Vector2I(-1, 0)),
|
||||
new CCElephant(this, TurnsSideType.Black, new Vector2I(-2, 0)),
|
||||
new CCHorse (this, TurnsSideType.Black, new Vector2I(-3, 0)),
|
||||
new CCChariot (this, TurnsSideType.Black, new Vector2I(-4, 0)),
|
||||
new CCCannon (this, TurnsSideType.Black, new Vector2I( 3, 2)),
|
||||
new CCCannon (this, TurnsSideType.Black, new Vector2I(-3, 2)),
|
||||
new CCPawn (this, TurnsSideType.Black, new Vector2I(-4, 3)),
|
||||
new CCPawn (this, TurnsSideType.Black, new Vector2I(-2, 3)),
|
||||
new CCPawn (this, TurnsSideType.Black, new Vector2I( 0, 3)),
|
||||
new CCPawn (this, TurnsSideType.Black, new Vector2I( 2, 3)),
|
||||
new CCPawn (this, TurnsSideType.Black, new Vector2I( 4, 3)),
|
||||
]);
|
||||
|
||||
ArrayList redPart = InitOnePartPieces(TurnsSideType.Red, [
|
||||
new CCChariot (this, TurnsSideType.Red, new Vector2I( 4, 0)),
|
||||
new CCHorse (this, TurnsSideType.Red, new Vector2I( 3, 0)),
|
||||
new CCElephant(this, TurnsSideType.Red, new Vector2I( 2, 0)),
|
||||
new CCAdvisor (this, TurnsSideType.Red, new Vector2I( 1, 0)),
|
||||
new CCGeneral (this, TurnsSideType.Red, new Vector2I( 0, 0)),
|
||||
new CCAdvisor (this, TurnsSideType.Red, new Vector2I(-1, 0)),
|
||||
new CCElephant(this, TurnsSideType.Red, new Vector2I(-2, 0)),
|
||||
new CCHorse (this, TurnsSideType.Red, new Vector2I(-3, 0)),
|
||||
new CCChariot (this, TurnsSideType.Red, new Vector2I(-4, 0)),
|
||||
new CCCannon (this, TurnsSideType.Red, new Vector2I( 3, 2)),
|
||||
new CCCannon (this, TurnsSideType.Red, new Vector2I(-3, 2)),
|
||||
new CCPawn (this, TurnsSideType.Red, new Vector2I(-4, 3)),
|
||||
new CCPawn (this, TurnsSideType.Red, new Vector2I(-2, 3)),
|
||||
new CCPawn (this, TurnsSideType.Red, new Vector2I( 0, 3)),
|
||||
new CCPawn (this, TurnsSideType.Red, new Vector2I( 2, 3)),
|
||||
new CCPawn (this, TurnsSideType.Red, new Vector2I( 4, 3)),
|
||||
]);
|
||||
|
||||
return (blackPart, redPart);
|
||||
}
|
||||
|
||||
private ArrayList InitOnePartPieces(TurnsSideType side, CCPiece[] pieces) {
|
||||
ArrayList list = [];
|
||||
foreach (var piece in pieces) {
|
||||
list.Add(piece);
|
||||
InsertPiece(piece, piece.Pos);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
1
Scripts/Src/ChineseChess/CCBoard.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dpcteo12eebjn
|
119
Scripts/Src/ChineseChess/CCMain.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using Vector2 = Vector.Vector2I;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using static IBoard.IBoardOn;
|
||||
|
||||
namespace ChineseChess;
|
||||
|
||||
public 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 CCBoard board;
|
||||
private readonly Player playerSelf;
|
||||
private readonly Player playerOpponent;
|
||||
// public EventHandler<IBoard.MoveEventArgs> OnMove;
|
||||
public ChessCore(Mode mode, TurnsSideType selfSide, ICCBoardOn? boardOn = null) {
|
||||
this.selfSide = selfSide;
|
||||
board = new(boardOn);
|
||||
|
||||
playerSelf = new(board, Player.PlayerType.Human);
|
||||
playerOpponent = new(board, Player.PlayerType.Human);
|
||||
|
||||
void func(object? _self, MoveEventArgs record) {
|
||||
// 防止 Undo 时 Selected Clear 出现 Null Pointer Exception
|
||||
playerSelf.SelectedClear();
|
||||
playerOpponent.SelectedClear();
|
||||
|
||||
// TODO FIXME it can be simple
|
||||
if (record.From is null || record.To is null) {
|
||||
return;
|
||||
}
|
||||
|
||||
IPiece? from = record.From is not null ? board.GetPiece(record.From) : null;
|
||||
IPiece? to = record.To is not null ? board.GetPiece(record.To) : null;
|
||||
board.AddRecord(from, to, record.From ?? new(), record.To ?? new());
|
||||
}
|
||||
playerSelf.OnMove += func;
|
||||
playerOpponent.OnMove += func;
|
||||
switch (mode) {
|
||||
case Mode.SingleMode:
|
||||
break;
|
||||
case Mode.MultiMode:
|
||||
break;
|
||||
default:
|
||||
case Mode.DebugMode:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
public void Init() {
|
||||
(ArrayList blackPart, ArrayList redPart) = board.InitGame();
|
||||
if (selfSide == TurnsSideType.Red) {
|
||||
playerSelf.SetAllowedPieces(redPart);
|
||||
playerOpponent.SetAllowedPieces(blackPart);
|
||||
} else {
|
||||
playerSelf.SetAllowedPieces(blackPart);
|
||||
playerOpponent.SetAllowedPieces(redPart);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPosClicked(Vector2 pos, PlayerSideType clickedSide = PlayerSideType.Any) {
|
||||
if (GetTurnsType() == 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;
|
||||
}
|
||||
}
|
||||
|
||||
public TurnsSideType GetTurnsType() {
|
||||
sideType = board.Steps % 2 == 0 ? TurnsSideType.Red : TurnsSideType.Black;
|
||||
return sideType;
|
||||
}
|
||||
|
||||
public void Undo() {
|
||||
playerSelf.SelectedClear();
|
||||
playerOpponent.SelectedClear();
|
||||
board.UndoRecord();
|
||||
}
|
||||
|
||||
public void ReInit() {
|
||||
playerSelf.SelectedClear();
|
||||
playerOpponent.SelectedClear();
|
||||
board.Clear(true);
|
||||
Init();
|
||||
}
|
||||
}
|
1
Scripts/Src/ChineseChess/CCMain.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://sgx62hxlp6fr
|
85
Scripts/Src/ChineseChess/CCPiece.cs
Normal file
@ -0,0 +1,85 @@
|
||||
namespace ChineseChess;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Vector;
|
||||
using static ChineseChess.ChessCore;
|
||||
|
||||
public class CCPiece : AbstractPiece {
|
||||
public string CNName { get; protected set; } = "unknown";
|
||||
public TurnsSideType TurnsSide { get; }
|
||||
protected CCBoard board;
|
||||
protected Vector2I localPos = new();
|
||||
|
||||
static readonly Trans2DI transRedGlobal2Local =
|
||||
new(new Vector2I(1, 0), new Vector2I(0, -1), new Vector2I(-4, 9));
|
||||
static readonly Trans2DI transBlackGlobal2Local =
|
||||
new(new Vector2I(-1, 0), new Vector2I(0, 1), new Vector2I(4, 0));
|
||||
public CCPiece(CCBoard? board = null, TurnsSideType turnsSide = TurnsSideType.Red,
|
||||
string name = "", Vector2I? pos = null) : base(name) {
|
||||
this.board = board ?? new();
|
||||
TurnsSide = turnsSide;
|
||||
Pos = pos is not null ? Local2Global(pos) : Vector2I.Zero;
|
||||
}
|
||||
|
||||
public override Vector2I Pos {
|
||||
get => base.Pos; set {
|
||||
base.Pos = value;
|
||||
localPos = Global2Local(Pos);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanMove(Vector2I to) {
|
||||
return CanMoveAllPos().Any(item => item == to);
|
||||
}
|
||||
|
||||
protected Vector2I Local2Global(in Vector2I pos) {
|
||||
return TurnsSide == TurnsSideType.Red ? (pos * transRedGlobal2Local) : (pos * transBlackGlobal2Local);
|
||||
}
|
||||
|
||||
protected Vector2I Global2Local(in Vector2I pos) {
|
||||
return TurnsSide == TurnsSideType.Red ? (transRedGlobal2Local * pos) : (transBlackGlobal2Local * pos);
|
||||
}
|
||||
|
||||
protected CCPiece? GetCCPieceLocal(in Vector2I pos) {
|
||||
return (CCPiece?)board.GetPiece(Local2Global(pos));
|
||||
}
|
||||
|
||||
public virtual List<Vector2I> CanMoveAllPosSelf() {
|
||||
return [];
|
||||
}
|
||||
|
||||
public IEnumerable<Vector2I> CanMoveAllPosLocal() {
|
||||
var self = CanMoveAllPosSelf().Select(item => item + localPos);
|
||||
var ret = self.Where(item => {
|
||||
CCPiece? piece = GetCCPieceLocal(item);
|
||||
bool ret = piece is null || piece.TurnsSide != TurnsSide;
|
||||
// Console.WriteLine($"{item} can move: {ret}");
|
||||
return ret;
|
||||
});
|
||||
|
||||
// Console.WriteLine("localPos: {0}", localPos);
|
||||
// Console.WriteLine("CanMoveAllPosSelf: {0}", string.Join(",", self));
|
||||
// Console.WriteLine("CanMoveAllPosLocal: {0}", string.Join(",", ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public IEnumerable<Vector2I> CanMoveAllPos() {
|
||||
var ret = CanMoveAllPosLocal()
|
||||
.Select(item => Local2Global(item));
|
||||
// Console.WriteLine("CanMoveAllPos: {0}", string.Join(",", ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected bool IsPosOutOfRangeLocal(Vector2I pos) {
|
||||
return board.IsPosOutOfRange(Local2Global(pos));
|
||||
}
|
||||
|
||||
protected (CCPiece?, Vector2I) GetRecursivePieceLocal(Vector2I origin, Vector2I pos) {
|
||||
Vector2I with = origin + pos;
|
||||
while (!IsPosOutOfRangeLocal(with) && GetCCPieceLocal(with) == null) {
|
||||
with += pos;
|
||||
}
|
||||
return (GetCCPieceLocal(with), with);
|
||||
}
|
||||
}
|
1
Scripts/Src/ChineseChess/CCPiece.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://b6ajoxcxs66n1
|
122
Scripts/Src/ChineseChess/CCPlayer.cs
Normal file
@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Vector2I = Vector.Vector2I;
|
||||
|
||||
namespace ChineseChess;
|
||||
using static IBoard.IBoardOn;
|
||||
public class Player {
|
||||
private readonly CCBoard board;
|
||||
private readonly SelectedPiece selectedNode;
|
||||
|
||||
public EventHandler<MoveEventArgs>? OnMove;
|
||||
public bool CanMove { get; set; } = true;
|
||||
|
||||
public enum PlayerType {
|
||||
Human,
|
||||
AI
|
||||
}
|
||||
|
||||
public Player(CCBoard board, PlayerType type = PlayerType.Human) {
|
||||
this.board = board;
|
||||
this.selectedNode = new SelectedPiece(board);
|
||||
}
|
||||
|
||||
public void HandleBoardPosClick(Vector2I clickPos) {
|
||||
if (board.IsPosOutOfRange(clickPos)) return;
|
||||
// Console.WriteLine($"VirtualBoard {clickPos} clicked");
|
||||
IPiece? 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);
|
||||
if (CanMove) MoveAndRecord(clickPos, selectedNode.GetPos());
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveAndRecord(Vector2I toPos, Vector2I fromPos) {
|
||||
// GD.Print($"{fromPos} move to {toPos}");
|
||||
IPiece? toChess = board.GetPiece(toPos);
|
||||
IPiece? fromChess = board.GetPiece(fromPos);
|
||||
if (fromChess != null) fromChess.IsSelected = false;
|
||||
else return;
|
||||
|
||||
selectedNode.Clear();
|
||||
if (!fromChess.CanMove(toPos)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// MUST BE THERE !!! 防止删除节点后在启动回调导致错误
|
||||
OnMove?.Invoke(this, new MoveEventArgs
|
||||
(fromChess, fromPos, toPos));
|
||||
|
||||
if (toChess != null) {
|
||||
board.RemovePiece(toPos);
|
||||
}
|
||||
board.MovePiece(fromPos, toPos);
|
||||
|
||||
selectedNode.Clear();
|
||||
}
|
||||
|
||||
public void SelectedClear() {
|
||||
selectedNode.Clear();
|
||||
}
|
||||
|
||||
public void SetAllowedPieces(ArrayList allowedPieces) {
|
||||
selectedNode.allowedPieces = allowedPieces;
|
||||
}
|
||||
|
||||
private class SelectedPiece {
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
private Vector2I selectedNodePos = Vector2I.MaxValue;
|
||||
private IPiece? piece = null;
|
||||
private readonly CCBoard board;
|
||||
public ArrayList? allowedPieces = null;
|
||||
|
||||
public SelectedPiece(CCBoard board) {
|
||||
this.board = board;
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
if (selectedNodePos != Vector2I.MaxValue) {
|
||||
selectedNodePos = Vector2I.MaxValue;
|
||||
if (piece != null)
|
||||
piece.IsSelected = false;
|
||||
}
|
||||
// Console.WriteLine("SelectedPiece.Clear {0}", piece);
|
||||
}
|
||||
|
||||
public void SetPos(Vector2I pos) {
|
||||
piece = board.GetPiece(pos);
|
||||
if (allowedPieces != null && allowedPieces.Contains(piece) == false) {
|
||||
return;
|
||||
}
|
||||
selectedNodePos = pos;
|
||||
if (piece == null)
|
||||
return;
|
||||
piece.IsSelected = true;
|
||||
Console.WriteLine("SelectedPiece.SetPos {0}", piece);
|
||||
}
|
||||
|
||||
public IPiece? GetPiece() {
|
||||
return piece;
|
||||
}
|
||||
|
||||
public Vector2I GetPos() {
|
||||
return selectedNodePos;
|
||||
}
|
||||
|
||||
public bool HasSelected() {
|
||||
return selectedNodePos != Vector2I.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
1
Scripts/Src/ChineseChess/CCPlayer.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://blpqjd37p3r38
|
250
Scripts/Src/ChineseChess/CCTypes.cs
Normal file
@ -0,0 +1,250 @@
|
||||
using System.Collections.Generic;
|
||||
using static ChineseChess.ChessCore;
|
||||
using Vector2I = Vector.Vector2I;
|
||||
|
||||
namespace ChineseChess;
|
||||
public class CCGeneral : CCPiece {
|
||||
public CCGeneral(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null)
|
||||
: base(board, turnsSide, name : "General", pos) {
|
||||
if (turnsSide == TurnsSideType.Red) {
|
||||
CNName = "帅";
|
||||
} else {
|
||||
CNName = "将";
|
||||
}
|
||||
}
|
||||
|
||||
public override List<Vector2I> CanMoveAllPosSelf() {
|
||||
List<Vector2I> list = [
|
||||
new(1, 0),
|
||||
new(-1, 0),
|
||||
new(0, 1),
|
||||
new(0, -1),
|
||||
];
|
||||
|
||||
// 移除不符合条件的元素
|
||||
list.RemoveAll(item =>
|
||||
localPos.X + item.X > 1 || localPos.X + item.X < -1 ||
|
||||
localPos.Y + item.Y > 2 || localPos.Y + item.Y < 0);
|
||||
|
||||
(var piece, Vector2I pos) = GetRecursivePieceLocal(localPos, new(0, 1));
|
||||
if (piece is CCGeneral) {
|
||||
list.Add(pos);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public class CCAdvisor : CCPiece {
|
||||
public CCAdvisor(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null)
|
||||
: base(board, turnsSide, name : "Advisor", pos) {
|
||||
if (turnsSide == TurnsSideType.Red) {
|
||||
CNName = "仕";
|
||||
} else {
|
||||
CNName = "士";
|
||||
}
|
||||
}
|
||||
|
||||
public override List<Vector2I> CanMoveAllPosSelf() {
|
||||
List<Vector2I> list = [
|
||||
new(1, 1),
|
||||
new(-1, 1),
|
||||
new(1, -1),
|
||||
new(-1, -1),
|
||||
];
|
||||
|
||||
// 移除不符合条件的元素
|
||||
list.RemoveAll(item =>
|
||||
localPos.X + item.X > 1 || localPos.X + item.X < -1 ||
|
||||
localPos.Y + item.Y > 2 || localPos.Y + item.Y < 0);
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public class CCElephant : CCPiece {
|
||||
public CCElephant(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null)
|
||||
: base(board, turnsSide, name : "Bishop", pos) {
|
||||
if (turnsSide == TurnsSideType.Red) {
|
||||
CNName = "相";
|
||||
} else {
|
||||
CNName = "象";
|
||||
}
|
||||
}
|
||||
|
||||
public override List<Vector2I> CanMoveAllPosSelf() {
|
||||
List<Vector2I> list = [
|
||||
new(2, 2),
|
||||
new(-2, 2),
|
||||
new(2, -2),
|
||||
new(-2, -2),
|
||||
];
|
||||
|
||||
list.RemoveAll(item => IsPosOutOfRangeLocal(localPos + item));
|
||||
// 移除不符合条件的元素
|
||||
list.RemoveAll(item => localPos.Y + item.Y < 0 || localPos.Y + item.Y > 4 ||
|
||||
GetCCPieceLocal(new(localPos.X + item.X / 2, localPos.Y + item.Y / 2)) is not null);
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public class CCHorse : CCPiece {
|
||||
public CCHorse(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null)
|
||||
: base(board, turnsSide, name : "Horse", pos) {
|
||||
if (turnsSide == TurnsSideType.Red) {
|
||||
CNName = "馬";
|
||||
} else {
|
||||
CNName = "马";
|
||||
}
|
||||
}
|
||||
|
||||
public override List<Vector2I> CanMoveAllPosSelf() {
|
||||
List<Vector2I> list = [
|
||||
new Vector2I(1, 2),
|
||||
new Vector2I(1, -2),
|
||||
new Vector2I(2, 1),
|
||||
new Vector2I(2, -1),
|
||||
new Vector2I(-1, -2),
|
||||
new Vector2I(-1, 2),
|
||||
new Vector2I(-2, -1),
|
||||
new Vector2I(-2, 1),
|
||||
];
|
||||
|
||||
list.RemoveAll(item => IsPosOutOfRangeLocal(localPos + item));
|
||||
list.RemoveAll(item => {
|
||||
Vector2I pos = new(localPos);
|
||||
if (item.X == 2) {
|
||||
pos.X += 1;
|
||||
} else if (item.X == -2) {
|
||||
pos.X -= 1;
|
||||
} else if (item.Y == 2) {
|
||||
pos.Y += 1;
|
||||
} else if (item.Y == -2) {
|
||||
pos.Y -= 1;
|
||||
}
|
||||
return GetCCPieceLocal(pos) is not null;
|
||||
});
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public class CCChariot : CCPiece {
|
||||
public CCChariot(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null)
|
||||
: base(board, turnsSide, name : "Chariot", pos) {
|
||||
if (turnsSide == TurnsSideType.Red) {
|
||||
CNName = "車";
|
||||
} else {
|
||||
CNName = "车";
|
||||
}
|
||||
}
|
||||
|
||||
public override List<Vector2I> CanMoveAllPosSelf() {
|
||||
List<Vector2I> list = [];
|
||||
|
||||
void func(Vector2I added) {
|
||||
Vector2I ptr = new(localPos);
|
||||
while (true) {
|
||||
ptr += added;
|
||||
if (IsPosOutOfRangeLocal(ptr)) {
|
||||
break;
|
||||
}
|
||||
if (GetCCPieceLocal(ptr) != null) {
|
||||
list.Add(ptr - localPos);
|
||||
break;
|
||||
}
|
||||
list.Add(ptr - localPos);
|
||||
}
|
||||
}
|
||||
|
||||
func(Vector2I.Up);
|
||||
func(Vector2I.Down);
|
||||
func(Vector2I.Left);
|
||||
func(Vector2I.Right);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public class CCCannon : CCPiece {
|
||||
public CCCannon(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null)
|
||||
: base(board, turnsSide, name : "Cannon", pos) {
|
||||
if (turnsSide == TurnsSideType.Red) {
|
||||
CNName = "砲";
|
||||
} else {
|
||||
CNName = "炮";
|
||||
}
|
||||
}
|
||||
|
||||
public override List<Vector2I> CanMoveAllPosSelf() {
|
||||
List<Vector2I> list = [];
|
||||
|
||||
void func(Vector2I added) {
|
||||
Vector2I ptr = new(localPos);
|
||||
bool flag = true;
|
||||
while (true) {
|
||||
ptr += added;
|
||||
if (IsPosOutOfRangeLocal(ptr)) {
|
||||
break;
|
||||
}
|
||||
if (GetCCPieceLocal(ptr) != null) {
|
||||
if (flag) {
|
||||
flag = false;
|
||||
} else {
|
||||
list.Add(ptr - localPos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag) list.Add(ptr - localPos);
|
||||
}
|
||||
}
|
||||
|
||||
func(Vector2I.Up);
|
||||
func(Vector2I.Down);
|
||||
func(Vector2I.Left);
|
||||
func(Vector2I.Right);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public class CCPawn : CCPiece {
|
||||
public CCPawn(CCBoard board, TurnsSideType turnsSide = TurnsSideType.Red, Vector2I? pos = null)
|
||||
: base(board, turnsSide, name : "Pawn", pos) {
|
||||
if (turnsSide == TurnsSideType.Red) {
|
||||
CNName = "兵";
|
||||
} else {
|
||||
CNName = "卒";
|
||||
}
|
||||
}
|
||||
|
||||
public override List<Vector2I> CanMoveAllPosSelf() {
|
||||
List<Vector2I> list = [
|
||||
new(0, 1),
|
||||
new(1, 0),
|
||||
new(-1, 0),
|
||||
];
|
||||
|
||||
list.RemoveAll(item => IsPosOutOfRangeLocal(localPos + item));
|
||||
list.RemoveAll(item => localPos.Y <= 4 && item != new Vector2I(0, 1));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
// 帅/将 (General) - 代表双方的最高统帅。
|
||||
// 子类名:ChessGeneral
|
||||
|
||||
// 仕/士 (Advisor) - 保护帅/将的近身侍卫。
|
||||
// 子类名:ChessAdvisor
|
||||
|
||||
// 相/象 (Elephant) - 行动受限,走田字格,不能过河。
|
||||
// 子类名:ChessElephant
|
||||
|
||||
// 車/车 (Chariot) - 横竖移动,威力巨大。
|
||||
// 子类名:ChessChariot
|
||||
|
||||
// 馬/马 (Horse) - 走日字形,跳跃式移动。
|
||||
// 子类名:ChessHorse
|
||||
|
||||
// 砲/炮 (Cannon) - 需要隔子才能吃子,直线移动。
|
||||
// 子类名:ChessCannon
|
||||
|
||||
// 兵/卒 (Pawn) - 最基础的棋子,过河后可横移。
|
||||
// 子类名:ChessPawn
|
1
Scripts/Src/ChineseChess/CCTypes.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://mv1sbsok7q3k
|
33
Scripts/Src/IBoard.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Godot;
|
||||
using Vector2I = Vector.Vector2I;
|
||||
|
||||
|
||||
public interface IBoard {
|
||||
public interface IBoardOn {
|
||||
void OnInsert(object self, IPiece piece) {}
|
||||
void OnRemove(object self, IPiece piece) {}
|
||||
void OnMove(object self, MoveEventArgs args) {}
|
||||
|
||||
void OnAddRecord(object self, MoveRecord record) {}
|
||||
void OnUndoRecord(object self, MoveRecord record) {}
|
||||
void OnSetPieceInteral(object self, SetPieceEventArgs args) {}
|
||||
record SetPieceEventArgs(IPiece? OldPiece, IPiece? NewPiece, Vector2I Pos);
|
||||
record MoveEventArgs(IPiece? Piece, Vector2I From, Vector2I To);
|
||||
}
|
||||
|
||||
public IBoardOn? On { get; protected set; }
|
||||
public int Rows { get; }
|
||||
public int Cols { get; }
|
||||
|
||||
bool IsPosOutOfRange(Vector2I pos);
|
||||
IPiece? GetPiece(Vector2I pos);
|
||||
IPiece? SetPiece(IPiece? piece, Vector2I pos);
|
||||
bool InsertPiece(IPiece piece, Vector2I pos);
|
||||
bool MovePiece(Vector2I from, Vector2I to);
|
||||
IPiece? RemovePiece(Vector2I pos);
|
||||
void Clear(bool clearRecords);
|
||||
void AddRecord(IPiece? From, IPiece? To, Vector2I FromPos, Vector2I ToPos);
|
||||
void UndoRecord();
|
||||
record MoveRecord(IPiece? From, IPiece? To, Vector2I FromPos, Vector2I ToPos);
|
||||
}
|
1
Scripts/Src/IBoard.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://cgbntdvka6y2f
|
22
Scripts/Src/IPiece.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Vector2I = Vector.Vector2I;
|
||||
|
||||
|
||||
public interface IPiece {
|
||||
public interface IPieceOn {
|
||||
void OnPos(object self, Vector2I oldPos) {}
|
||||
void OnMove(object self, Vector2I oldPos) {}
|
||||
void OnSelected(object self, bool oldIsSelected) {}
|
||||
void OnName(object self, string oldName) {}
|
||||
}
|
||||
|
||||
IPieceOn? On { get; protected set; }
|
||||
Vector2I Pos { get; set; }
|
||||
string Name { get; set; }
|
||||
bool IsSelected { get; set; }
|
||||
Dictionary<string, object> Data { get; set; }
|
||||
|
||||
bool CanMove(Vector2I to);
|
||||
bool Move(Vector2I pos);
|
||||
}
|
1
Scripts/Src/IPiece.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dr1tx5gmpvy2h
|
133
Scripts/Src/Vector.cs
Normal file
@ -0,0 +1,133 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Vector;
|
||||
|
||||
public class Vector2I {
|
||||
public Vector2I() {
|
||||
X = 0;
|
||||
Y = 0;
|
||||
}
|
||||
|
||||
public Vector2I(int x, int y) {
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public Vector2I(Vector2I other) {
|
||||
X = other.X;
|
||||
Y = other.Y;
|
||||
}
|
||||
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
|
||||
public static bool operator ==(Vector2I a, Vector2I b) {
|
||||
return a?.X == b?.X && a?.Y == b?.Y;
|
||||
}
|
||||
|
||||
public static bool operator !=(Vector2I a, Vector2I b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public static Vector2I operator +(Vector2I left, Vector2I right) {
|
||||
return new (
|
||||
left.X + right.X,
|
||||
left.Y + right.Y);
|
||||
}
|
||||
|
||||
public static Vector2I operator -(Vector2I left, Vector2I right) {
|
||||
return new (
|
||||
left.X - right.X,
|
||||
left.Y - right.Y);
|
||||
}
|
||||
|
||||
public static Vector2I operator *(Vector2I left, Vector2I right) {
|
||||
return new (
|
||||
left.X * right.X,
|
||||
left.Y * right.Y);
|
||||
}
|
||||
|
||||
public int Dot(Vector2I with) {
|
||||
return X * with.X + Y * with.Y;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj) {
|
||||
if (obj is Vector2I other) {
|
||||
return this == other;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return System.HashCode.Combine(X, Y);
|
||||
}
|
||||
|
||||
public static readonly Vector2I MaxValue = new(int.MaxValue, int.MinValue);
|
||||
public static readonly Vector2I MinValue = new (int.MinValue, int.MaxValue);
|
||||
public static readonly Vector2I Zero = new(0, 0);
|
||||
|
||||
public static readonly Vector2I Up = new(0, 1);
|
||||
public static readonly Vector2I Down = new(0, -1);
|
||||
public static readonly Vector2I Left = new(-1, 0);
|
||||
public static readonly Vector2I Right = new(1, 0);
|
||||
|
||||
public override string ToString() {
|
||||
return $"({X},{Y})";
|
||||
}
|
||||
}
|
||||
|
||||
public class Trans2DI {
|
||||
public Vector2I XAxis { get; set; } // x axis , first column
|
||||
public Vector2I YAxis { get; set; } // y axis , second column
|
||||
public Vector2I Origin { get; set; } // origin point
|
||||
public Trans2DI() {
|
||||
XAxis = new Vector2I(1, 0);
|
||||
YAxis = new Vector2I(0, 1);
|
||||
Origin = new Vector2I(0, 0);
|
||||
}
|
||||
|
||||
public Trans2DI(Vector2I xAxis, Vector2I yAxis, Vector2I origin) {
|
||||
XAxis = xAxis;
|
||||
YAxis = yAxis;
|
||||
Origin = origin;
|
||||
}
|
||||
|
||||
public Trans2DI(Trans2DI other) {
|
||||
XAxis = other.XAxis;
|
||||
YAxis = other.YAxis;
|
||||
Origin = other.Origin;
|
||||
}
|
||||
|
||||
public Trans2DI(int xx, int xy, int yx, int yy, int ox, int oy) {
|
||||
XAxis = new Vector2I(xx, xy);
|
||||
YAxis = new Vector2I(yx, yy);
|
||||
Origin = new Vector2I(ox, oy);
|
||||
}
|
||||
|
||||
public static Trans2DI Identity => new();
|
||||
|
||||
/**
|
||||
* X.x Y.x * v.x + O.x = X.x * v.x + Y.x * v.y + O.x
|
||||
* X.y Y.y v.y O.y X.y * v.x + Y.y * v.y + O.y
|
||||
*/
|
||||
public static Vector2I operator *(in Trans2DI trans, in Vector2I vec) {
|
||||
return new Vector2I(
|
||||
trans.XAxis.X * vec.X + trans.XAxis.Y * vec.Y,
|
||||
trans.YAxis.X * vec.X + trans.YAxis.Y * vec.Y) + trans.Origin;
|
||||
}
|
||||
|
||||
public static Vector2I operator *(in Vector2I vec, in Trans2DI trans) {
|
||||
Vector2I with = vec - trans.Origin;
|
||||
return new Vector2I(
|
||||
trans.XAxis.X * with.X + trans.XAxis.Y * with.Y,
|
||||
trans.YAxis.X * with.X + trans.YAxis.Y * with.Y);
|
||||
}
|
||||
|
||||
public static Trans2DI operator *(Trans2DI a, Trans2DI b) {
|
||||
return new Trans2DI();
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return $"[{XAxis}, {YAxis}, {Origin}]";
|
||||
}
|
||||
}
|
1
Scripts/Src/Vector.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://btjgh7imdrha1
|
58
Scripts/Utilities/GodotConfigManager.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
class GodotConfigManager {
|
||||
private readonly string ConfigFilePath;
|
||||
private readonly ConfigFile config = new();
|
||||
private readonly bool successful;
|
||||
|
||||
public GodotConfigManager(string ConfigFilePath) {
|
||||
this.ConfigFilePath = ConfigFilePath;
|
||||
|
||||
Error err = config.Load(ConfigFilePath);
|
||||
if (err == Error.Ok) {
|
||||
successful = true;
|
||||
} else {
|
||||
successful = false;
|
||||
GD.PrintErr("config.Load", err);
|
||||
// OS.Alert("配置文件加载失败!", "错误");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadConfig(string SessionName,
|
||||
Dictionary<string, Variant> data) {
|
||||
|
||||
// 如果文件没有加载,忽略它。
|
||||
if (!successful) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 迭代所有小节。
|
||||
foreach (string session in config.GetSections()) {
|
||||
if (session == SessionName) {
|
||||
foreach (var key in config.GetSectionKeys(session)) {
|
||||
if (data.ContainsKey(key)) {
|
||||
data[key] = config.GetValue(session, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveConfig(string SessionName, Dictionary<string, Variant> data)
|
||||
{
|
||||
// 将 GlobalConfig 中的键值对写入配置文件
|
||||
foreach (var key in data.Keys)
|
||||
{
|
||||
GD.Print(data[key]);
|
||||
|
||||
config.SetValue(SessionName, key, data[key]);
|
||||
}
|
||||
|
||||
// 保存配置文件
|
||||
if (config.Save(ConfigFilePath) != Error.Ok) {
|
||||
OS.Alert("配置文件保存失败!", "错误");
|
||||
}
|
||||
}
|
||||
}
|
1
Scripts/Utilities/GodotConfigManager.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://qfml5c031hb0
|
17
Scripts/Utilities/IConfig.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
public interface IConfigManager {
|
||||
void SetFilePath(string filePath);
|
||||
void SetDefault(Dictionary<string, object> defalutConfig);
|
||||
T GetValue<T>(string key);
|
||||
void SetValue<T>(string key, [NotNull]T value) {
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
SetValue(key, (object?)value);
|
||||
}
|
||||
void SetValue(string key, [NotNull]object? value);
|
||||
bool HasKey(string key);
|
||||
void SaveToFile();
|
||||
void LoadFromFile();
|
||||
}
|
1
Scripts/Utilities/IConfig.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://b8jvplvi4a7iv
|
53
Scripts/Utilities/JsonConfig.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
|
||||
public class JsonConfigManager : IConfigManager {
|
||||
private string? filePath;
|
||||
private Dictionary<string, object> config = [];
|
||||
private Dictionary<string, object>? defaultConfig;
|
||||
|
||||
public T GetValue<T>(string key) {
|
||||
if (config.TryGetValue(key, out object? val)) {
|
||||
if (val is T t) {
|
||||
return t;
|
||||
} else if (val is JsonElement element) {
|
||||
return element.Deserialize<T>() ??
|
||||
throw new InvalidCastException($"无法将键'{key}'的值转换为类型{typeof(T).Name}");
|
||||
}
|
||||
}
|
||||
if (
|
||||
defaultConfig != null &&
|
||||
defaultConfig.TryGetValue(key, out object? dval) &&
|
||||
dval is T ret) {
|
||||
return ret;
|
||||
}
|
||||
throw new KeyNotFoundException($"Key '{key}' not found in config.");
|
||||
}
|
||||
|
||||
public bool HasKey(string key) => config.ContainsKey(key);
|
||||
public void SaveToFile() {
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(filePath);
|
||||
File.WriteAllText(filePath, JsonSerializer.Serialize(config));
|
||||
}
|
||||
|
||||
public void LoadFromFile() {
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(filePath);
|
||||
if (!File.Exists(filePath)) {
|
||||
return;
|
||||
}
|
||||
config = JsonSerializer.Deserialize
|
||||
<Dictionary<string, object>>(File.ReadAllText(filePath)) ?? [];
|
||||
}
|
||||
|
||||
public void SetDefault(Dictionary<string, object> defaultConfig) => this.defaultConfig = defaultConfig;
|
||||
|
||||
public void SetFilePath(string filePath) => this.filePath = filePath;
|
||||
|
||||
public void SetValue(string key, [NotNull]object? value) {
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
config[key] = value;
|
||||
}
|
||||
}
|
1
Scripts/Utilities/JsonConfig.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://ddvrwflje2x87
|
0
Test/.gdignore
Normal file
31
Test/Test.csproj
Normal file
@ -0,0 +1,31 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.14.0" />
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.9.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="NUnit.Framework" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\*.csproj" />
|
||||
</ItemGroup>
|
||||
<!-- <ItemGroup>
|
||||
<Compile Include="..\Scripts\Src\*.cs" />
|
||||
</ItemGroup> -->
|
||||
|
||||
</Project>
|
16
Test/UnitTest1.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using Vector;
|
||||
|
||||
namespace Test;
|
||||
public class Tests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test1()
|
||||
{
|
||||
Assert.Pass();
|
||||
}
|
||||
}
|
277
Test/src/TestVector.cs
Normal file
@ -0,0 +1,277 @@
|
||||
using Vector;
|
||||
namespace Test.Vector;
|
||||
public class TestsVector2I {
|
||||
[SetUp]
|
||||
public void Setup() {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVector2I_Constructors() {
|
||||
// Arrange & Act
|
||||
var v1 = new Vector2I();
|
||||
var v2 = new Vector2I(1, 2);
|
||||
var v3 = new Vector2I(v2);
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(v1.X, Is.EqualTo(0));
|
||||
Assert.That(v1.Y, Is.EqualTo(0));
|
||||
Assert.That(v2.X, Is.EqualTo(1));
|
||||
Assert.That(v2.Y, Is.EqualTo(2));
|
||||
Assert.That(v3.X, Is.EqualTo(1));
|
||||
Assert.That(v3.Y, Is.EqualTo(2));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVector2I_Operators() {
|
||||
// Arrange
|
||||
var v1 = new Vector2I(1, 2);
|
||||
var v2 = new Vector2I(3, 4);
|
||||
|
||||
// Act
|
||||
var v3 = v1 + v2;
|
||||
var v4 = v1 - v2;
|
||||
var v5 = v1 * v2;
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(v3, Is.EqualTo(new Vector2I(4, 6)));
|
||||
Assert.That(v4, Is.EqualTo(new Vector2I(-2, -2)));
|
||||
Assert.That(v5, Is.EqualTo(new Vector2I(3, 8)));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVector2I_DotProduct() {
|
||||
// Arrange
|
||||
var v1 = new Vector2I(1, 2);
|
||||
var v2 = new Vector2I(3, 4);
|
||||
|
||||
// Act
|
||||
var dotProduct = v1.Dot(v2);
|
||||
|
||||
// Assert
|
||||
Assert.That(dotProduct, Is.EqualTo(11));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVector2I_ParameterModification() {
|
||||
// Arrange
|
||||
var v1 = new Vector2I(1, 2);
|
||||
var v2 = new Vector2I(3, 4);
|
||||
|
||||
// Act
|
||||
var v3 = v1 + v2;
|
||||
var v4 = v1 - v2;
|
||||
var v5 = v1 * v2;
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(v1, Is.EqualTo(new Vector2I(1, 2)), "v1 should not be modified");
|
||||
Assert.That(v2, Is.EqualTo(new Vector2I(3, 4)), "v2 should not be modified");
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVector2I_Equality() {
|
||||
// Arrange
|
||||
var v1 = new Vector2I(1, 2);
|
||||
var v2 = new Vector2I(1, 2);
|
||||
var v3 = new Vector2I(3, 4);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(v1, Is.EqualTo(v2));
|
||||
Assert.That(v1, Is.Not.EqualTo(v3));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVector2I_HashCode() {
|
||||
// Arrange
|
||||
var v1 = new Vector2I(1, 2);
|
||||
var v2 = new Vector2I(1, 2);
|
||||
var v3 = new Vector2I(3, 4);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(v1.GetHashCode(), Is.EqualTo(v2.GetHashCode()));
|
||||
Assert.That(v1.GetHashCode(), Is.Not.EqualTo(v3.GetHashCode()));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVector2I_BoundaryValues() {
|
||||
// Arrange
|
||||
var v1 = new Vector2I(0, 0);
|
||||
var v2 = new Vector2I(-1, -2);
|
||||
var v3 = new Vector2I(int.MaxValue, int.MaxValue);
|
||||
var v4 = new Vector2I(int.MinValue, int.MinValue);
|
||||
|
||||
// Act
|
||||
var v5 = v1 + v2;
|
||||
var v6 = v1 - v2;
|
||||
var v7 = v1 * v2;
|
||||
var v8 = v3 + v4;
|
||||
var v9 = v3 - v4;
|
||||
var v10 = v3 * v4;
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(v5, Is.EqualTo(new Vector2I(-1, -2)));
|
||||
Assert.That(v6, Is.EqualTo(new Vector2I(1, 2)));
|
||||
Assert.That(v7, Is.EqualTo(new Vector2I(0, 0)));
|
||||
|
||||
Assert.That(v8, Is.EqualTo(new Vector2I(-1, -1)));
|
||||
// Assert.That(v9, Is.EqualTo(new Vector2I(2 * int.MaxValue - 1, 2 * int.MaxValue - 1)));
|
||||
// Assert.That(v10, Is.EqualTo(new Vector2I(int.MaxValue * int.MinValue, int.MaxValue * int.MinValue)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class TestsTrans2DI {
|
||||
[SetUp]
|
||||
public void Setup() {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test1() {
|
||||
Assert.Pass();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVector2I_Constructors() {
|
||||
// Arrange & Act
|
||||
var v1 = new Vector2I();
|
||||
var v2 = new Vector2I(1, 2);
|
||||
var v3 = new Vector2I(v2);
|
||||
|
||||
Assert.Multiple(() => {
|
||||
// Assert
|
||||
Assert.That(v1.X, Is.EqualTo(0));
|
||||
Assert.That(v1.Y, Is.EqualTo(0));
|
||||
Assert.That(v2.X, Is.EqualTo(1));
|
||||
Assert.That(v2.Y, Is.EqualTo(2));
|
||||
Assert.That(v3.X, Is.EqualTo(1));
|
||||
Assert.That(v3.Y, Is.EqualTo(2));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVector2I_Operators() {
|
||||
// Arrange
|
||||
var v1 = new Vector2I(1, 2);
|
||||
var v2 = new Vector2I(3, 4);
|
||||
|
||||
// Act
|
||||
var v3 = v1 + v2;
|
||||
var v4 = v1 - v2;
|
||||
var v5 = v1 * v2;
|
||||
|
||||
Assert.Multiple(() => {
|
||||
// Assert
|
||||
Assert.That(v3, Is.EqualTo(new Vector2I(4, 6)));
|
||||
Assert.That(v4, Is.EqualTo(new Vector2I(-2, -2)));
|
||||
Assert.That(v5, Is.EqualTo(new Vector2I(3, 8)));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTrans2DI_Constructors() {
|
||||
// Arrange & Act
|
||||
var t1 = new Trans2DI();
|
||||
var t2 = new Trans2DI(new Vector2I(1, 0), new Vector2I(0, 1), new Vector2I(0, 0));
|
||||
var t3 = new Trans2DI(t2);
|
||||
var t4 = new Trans2DI(1, 0, 0, 1, 0, 0);
|
||||
|
||||
Assert.Multiple(() => {
|
||||
// Assert
|
||||
Assert.That(t1.XAxis, Is.EqualTo(new Vector2I(1, 0)));
|
||||
Assert.That(t1.YAxis, Is.EqualTo(new Vector2I(0, 1)));
|
||||
Assert.That(t1.Origin, Is.EqualTo(new Vector2I(0, 0)));
|
||||
|
||||
Assert.That(t2.XAxis, Is.EqualTo(new Vector2I(1, 0)));
|
||||
Assert.That(t2.YAxis, Is.EqualTo(new Vector2I(0, 1)));
|
||||
Assert.That(t2.Origin, Is.EqualTo(new Vector2I(0, 0)));
|
||||
|
||||
Assert.That(t3.XAxis, Is.EqualTo(new Vector2I(1, 0)));
|
||||
Assert.That(t3.YAxis, Is.EqualTo(new Vector2I(0, 1)));
|
||||
Assert.That(t3.Origin, Is.EqualTo(new Vector2I(0, 0)));
|
||||
|
||||
Assert.That(t4.XAxis, Is.EqualTo(new Vector2I(1, 0)));
|
||||
Assert.That(t4.YAxis, Is.EqualTo(new Vector2I(0, 1)));
|
||||
Assert.That(t4.Origin, Is.EqualTo(new Vector2I(0, 0)));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTrans2DI_Operators() {
|
||||
// Arrange
|
||||
var t1 = new Trans2DI(new Vector2I(1, 0), new Vector2I(0, 1), new Vector2I(1, 2));
|
||||
var v1 = new Vector2I(3, 4);
|
||||
|
||||
// Act
|
||||
var v2 = t1 * v1;
|
||||
var v3 = v1 * t1;
|
||||
|
||||
Assert.Multiple(() => {
|
||||
// Assert
|
||||
Assert.That(v2, Is.EqualTo(new Vector2I(4, 6)));
|
||||
Assert.That(v3, Is.EqualTo(new Vector2I(2, 2)));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTrans2DI_BoundaryValues() {
|
||||
// Arrange
|
||||
var t1 = new Trans2DI(new Vector2I(int.MaxValue, 0), new Vector2I(0, int.MaxValue), new Vector2I(0, 0));
|
||||
var t2 = new Trans2DI(new Vector2I(int.MinValue, 0), new Vector2I(0, int.MinValue), new Vector2I(0, 0));
|
||||
var v1 = new Vector2I(1, 1);
|
||||
|
||||
// Act
|
||||
var v2 = t1 * v1;
|
||||
var v3 = t2 * v1;
|
||||
|
||||
Assert.Multiple(() => {
|
||||
// Assert
|
||||
Assert.That(v2, Is.EqualTo(new Vector2I(int.MaxValue, int.MaxValue)));
|
||||
Assert.That(v3, Is.EqualTo(new Vector2I(int.MinValue, int.MinValue)));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTrans2DI_SpecialValues() {
|
||||
// Arrange
|
||||
var t1 = new Trans2DI(new Vector2I(0, 0), new Vector2I(0, 0), new Vector2I(0, 0));
|
||||
var t2 = new Trans2DI(new Vector2I(1, 0), new Vector2I(0, 1), new Vector2I(0, 0));
|
||||
var v1 = new Vector2I(1, 1);
|
||||
|
||||
// Act
|
||||
var v2 = t1 * v1;
|
||||
var v3 = t2 * v1;
|
||||
|
||||
Assert.Multiple(() => {
|
||||
// Assert
|
||||
Assert.That(v2, Is.EqualTo(new Vector2I(0, 0)));
|
||||
Assert.That(v3, Is.EqualTo(new Vector2I(1, 1)));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTrans2DI_Multiplication() {
|
||||
// Arrange
|
||||
var t1 = new Trans2DI(new Vector2I(1, 0), new Vector2I(0, 1), new Vector2I(1, 2));
|
||||
var t2 = new Trans2DI(new Vector2I(2, 0), new Vector2I(0, 2), new Vector2I(3, 4));
|
||||
|
||||
// Act
|
||||
var t3 = t1 * t2;
|
||||
|
||||
Assert.Multiple(() => {
|
||||
// Assert
|
||||
Assert.That(t3.XAxis, Is.EqualTo(new Vector2I(2, 0)));
|
||||
Assert.That(t3.YAxis, Is.EqualTo(new Vector2I(0, 2)));
|
||||
Assert.That(t3.Origin, Is.EqualTo(new Vector2I(5, 8)));
|
||||
});
|
||||
}
|
||||
}
|
1
icon.svg
Normal 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 |
44
project.godot
Normal file
@ -0,0 +1,44 @@
|
||||
; 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="ChessGame"
|
||||
config/version="0.0.6"
|
||||
run/main_scene="res://Main.tscn"
|
||||
config/features=PackedStringArray("4.4", "C#", "Mobile")
|
||||
|
||||
[autoload]
|
||||
|
||||
GlobalManager="*res://Scripts/GlobalManager.cs"
|
||||
|
||||
[display]
|
||||
|
||||
window/size/viewport_width=720
|
||||
window/size/viewport_height=1280
|
||||
window/stretch/mode="viewport"
|
||||
window/handheld/orientation=1
|
||||
|
||||
[dotnet]
|
||||
|
||||
project/assembly_name="ChessGame"
|
||||
|
||||
[internationalization]
|
||||
|
||||
locale/translations=PackedStringArray("res://Lang/godot_chessgame/content/zh_Hans.po", "res://Lang/godot_chessgame/content/en_devel.po")
|
||||
|
||||
[navigation]
|
||||
|
||||
2d/name_localized={}
|
||||
2d/version="0.0."
|
||||
|
||||
[rendering]
|
||||
|
||||
textures/vram_compression/import_etc2_astc=true
|