完善宠物系统

This commit is contained in:
2025-07-26 22:41:15 +08:00
parent 02a7e29e52
commit 048600e95d
135 changed files with 10204 additions and 5859 deletions

View File

@@ -46,7 +46,7 @@ texture = ExtResource("1_bns1c")
[node name="crop_sprite" type="Sprite2D" parent="."] [node name="crop_sprite" type="Sprite2D" parent="."]
material = SubResource("ShaderMaterial_s5pb0") material = SubResource("ShaderMaterial_s5pb0")
position = Vector2(51, 45) position = Vector2(51, 40)
scale = Vector2(0.339844, 0.363281) scale = Vector2(0.339844, 0.363281)
[node name="ProgressBar" type="ProgressBar" parent="."] [node name="ProgressBar" type="ProgressBar" parent="."]

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=11 format=3 uid="uid://bypjb28h4ntdr"] [gd_scene load_steps=12 format=3 uid="uid://bypjb28h4ntdr"]
[ext_resource type="Script" uid="uid://badqjgdfhg7vt" path="res://GUI/MainMenuPanel.gd" id="1_wpehy"] [ext_resource type="Script" uid="uid://badqjgdfhg7vt" path="res://GUI/MainMenuPanel.gd" id="1_wpehy"]
[ext_resource type="Texture2D" uid="uid://ddcmrh50o1y0q" path="res://assets/菜单UI/背景1.webp" id="2_eghpk"] [ext_resource type="Texture2D" uid="uid://ddcmrh50o1y0q" path="res://assets/菜单UI/背景1.webp" id="2_eghpk"]
@@ -7,6 +7,7 @@
[ext_resource type="Texture2D" uid="uid://dgdootc5bny5q" path="res://assets/菜单UI/QQ群.webp" id="4_eghpk"] [ext_resource type="Texture2D" uid="uid://dgdootc5bny5q" path="res://assets/菜单UI/QQ群.webp" id="4_eghpk"]
[ext_resource type="Script" uid="uid://kj7v1uxk2i6h" path="res://GUI/GameUpdatePanel.gd" id="4_fys16"] [ext_resource type="Script" uid="uid://kj7v1uxk2i6h" path="res://GUI/GameUpdatePanel.gd" id="4_fys16"]
[ext_resource type="Texture2D" uid="uid://ccav04woielxa" path="res://assets/菜单UI/柚小青装饰品.webp" id="5_6jmhb"] [ext_resource type="Texture2D" uid="uid://ccav04woielxa" path="res://assets/菜单UI/柚小青装饰品.webp" id="5_6jmhb"]
[ext_resource type="Texture2D" uid="uid://be4fa6qo525y1" path="res://assets/菜单UI/灵创招新群.png" id="5_m77al"]
[ext_resource type="Script" uid="uid://ciwjx67wjubdy" path="res://GUI/CheckUpdatePanel.gd" id="9_6jmhb"] [ext_resource type="Script" uid="uid://ciwjx67wjubdy" path="res://GUI/CheckUpdatePanel.gd" id="9_6jmhb"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_eghpk"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_eghpk"]
@@ -86,6 +87,18 @@ offset_bottom = 718.0
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
text = "版本号v1.0.1" text = "版本号v1.0.1"
[node name="Developer" type="RichTextLabel" parent="GUI"]
layout_mode = 0
offset_left = 1194.0
offset_top = 676.0
offset_right = 1398.0
offset_bottom = 718.0
theme_override_font_sizes/normal_font_size = 30
bbcode_enabled = true
text = "[rainbow freq=1 sat=2 val=100]By-树萌芽[/rainbow]"
horizontal_alignment = 1
vertical_alignment = 1
[node name="AddGroupLabel" type="Label" parent="GUI"] [node name="AddGroupLabel" type="Label" parent="GUI"]
self_modulate = Color(1, 1, 0, 1) self_modulate = Color(1, 1, 0, 1)
layout_mode = 0 layout_mode = 0
@@ -105,6 +118,14 @@ offset_bottom = 1229.0
scale = Vector2(0.3, 0.3) scale = Vector2(0.3, 0.3)
texture = ExtResource("4_eghpk") texture = ExtResource("4_eghpk")
[node name="QQGroupImage2" type="TextureRect" parent="GUI/AddGroupLabel"]
layout_mode = 0
offset_left = -832.0
offset_right = 103.0
offset_bottom = 1186.0
scale = Vector2(0.3, 0.3)
texture = ExtResource("5_m77al")
[node name="YouXiaoQing" type="TextureRect" parent="GUI/AddGroupLabel"] [node name="YouXiaoQing" type="TextureRect" parent="GUI/AddGroupLabel"]
layout_mode = 0 layout_mode = 0
offset_left = 298.0 offset_left = 298.0
@@ -114,6 +135,19 @@ offset_bottom = 1268.0
scale = Vector2(0.14, 0.14) scale = Vector2(0.14, 0.14)
texture = ExtResource("5_6jmhb") texture = ExtResource("5_6jmhb")
[node name="RichTextLabel" type="RichTextLabel" parent="GUI/AddGroupLabel"]
self_modulate = Color(0.580392, 1, 0, 1)
layout_mode = 0
offset_left = -896.0
offset_top = -47.0
offset_right = -420.0
offset_bottom = -7.0
theme_override_font_sizes/normal_font_size = 30
bbcode_enabled = true
text = "欢迎了解灵创新媒实验室"
horizontal_alignment = 1
vertical_alignment = 1
[node name="VBox" type="VBoxContainer" parent="."] [node name="VBox" type="VBoxContainer" parent="."]
layout_mode = 0 layout_mode = 0
offset_top = 248.0 offset_top = 248.0
@@ -217,11 +251,17 @@ text = "玩法介绍:
3.电脑Windows平台按住wsad或者方向键可以移动视角鼠标滚轮可以缩放视角安卓则为拖动和双指缩放 3.电脑Windows平台按住wsad或者方向键可以移动视角鼠标滚轮可以缩放视角安卓则为拖动和双指缩放
3.注册账号一定一定要用QQ号目前游戏的所有登录服务都是围绕着腾讯QQ来验证注册时会向您输入的QQ号对应的QQ邮箱发送一封注册邮件。 3.注册账号一定一定要用QQ号目前游戏的所有登录服务都是围绕着腾讯QQ来验证注册时会向您输入的QQ号对应的QQ邮箱发送一封注册邮件。
4.不要一上来就把钱用完了(比如某某人一上来就十连抽),可以去偷别人的菜 4.不要一上来就把钱用完了(比如某某人一上来就十连抽),可以去偷别人的菜
5.玩家排行榜有一些特殊农场,可以直接搜索访问: 杂交农场666 花卉农场520 稻香111 小麦谷222 访问有惊喜
6.全服大喇叭也有一些小彩蛋
7.记得在小卖部向其他玩家出售你不需要的东西
8.玩家太多无法找到你的好友的农场试试直接搜索QQ号
9.如果有条件尽量还是玩电脑版吧,毕竟电脑版优化是最好的,手机版或多或少有些问题(
致谢名单: 致谢名单:
程序牛马:(作物处理+抠图) 程序牛马:(作物处理+抠图)
虚空领主:(抠图) 虚空领主:(美术+抠图)
豆包:(万能的美术)" 豆包:(万能的美术)
ChatGPT超级美术"
[node name="GameUpdatePanel" type="Panel" parent="."] [node name="GameUpdatePanel" type="Panel" parent="."]
visible = false visible = false

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=97 format=3 uid="uid://dgh61dttaas5a"] [gd_scene load_steps=105 format=3 uid="uid://dgh61dttaas5a"]
[ext_resource type="Script" uid="uid://2pt11sfcaxf7" path="res://MainGame.gd" id="1_v3yaj"] [ext_resource type="Script" uid="uid://2pt11sfcaxf7" path="res://MainGame.gd" id="1_v3yaj"]
[ext_resource type="Texture2D" uid="uid://du2pyiojliasy" path="res://assets/游戏UI/经验球.webp" id="2_6jgly"] [ext_resource type="Texture2D" uid="uid://du2pyiojliasy" path="res://assets/游戏UI/经验球.webp" id="2_6jgly"]
@@ -39,6 +39,7 @@
[ext_resource type="Script" uid="uid://bvhupqlw2h1j8" path="res://Script/SmallPanel/DebugPanel.gd" id="28_8kysg"] [ext_resource type="Script" uid="uid://bvhupqlw2h1j8" path="res://Script/SmallPanel/DebugPanel.gd" id="28_8kysg"]
[ext_resource type="Script" uid="uid://ca2chgx5w3g1y" path="res://Components/GameBGMPlayer.gd" id="28_m6fch"] [ext_resource type="Script" uid="uid://ca2chgx5w3g1y" path="res://Components/GameBGMPlayer.gd" id="28_m6fch"]
[ext_resource type="Script" uid="uid://d4fvv2sjngajr" path="res://Script/Dialog/BatchBuyPopup.gd" id="29_5b81d"] [ext_resource type="Script" uid="uid://d4fvv2sjngajr" path="res://Script/Dialog/BatchBuyPopup.gd" id="29_5b81d"]
[ext_resource type="PackedScene" uid="uid://diwbnwhnq026" path="res://Scene/NewPet/PetBattlePanel.tscn" id="29_mw3xw"]
[ext_resource type="PackedScene" uid="uid://dos15dmc1b6bt" path="res://GUI/GameSettingPanel.tscn" id="30_game_setting"] [ext_resource type="PackedScene" uid="uid://dos15dmc1b6bt" path="res://GUI/GameSettingPanel.tscn" id="30_game_setting"]
[ext_resource type="Texture2D" uid="uid://2sdfbvf1isif" path="res://icon.svg" id="31_uc6q1"] [ext_resource type="Texture2D" uid="uid://2sdfbvf1isif" path="res://icon.svg" id="31_uc6q1"]
[ext_resource type="Script" uid="uid://doo34ll0yb078" path="res://Script/SmallPanel/PetInformPanel.gd" id="31_vygm6"] [ext_resource type="Script" uid="uid://doo34ll0yb078" path="res://Script/SmallPanel/PetInformPanel.gd" id="31_vygm6"]
@@ -70,7 +71,14 @@
[ext_resource type="Texture2D" uid="uid://cqqyc3ddwtvpn" path="res://assets/天气系统图片/栀子花3.webp" id="55_iluto"] [ext_resource type="Texture2D" uid="uid://cqqyc3ddwtvpn" path="res://assets/天气系统图片/栀子花3.webp" id="55_iluto"]
[ext_resource type="Texture2D" uid="uid://d4e54gh5iccul" path="res://assets/装饰物图片/道具商店.webp" id="56_rlmnt"] [ext_resource type="Texture2D" uid="uid://d4e54gh5iccul" path="res://assets/装饰物图片/道具商店.webp" id="56_rlmnt"]
[ext_resource type="Texture2D" uid="uid://deow5dqdm412v" path="res://assets/装饰物图片/宠物商店.webp" id="57_rlmnt"] [ext_resource type="Texture2D" uid="uid://deow5dqdm412v" path="res://assets/装饰物图片/宠物商店.webp" id="57_rlmnt"]
[ext_resource type="Texture2D" uid="uid://dfeqilibb6ecs" path="res://assets/装饰物图片/作物仓库.webp" id="58_mjfri"]
[ext_resource type="Texture2D" uid="uid://b738esrtjlho7" path="res://assets/装饰物图片/种子仓库.webp" id="59_612dn"]
[ext_resource type="Texture2D" uid="uid://cbj1s6ctp0utb" path="res://assets/装饰物图片/玩家排行榜.webp" id="60_2fqxv"]
[ext_resource type="Script" uid="uid://o4mcuqoivqri" path="res://GameManager/WeatherSystem.gd" id="62_uyv6e"] [ext_resource type="Script" uid="uid://o4mcuqoivqri" path="res://GameManager/WeatherSystem.gd" id="62_uyv6e"]
[ext_resource type="Texture2D" uid="uid://deh0dnprkw155" path="res://assets/装饰物图片/每日签到礼包.webp" id="63_ekowe"]
[ext_resource type="Texture2D" uid="uid://ic2nvi3xlwl4" path="res://assets/装饰物图片/在线时长礼包.webp" id="64_crc4a"]
[ext_resource type="Texture2D" uid="uid://1xgmal8sw6il" path="res://assets/装饰物图片/宠物背包.webp" id="67_onvxb"]
[ext_resource type="Texture2D" uid="uid://ywdg7xgq7hm8" path="res://assets/装饰物图片/道具背包.webp" id="68_bpbm8"]
[ext_resource type="Texture2D" uid="uid://bnv6wb0k443fv" path="res://assets/天气系统图片/柳叶2.webp" id="69_uyv6e"] [ext_resource type="Texture2D" uid="uid://bnv6wb0k443fv" path="res://assets/天气系统图片/柳叶2.webp" id="69_uyv6e"]
[ext_resource type="Script" uid="uid://di8wjflimodb0" path="res://GameManager/DayNightSystem.gd" id="73_6fhdl"] [ext_resource type="Script" uid="uid://di8wjflimodb0" path="res://GameManager/DayNightSystem.gd" id="73_6fhdl"]
@@ -277,6 +285,20 @@ fog_density = 1.0
[node name="main" type="Node"] [node name="main" type="Node"]
script = ExtResource("1_v3yaj") script = ExtResource("1_v3yaj")
[node name="PetPatrolPoints" type="Node" parent="."]
[node name="Pos1" type="Marker2D" parent="PetPatrolPoints"]
position = Vector2(-276, -151)
[node name="Pos2" type="Marker2D" parent="PetPatrolPoints"]
position = Vector2(-276, 1052)
[node name="Pos3" type="Marker2D" parent="PetPatrolPoints"]
position = Vector2(1391, 1052)
[node name="Pos4" type="Marker2D" parent="PetPatrolPoints"]
position = Vector2(1391, -184)
[node name="UI" type="CanvasLayer" parent="."] [node name="UI" type="CanvasLayer" parent="."]
[node name="GUI" type="Control" parent="UI"] [node name="GUI" type="Control" parent="UI"]
@@ -602,6 +624,18 @@ layout_mode = 2
theme_override_font_sizes/font_size = 40 theme_override_font_sizes/font_size = 40
text = "点赞" text = "点赞"
[node name="BattleButton" type="Button" parent="UI/GUI/VisitVBox"]
modulate = Color(0, 0.784782, 0.487639, 1)
layout_mode = 2
theme_override_font_sizes/font_size = 40
text = "发起对战"
[node name="UseItemButton" type="Button" parent="UI/GUI/VisitVBox"]
modulate = Color(0.37232, 0.679193, 1, 1)
layout_mode = 2
theme_override_font_sizes/font_size = 40
text = "使用道具"
[node name="ReturnMyFarmButton" type="Button" parent="UI/GUI/VisitVBox"] [node name="ReturnMyFarmButton" type="Button" parent="UI/GUI/VisitVBox"]
modulate = Color(1, 1, 0.721569, 1) modulate = Color(1, 1, 0.721569, 1)
layout_mode = 2 layout_mode = 2
@@ -916,6 +950,9 @@ visible = false
[node name="GameSettingPanel" parent="UI/BigPanel" instance=ExtResource("30_game_setting")] [node name="GameSettingPanel" parent="UI/BigPanel" instance=ExtResource("30_game_setting")]
visible = false visible = false
[node name="PetBattlePanel" parent="UI/BigPanel" instance=ExtResource("29_mw3xw")]
visible = false
[node name="SmallPanel" type="CanvasLayer" parent="UI"] [node name="SmallPanel" type="CanvasLayer" parent="UI"]
[node name="LoadProgressPanel" parent="UI/SmallPanel" instance=ExtResource("27_vygm6")] [node name="LoadProgressPanel" parent="UI/SmallPanel" instance=ExtResource("27_vygm6")]
@@ -1427,7 +1464,9 @@ offset_right = 1322.0
offset_bottom = 280.0 offset_bottom = 280.0
theme_override_colors/font_color = Color(0.654902, 1, 1, 1) theme_override_colors/font_color = Color(0.654902, 1, 1, 1)
theme_override_font_sizes/font_size = 30 theme_override_font_sizes/font_size = 30
text = "只需花费一点点钱币,就可以匿名发送一句话,由于智慧树强大的链接性,其他玩家在浇水施肥时就有概率收到这句话。向他人发送一句祝福吧(,,・ω・,,) ,只要你不断的给智慧树浇水施肥,它就会长得越来越高" text = "只需花费一点点钱币,就可以匿名发送一句话,由于智慧树强大的链接性,
其他玩家在浇水施肥时就有概率收到这句话。向他人发送一句祝福吧(,,・ω・,,)
只要你不断的给智慧树浇水施肥,它就会长得越来越高"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
autowrap_mode = 2 autowrap_mode = 2
@@ -1881,14 +1920,6 @@ script = ExtResource("17_0igvr")
[node name="Timer" type="Timer" parent="BackgroundUI/BackgroundSwitcher"] [node name="Timer" type="Timer" parent="BackgroundUI/BackgroundSwitcher"]
[node name="PetPatrolPathLine" type="Line2D" parent="."]
position = Vector2(-52.4841, -115.095)
scale = Vector2(0.92426, 0.816774)
points = PackedVector2Array(-200, -100, -200, 1500, 1500, 1500, 1500, -100)
closed = true
width = 5.0
default_color = Color(0, 1, 1, 1)
[node name="GridContainer" type="GridContainer" parent="."] [node name="GridContainer" type="GridContainer" parent="."]
z_as_relative = false z_as_relative = false
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
@@ -2056,6 +2087,7 @@ layout_mode = 0
offset_left = 13.0 offset_left = 13.0
offset_right = 390.0 offset_right = 390.0
offset_bottom = 113.0 offset_bottom = 113.0
theme_override_constants/outline_size = 20
theme_override_font_sizes/bold_italics_font_size = 35 theme_override_font_sizes/bold_italics_font_size = 35
theme_override_font_sizes/italics_font_size = 35 theme_override_font_sizes/italics_font_size = 35
theme_override_font_sizes/mono_font_size = 35 theme_override_font_sizes/mono_font_size = 35
@@ -2207,7 +2239,7 @@ text = "宠物商店"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="Decoration5" type="Button" parent="Decoration"] [node name="CropWarehouse" type="Button" parent="Decoration"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_left = 610.0 offset_left = 610.0
@@ -2216,18 +2248,17 @@ offset_right = 874.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration/Decoration5"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration/CropWarehouse"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration/Decoration5"] [node name="Image" type="Sprite2D" parent="Decoration/CropWarehouse"]
position = Vector2(132, 48) position = Vector2(132, 48)
scale = Vector2(1.2, 1.2) scale = Vector2(1.2, 1.2)
texture = ExtResource("49_xjiif") texture = ExtResource("58_mjfri")
[node name="Name" type="RichTextLabel" parent="Decoration/Decoration5"] [node name="Name" type="RichTextLabel" parent="Decoration/CropWarehouse"]
visible = false
layout_mode = 0 layout_mode = 0
offset_left = -65.0 offset_left = -65.0
offset_top = -145.0 offset_top = -145.0
@@ -2239,11 +2270,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40 theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40 theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true bbcode_enabled = true
text = "稻草人" text = "作物仓库"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="Decoration6" type="Button" parent="Decoration"] [node name="SeedWarehouse" type="Button" parent="Decoration"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_left = 732.0 offset_left = 732.0
@@ -2252,18 +2283,17 @@ offset_right = 996.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration/Decoration6"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration/SeedWarehouse"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration/Decoration6"] [node name="Image" type="Sprite2D" parent="Decoration/SeedWarehouse"]
position = Vector2(132, 48) position = Vector2(132, 48)
scale = Vector2(1.2, 1.2) scale = Vector2(1.2, 1.2)
texture = ExtResource("49_xjiif") texture = ExtResource("59_612dn")
[node name="Name" type="RichTextLabel" parent="Decoration/Decoration6"] [node name="Name" type="RichTextLabel" parent="Decoration/SeedWarehouse"]
visible = false
layout_mode = 0 layout_mode = 0
offset_left = -65.0 offset_left = -65.0
offset_top = -145.0 offset_top = -145.0
@@ -2275,11 +2305,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40 theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40 theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true bbcode_enabled = true
text = "稻草人" text = "种子仓库"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="Decoration7" type="Button" parent="Decoration"] [node name="PlayerRank" type="Button" parent="Decoration"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_left = 854.0 offset_left = 854.0
@@ -2288,18 +2318,17 @@ offset_right = 1118.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration/Decoration7"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration/PlayerRank"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration/Decoration7"] [node name="Image" type="Sprite2D" parent="Decoration/PlayerRank"]
position = Vector2(132, 48) position = Vector2(132, 48)
scale = Vector2(1.2, 1.2) scale = Vector2(1.2, 1.2)
texture = ExtResource("50_sqnmr") texture = ExtResource("60_2fqxv")
[node name="Name" type="RichTextLabel" parent="Decoration/Decoration7"] [node name="Name" type="RichTextLabel" parent="Decoration/PlayerRank"]
visible = false
layout_mode = 0 layout_mode = 0
offset_left = -65.0 offset_left = -65.0
offset_top = -145.0 offset_top = -145.0
@@ -2311,7 +2340,7 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40 theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40 theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true bbcode_enabled = true
text = "稻草人" text = "[rainbow]玩家排行榜[/rainbow]"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
@@ -2330,16 +2359,17 @@ scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="WisdomTreeImage" type="Sprite2D" parent="Decoration/WisdomTree"] [node name="WisdomTreeImage" type="Sprite2D" parent="Decoration/WisdomTree"]
position = Vector2(126, 82) position = Vector2(135, -107.5)
scale = Vector2(0.5, 0.5) scale = Vector2(2.5, 2.5)
texture = ExtResource("45_xvovi") texture = ExtResource("45_xvovi")
[node name="TreeName" type="Label" parent="Decoration/WisdomTree"] [node name="TreeName" type="Label" parent="Decoration/WisdomTree"]
self_modulate = Color(2, 2, 2, 1) self_modulate = Color(2, 2, 2, 1)
layout_mode = 0 layout_mode = 0
offset_top = -145.0 offset_left = 37.0
offset_right = 265.0 offset_top = -450.0
offset_bottom = -96.0 offset_right = 302.0
offset_bottom = -401.0
theme_override_font_sizes/font_size = 35 theme_override_font_sizes/font_size = 35
text = "智慧树" text = "智慧树"
horizontal_alignment = 1 horizontal_alignment = 1
@@ -2348,10 +2378,10 @@ vertical_alignment = 1
[node name="TreeStatus" type="Label" parent="Decoration/WisdomTree"] [node name="TreeStatus" type="Label" parent="Decoration/WisdomTree"]
self_modulate = Color(2, 2, 2, 1) self_modulate = Color(2, 2, 2, 1)
layout_mode = 0 layout_mode = 0
offset_left = -122.0 offset_left = -85.0
offset_top = -190.0 offset_top = -495.0
offset_right = 370.0 offset_right = 407.0
offset_bottom = -141.0 offset_bottom = -446.0
theme_override_font_sizes/font_size = 35 theme_override_font_sizes/font_size = 35
text = "等级lv99 高度99m" text = "等级lv99 高度99m"
horizontal_alignment = 1 horizontal_alignment = 1
@@ -2359,10 +2389,10 @@ vertical_alignment = 1
[node name="BackgroundPanel" type="Panel" parent="Decoration/WisdomTree"] [node name="BackgroundPanel" type="Panel" parent="Decoration/WisdomTree"]
layout_mode = 0 layout_mode = 0
offset_left = -212.0 offset_left = -175.0
offset_top = -350.0 offset_top = -655.0
offset_right = 491.0 offset_right = 528.0
offset_bottom = -195.0 offset_bottom = -500.0
theme_override_styles/panel = SubResource("StyleBoxFlat_6ylhg") theme_override_styles/panel = SubResource("StyleBoxFlat_6ylhg")
[node name="AnonymousTalk" type="RichTextLabel" parent="Decoration/WisdomTree/BackgroundPanel"] [node name="AnonymousTalk" type="RichTextLabel" parent="Decoration/WisdomTree/BackgroundPanel"]
@@ -2370,6 +2400,8 @@ layout_mode = 0
offset_left = 13.0 offset_left = 13.0
offset_right = 695.0 offset_right = 695.0
offset_bottom = 155.0 offset_bottom = 155.0
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 15
theme_override_font_sizes/bold_italics_font_size = 35 theme_override_font_sizes/bold_italics_font_size = 35
theme_override_font_sizes/italics_font_size = 35 theme_override_font_sizes/italics_font_size = 35
theme_override_font_sizes/mono_font_size = 35 theme_override_font_sizes/mono_font_size = 35
@@ -3107,7 +3139,7 @@ vertical_alignment = 1
[node name="Decoration4" type="Node2D" parent="."] [node name="Decoration4" type="Node2D" parent="."]
position = Vector2(0, 976) position = Vector2(0, 976)
[node name="ScareCrow" type="Button" parent="Decoration4"] [node name="DailyCheckinGift" type="Button" parent="Decoration4"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_top = -108.0 offset_top = -108.0
@@ -3115,16 +3147,17 @@ offset_right = 264.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/ScareCrow"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/DailyCheckinGift"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration4/ScareCrow"] [node name="Image" type="Sprite2D" parent="Decoration4/DailyCheckinGift"]
position = Vector2(132, 48) position = Vector2(132, 48)
scale = Vector2(1.2, 1.2) scale = Vector2(1.2, 1.2)
texture = ExtResource("63_ekowe")
[node name="Name" type="RichTextLabel" parent="Decoration4/ScareCrow"] [node name="Name" type="RichTextLabel" parent="Decoration4/DailyCheckinGift"]
layout_mode = 0 layout_mode = 0
offset_left = -65.0 offset_left = -65.0
offset_top = -145.0 offset_top = -145.0
@@ -3136,10 +3169,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40 theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40 theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true bbcode_enabled = true
text = "每日签到礼包"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="Decoration1" type="Button" parent="Decoration4"] [node name="OnlineTimeGift" type="Button" parent="Decoration4"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_left = 122.0 offset_left = 122.0
@@ -3148,18 +3182,17 @@ offset_right = 386.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/Decoration1"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/OnlineTimeGift"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration4/Decoration1"] [node name="Image" type="Sprite2D" parent="Decoration4/OnlineTimeGift"]
position = Vector2(132, 48) position = Vector2(132, 48)
scale = Vector2(1.2, 1.2) scale = Vector2(1.2, 1.2)
texture = ExtResource("49_xjiif") texture = ExtResource("64_crc4a")
[node name="Name" type="RichTextLabel" parent="Decoration4/Decoration1"] [node name="Name" type="RichTextLabel" parent="Decoration4/OnlineTimeGift"]
visible = false
layout_mode = 0 layout_mode = 0
offset_left = -65.0 offset_left = -65.0
offset_top = -145.0 offset_top = -145.0
@@ -3171,7 +3204,7 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40 theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40 theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true bbcode_enabled = true
text = "稻草人" text = "在线时长礼包"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
@@ -3355,7 +3388,7 @@ text = "稻草人"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="Decoration7" type="Button" parent="Decoration4"] [node name="PetBag" type="Button" parent="Decoration4"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_left = 854.0 offset_left = 854.0
@@ -3364,18 +3397,17 @@ offset_right = 1118.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/Decoration7"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/PetBag"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Image" type="Sprite2D" parent="Decoration4/Decoration7"] [node name="Image" type="Sprite2D" parent="Decoration4/PetBag"]
position = Vector2(132, 48) position = Vector2(132, 48)
scale = Vector2(1.2, 1.2) scale = Vector2(1.2, 1.2)
texture = ExtResource("50_sqnmr") texture = ExtResource("67_onvxb")
[node name="Name" type="RichTextLabel" parent="Decoration4/Decoration7"] [node name="Name" type="RichTextLabel" parent="Decoration4/PetBag"]
visible = false
layout_mode = 0 layout_mode = 0
offset_left = -65.0 offset_left = -65.0
offset_top = -145.0 offset_top = -145.0
@@ -3387,11 +3419,11 @@ theme_override_font_sizes/mono_font_size = 40
theme_override_font_sizes/normal_font_size = 40 theme_override_font_sizes/normal_font_size = 40
theme_override_font_sizes/bold_font_size = 40 theme_override_font_sizes/bold_font_size = 40
bbcode_enabled = true bbcode_enabled = true
text = "稻草人" text = "宠物背包"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
[node name="WisdomTree" type="Button" parent="Decoration4"] [node name="ItemBag" type="Button" parent="Decoration4"]
self_modulate = Color(1, 1, 1, 0) self_modulate = Color(1, 1, 1, 0)
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
offset_left = 976.0 offset_left = 976.0
@@ -3400,18 +3432,24 @@ offset_right = 1240.0
offset_bottom = 156.0 offset_bottom = 156.0
scale = Vector2(0.4, 0.4) scale = Vector2(0.4, 0.4)
[node name="Image" type="Sprite2D" parent="Decoration4/WisdomTree"] [node name="GrassGroundImage" type="Sprite2D" parent="Decoration4/ItemBag"]
position = Vector2(132, 134) position = Vector2(132, 134)
scale = Vector2(1.4, 1.4) scale = Vector2(1.4, 1.4)
texture = ExtResource("48_2i8fe") texture = ExtResource("48_2i8fe")
[node name="Name" type="Label" parent="Decoration4/WisdomTree"] [node name="Image" type="Sprite2D" parent="Decoration4/ItemBag"]
position = Vector2(132, 48)
scale = Vector2(1.2, 1.2)
texture = ExtResource("68_bpbm8")
[node name="Name" type="Label" parent="Decoration4/ItemBag"]
self_modulate = Color(2, 2, 2, 1) self_modulate = Color(2, 2, 2, 1)
layout_mode = 0 layout_mode = 0
offset_top = -145.0 offset_top = -145.0
offset_right = 265.0 offset_right = 265.0
offset_bottom = -96.0 offset_bottom = -96.0
theme_override_font_sizes/font_size = 35 theme_override_font_sizes/font_size = 35
text = "道具背包"
horizontal_alignment = 1 horizontal_alignment = 1
vertical_alignment = 1 vertical_alignment = 1
@@ -3568,6 +3606,7 @@ environment = SubResource("Environment_uyv6e")
[connection signal="pressed" from="UI/GUI/FarmVBox/OneClickPlantButton" to="." method="_on_one_click_plant_button_pressed"] [connection signal="pressed" from="UI/GUI/FarmVBox/OneClickPlantButton" to="." method="_on_one_click_plant_button_pressed"]
[connection signal="pressed" from="UI/GUI/FarmVBox/AddNewGroundButton" to="." method="_on_add_new_ground_button_pressed"] [connection signal="pressed" from="UI/GUI/FarmVBox/AddNewGroundButton" to="." method="_on_add_new_ground_button_pressed"]
[connection signal="pressed" from="UI/GUI/VisitVBox/LikeButton" to="." method="_on_like_button_pressed"] [connection signal="pressed" from="UI/GUI/VisitVBox/LikeButton" to="." method="_on_like_button_pressed"]
[connection signal="pressed" from="UI/GUI/VisitVBox/BattleButton" to="." method="_on_battle_button_pressed"]
[connection signal="pressed" from="UI/GUI/VisitVBox/ReturnMyFarmButton" to="." method="_on_return_my_farm_button_pressed"] [connection signal="pressed" from="UI/GUI/VisitVBox/ReturnMyFarmButton" to="." method="_on_return_my_farm_button_pressed"]
[connection signal="pressed" from="UI/GUI/OtherVBox/MyStoreButton" to="." method="_on_my_store_button_pressed"] [connection signal="pressed" from="UI/GUI/OtherVBox/MyStoreButton" to="." method="_on_my_store_button_pressed"]
[connection signal="pressed" from="UI/GUI/OtherVBox/AccountSettingButton" to="." method="_on_account_setting_button_pressed"] [connection signal="pressed" from="UI/GUI/OtherVBox/AccountSettingButton" to="." method="_on_account_setting_button_pressed"]
@@ -3590,6 +3629,11 @@ environment = SubResource("Environment_uyv6e")
[connection signal="pressed" from="Decoration/SeedStore" to="." method="_on_seed_store_pressed"] [connection signal="pressed" from="Decoration/SeedStore" to="." method="_on_seed_store_pressed"]
[connection signal="pressed" from="Decoration/ItemStore" to="." method="_on_item_store_pressed"] [connection signal="pressed" from="Decoration/ItemStore" to="." method="_on_item_store_pressed"]
[connection signal="pressed" from="Decoration/PetStore" to="." method="_on_pet_store_pressed"] [connection signal="pressed" from="Decoration/PetStore" to="." method="_on_pet_store_pressed"]
[connection signal="pressed" from="Decoration/CropWarehouse" to="." method="_on_crop_warehouse_pressed"]
[connection signal="pressed" from="Decoration/SeedWarehouse" to="." method="_on_seed_warehouse_pressed"]
[connection signal="pressed" from="Decoration/PlayerRank" to="." method="_on_player_rank_pressed"]
[connection signal="pressed" from="Decoration/WisdomTree" to="." method="_on_wisdom_tree_pressed"] [connection signal="pressed" from="Decoration/WisdomTree" to="." method="_on_wisdom_tree_pressed"]
[connection signal="pressed" from="Decoration4/ScareCrow" to="." method="_on_scare_crow_pressed"] [connection signal="pressed" from="Decoration4/DailyCheckinGift" to="." method="_on_daily_checkin_gift_pressed"]
[connection signal="pressed" from="Decoration4/WisdomTree" to="." method="_on_wisdom_tree_pressed"] [connection signal="pressed" from="Decoration4/OnlineTimeGift" to="." method="_on_online_time_gift_pressed"]
[connection signal="pressed" from="Decoration4/PetBag" to="." method="_on_pet_bag_pressed"]
[connection signal="pressed" from="Decoration4/ItemBag" to="." method="_on_item_bag_pressed"]

View File

@@ -64,6 +64,9 @@ func _ready():
# 创建TCP客户端实例 # 创建TCP客户端实例
self.add_child(client) self.add_child(client)
# 禁用自动重连,避免频繁的本地连接
client.auto_reconnect = false
# 连接信号 # 连接信号
client.connected_to_server.connect(_on_connected) client.connected_to_server.connect(_on_connected)
client.connection_failed.connect(_on_connection_failed) client.connection_failed.connect(_on_connection_failed)
@@ -345,12 +348,24 @@ func _on_data_received(data):
elif action_type == "set_patrol_pet": elif action_type == "set_patrol_pet":
if success: if success:
main_game.patrol_pets = updated_data["巡逻宠物"] main_game.patrol_pets = updated_data["巡逻宠物"]
main_game.update_patrol_pets() main_game.update_patrol_pets(updated_data["巡逻宠物"])
pet_inform_panel._refresh_patrol_button() pet_inform_panel._refresh_patrol_button()
Toast.show(message, Color.GREEN) Toast.show(message, Color.GREEN)
else: else:
Toast.show(message, Color.RED) Toast.show(message, Color.RED)
# 设置出战宠物响应
elif action_type == "set_battle_pet":
if success:
main_game.battle_pets = updated_data["出战宠物"]
pet_inform_panel._refresh_battle_button()
# 更新对战按钮显示状态
if main_game.has_method("_update_battle_button_visibility"):
main_game._update_battle_button_visibility()
Toast.show(message, Color.GREEN)
else:
Toast.show(message, Color.RED)
# 使用道具响应 # 使用道具响应
elif action_type == "use_item": elif action_type == "use_item":
if success: if success:
@@ -533,6 +548,11 @@ func _on_data_received(data):
main_game._handle_crop_data_response(data) main_game._handle_crop_data_response(data)
elif message_type == "item_config_response": elif message_type == "item_config_response":
main_game._handle_item_config_response(data) main_game._handle_item_config_response(data)
elif message_type == "pet_config_response":
# 保存宠物配置到MainGame
main_game._handle_pet_config_response(data)
# 同时传递给宠物商店面板
pet_store_panel._on_pet_config_received(data)
elif message_type == "visit_player_response": elif message_type == "visit_player_response":
main_game._handle_visit_player_response(data) main_game._handle_visit_player_response(data)
elif message_type == "return_my_farm_response": elif message_type == "return_my_farm_response":
@@ -934,6 +954,16 @@ func sendGetItemConfig():
}) })
return true return true
#发送获取宠物配置数据请求
func sendGetPetConfig():
if not client.is_client_connected():
return false
client.send_data({
"type": "request_pet_config"
})
return true
#发送访问玩家请求 #发送访问玩家请求
func sendVisitPlayer(target_username): func sendVisitPlayer(target_username):
if not client.is_client_connected(): if not client.is_client_connected():
@@ -1169,6 +1199,18 @@ func send_get_wisdom_tree_config():
}) })
return true return true
#发送宠物对战结果
func send_pet_battle_result(battle_result: Dictionary):
if not client.is_client_connected():
return false
client.send_data({
"type": "pet_battle_result",
"battle_result": battle_result,
"timestamp": Time.get_unix_time_from_system()
})
return true
#检查是否连接到服务器 #检查是否连接到服务器
func is_connected_to_server(): func is_connected_to_server():
return client.is_client_connected() return client.is_client_connected()

View File

@@ -69,7 +69,7 @@ offset_top = 21.25
offset_right = 378.0 offset_right = 378.0
offset_bottom = 78.25 offset_bottom = 78.25
theme_override_font_sizes/font_size = 35 theme_override_font_sizes/font_size = 35
text = "输入要搜索的人" placeholder_text = "输入要搜索的人"
[node name="RefreshButton" type="Button" parent="."] [node name="RefreshButton" type="Button" parent="."]
custom_minimum_size = Vector2(55, 55) custom_minimum_size = Vector2(55, 55)

368
Scene/NewPet/BulletBase.gd Normal file
View File

@@ -0,0 +1,368 @@
extends Area2D
class_name BulletBase
# 简化子弹系统 - 辅助攻击用
# 基础功能:移动、碰撞检测、伤害
signal bullet_hit(bullet: BulletBase, target: NewPetBase)
@onready var sprite: Sprite2D = $Sprite
@onready var collision_shape: CollisionShape2D = $CollisionShape2D
const bullet = {
"小蓝弹":{
"图片":"res://assets/子弹图片/01.png",
"函数":"create_blue_bullet"
},
"小红弹":{
"图片":"res://assets/子弹图片/02.png",
"函数":"create_red_bullet"
},
"小粉弹":{
"图片":"res://assets/子弹图片/03.png",
"函数":"create_pink_bullet"
},
"小紫弹":{
"图片":"res://assets/子弹图片/04.png",
"函数":"create_purple_bullet"
},
"长橙弹":{
"图片":"res://assets/子弹图片/21.png",
"函数":"create_long_orange_bullet"
},
"长紫弹":{
"图片":"res://assets/子弹图片/22.png",
"函数":"create_long_purple_bullet"
},
"长绿弹":{
"图片":"res://assets/子弹图片/25.png",
"函数":"create_long_green_bullet"
},
"黄色闪电":{
"图片":"res://assets/子弹图片/36.png",
"函数":"create_yellow_lightning_bullet"
},
"绿色闪电":{
"图片":"res://assets/子弹图片/35.png",
"函数":"create_green_lightning_bullet"
},
"红色闪电":{
"图片":"res://assets/子弹图片/33.png",
"函数":"create_red_lightning_bullet"
},
"紫色闪电":{
"图片":"res://assets/子弹图片/32.png",
"函数":"create_purple_lightning_bullet"
},
}
# 基础子弹属性
var direction: Vector2 = Vector2.RIGHT
var speed: float = 300.0
var damage: float = 25.0
var owner_pet: NewPetBase = null
var max_distance: float = 800.0
var traveled_distance: float = 0.0
var is_active: bool = true
# 生存时间
var lifetime: float = 3.0
var current_lifetime: float = 0.0
#==================基础函数=========================
func _ready():
# 连接碰撞信号
area_entered.connect(_on_area_entered)
# 设置碰撞层
collision_layer = 4 # 子弹层
collision_mask = 1 # 只检测宠物层
# 添加到子弹组
add_to_group("bullets")
func _physics_process(delta):
if not is_active:
return
# 更新生存时间
current_lifetime += delta
if current_lifetime >= lifetime:
call_deferred("destroy_bullet")
return
# 检查长紫弹分裂计时
if has_meta("bullet_type") and get_meta("bullet_type") == "长紫弹":
var current_split_time = get_meta("current_split_time", 0.0)
var split_timer = get_meta("split_timer", 2.0)
current_split_time += delta
set_meta("current_split_time", current_split_time)
if current_split_time >= split_timer:
# 时间到了,分裂并销毁
call_deferred("create_split_bullets", global_position)
call_deferred("destroy_bullet")
return
# 移动子弹
var movement = direction * speed * delta
position += movement
traveled_distance += movement.length()
# 检查最大距离
if traveled_distance >= max_distance:
call_deferred("destroy_bullet")
return
# 检查是否超出屏幕边界
var viewport_rect = get_viewport().get_visible_rect()
if not viewport_rect.has_point(global_position):
call_deferred("destroy_bullet")
#==================基础函数=========================
#=============================每个子弹单独效果============================
# 小蓝弹
func create_blue_bullet():
sprite.texture = load(bullet["小蓝弹"]["图片"])
speed = 250.0
damage = 20.0
lifetime = 2.5
sprite.modulate = Color(0.5, 0.8, 1.0, 1.0) # 蓝色调
# 小红弹
func create_red_bullet():
sprite.texture = load(bullet["小红弹"]["图片"])
speed = 300.0
damage = 25.0
lifetime = 3.0
sprite.modulate = Color(1.0, 0.5, 0.5, 1.0) # 红色调
# 小粉弹
func create_pink_bullet():
sprite.texture = load(bullet["小粉弹"]["图片"])
speed = 280.0
damage = 22.0
lifetime = 2.8
sprite.modulate = Color(1.0, 0.7, 0.9, 1.0) # 粉色调
# 小紫弹
func create_purple_bullet():
sprite.texture = load(bullet["小紫弹"]["图片"])
speed = 320.0
damage = 28.0
lifetime = 3.2
sprite.modulate = Color(0.8, 0.5, 1.0, 1.0) # 紫色调
# 长橙弹
func create_long_orange_bullet():
sprite.texture = load(bullet["长橙弹"]["图片"])
speed = 350.0
damage = 35.0
lifetime = 4.0
max_distance = 1000.0
sprite.modulate = Color(1.0, 0.7, 0.3, 1.0) # 橙色调
# 长紫弹
func create_long_purple_bullet():
sprite.texture = load(bullet["长紫弹"]["图片"])
speed = 330.0
damage = 32.0
lifetime = 3.8
max_distance = 950.0
sprite.modulate = Color(0.9, 0.4, 1.0, 1.0) # 深紫色调
# 标记为长紫弹2秒后自动分裂
set_meta("bullet_type", "长紫弹")
set_meta("split_timer", 2.0) # 2秒后分裂
set_meta("current_split_time", 0.0) # 当前计时
# 创建分裂子弹长紫弹2秒后的效果
func create_split_bullets(hit_position: Vector2):
"""在指定位置生成4个小弹向四周发射"""
var bullet_types = ["小蓝弹", "小红弹", "小粉弹", "小紫弹"]
var bullet_scene = preload("res://Scene/NewPet/BulletBase.tscn")
# 生成4个方向的子弹
for i in range(4):
# 计算方向角度每90度一个方向
var angle = i * PI / 2.0
var direction_vector = Vector2(cos(angle), sin(angle))
# 选择子弹类型每种类型1个
var bullet_type = bullet_types[i]
# 创建子弹实例
var new_bullet = bullet_scene.instantiate()
get_parent().add_child(new_bullet)
# 设置子弹位置
new_bullet.global_position = hit_position
# 设置子弹属性5个参数方向、速度、伤害、所有者、子弹类型
new_bullet.setup(direction_vector, 200.0, 15.0, owner_pet, bullet_type)
# 分裂子弹生成完成
# 长绿弹
func create_long_green_bullet():
sprite.texture = load(bullet["长绿弹"]["图片"])
speed = 310.0
damage = 30.0
lifetime = 3.5
max_distance = 900.0
sprite.modulate = Color(0.4, 1.0, 0.5, 1.0) # 绿色调
# 黄色闪电
func create_yellow_lightning_bullet():
sprite.texture = load(bullet["黄色闪电"]["图片"])
speed = 400.0
damage = 40.0
lifetime = 2.0
max_distance = 600.0
sprite.modulate = Color(1.0, 1.0, 0.3, 1.0) # 黄色闪电
# 绿色闪电
func create_green_lightning_bullet():
sprite.texture = load(bullet["绿色闪电"]["图片"])
speed = 380.0
damage = 38.0
lifetime = 2.2
max_distance = 650.0
sprite.modulate = Color(0.3, 1.0, 0.3, 1.0) # 绿色闪电
# 红色闪电
func create_red_lightning_bullet():
sprite.texture = load(bullet["红色闪电"]["图片"])
speed = 420.0
damage = 45.0
lifetime = 1.8
max_distance = 550.0
sprite.modulate = Color(1.0, 0.3, 0.3, 1.0) # 红色闪电
# 紫色闪电
func create_purple_lightning_bullet():
sprite.texture = load(bullet["紫色闪电"]["图片"])
speed = 450.0
damage = 50.0
lifetime = 1.5
max_distance = 500.0
sprite.modulate = Color(0.8, 0.3, 1.0, 1.0) # 紫色闪电
#=============================每个子弹单独效果============================
#=========================通用子弹函数==============================
# 通用子弹创建函数
func create_bullet_by_name(bullet_name: String):
"""根据子弹名称创建对应类型的子弹"""
if not bullet.has(bullet_name):
return
var bullet_data = bullet[bullet_name]
var function_name = bullet_data.get("函数", "")
if function_name != "":
call(function_name)
# 获取子弹图标
func get_bullet_icon(bullet_name: String) -> Texture2D:
if bullet.has(bullet_name) and bullet[bullet_name].has("图片"):
return load(bullet[bullet_name]["图片"])
else:
return null
# 获取所有子弹名称列表
func get_all_bullet_names() -> Array:
return bullet.keys()
# 创建击中特效
func create_hit_effect(pos: Vector2):
pass
#销毁子弹
func destroy_bullet():
"""销毁子弹"""
is_active = false
remove_from_group("bullets")
queue_free()
#初始化子弹
func setup(dir: Vector2, spd: float, dmg: float, owner: NewPetBase, bullet_type: String = ""):
"""初始化子弹"""
direction = dir.normalized()
owner_pet = owner
# 如果指定了子弹类型,使用对应的创建函数
if bullet_type != "" and bullet.has(bullet_type):
create_bullet_by_name(bullet_type)
else:
# 使用传入的参数作为默认值
speed = spd
damage = dmg
# 简单的视觉效果
sprite.modulate = Color.YELLOW
# 设置子弹旋转
rotation = direction.angle()
#碰撞检测
func _on_area_entered(area: Area2D):
"""碰撞检测"""
if not is_active:
return
# 检查是否是宠物
if not area is NewPetBase:
return
var pet_target = area as NewPetBase
# 检查是否是有效目标
if not is_valid_target(pet_target):
return
# 造成伤害并延迟销毁子弹(避免在物理查询期间修改状态)
hit_target(pet_target)
call_deferred("destroy_bullet")
#检查是否是有效攻击目标
func is_valid_target(target: NewPetBase) -> bool:
"""检查是否是有效攻击目标"""
# 检查owner_pet是否有效
if not is_instance_valid(owner_pet):
owner_pet = null
# 不能攻击自己的主人
if target == owner_pet:
return false
# 不能攻击同队伍
if owner_pet != null and target.pet_team == owner_pet.pet_team:
return false
# 不能攻击已死亡的宠物
if not target.is_alive:
return false
return true
#击中目标
func hit_target(target: NewPetBase):
"""击中目标"""
# 检查owner_pet是否有效防止已释放对象错误
if not is_instance_valid(owner_pet):
owner_pet = null
# 造成伤害
target.take_damage(damage, owner_pet)
# 发射信号
bullet_hit.emit(self, target)
# 创建击中特效
create_hit_effect(target.global_position)
#=========================通用子弹函数==============================

View File

@@ -0,0 +1 @@
uid://bt57qac8hmg1u

View File

@@ -0,0 +1,29 @@
[gd_scene load_steps=4 format=3 uid="uid://cqtv1dob3dm8b"]
[ext_resource type="Script" uid="uid://bt57qac8hmg1u" path="res://Scene/NewPet/BulletBase.gd" id="1_guena"]
[ext_resource type="Texture2D" uid="uid://by01joyt7e4qh" path="res://assets/子弹图片/01.png" id="2_2q4gn"]
[sub_resource type="CircleShape2D" id="CircleShape2D_1"]
radius = 8.0
[node name="BulletBase" type="Area2D"]
script = ExtResource("1_guena")
[node name="Sprite" type="Sprite2D" parent="."]
modulate = Color(1, 1, 0, 0.8)
scale = Vector2(0.5, 0.5)
texture = ExtResource("2_2q4gn")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("CircleShape2D_1")
[node name="Trail" type="Line2D" parent="."]
width = 2.0
default_color = Color(1, 1, 0, 0.5)
[node name="HitEffect" type="Node2D" parent="."]
[node name="LifeTimer" type="Timer" parent="."]
wait_time = 5.0
one_shot = true
autostart = true

1198
Scene/NewPet/NewPetBase.gd Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
uid://cn6a0803t1bmu

View File

@@ -0,0 +1,146 @@
[gd_scene load_steps=8 format=3 uid="uid://cfwj8rnm2j8s3"]
[ext_resource type="Script" uid="uid://cn6a0803t1bmu" path="res://Scene/NewPet/NewPetBase.gd" id="1_bfbjx"]
[ext_resource type="Texture2D" uid="uid://lx0l12qrituk" path="res://assets/宠物图片/一堆小怪.png" id="2_gnd2w"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="3_bfbjx"]
[sub_resource type="AtlasTexture" id="AtlasTexture_h4hw6"]
atlas = ExtResource("2_gnd2w")
region = Rect2(0, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_51c25"]
atlas = ExtResource("2_gnd2w")
region = Rect2(24, 0, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_wmdx5"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_h4hw6")
}],
"loop": true,
"name": &"idle",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_h4hw6")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_51c25")
}],
"loop": true,
"name": &"walk",
"speed": 8.0
}]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_h4hw6"]
size = Vector2(79, 92)
[node name="PetBase" type="Area2D"]
script = ExtResource("1_bfbjx")
[node name="PetImage" type="AnimatedSprite2D" parent="."]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_wmdx5")
animation = &"walk"
autoplay = "walk"
[node name="LeftToolImage" type="Sprite2D" parent="PetImage"]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("3_bfbjx")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="PetImage"]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("3_bfbjx")
flip_h = true
[node name="VolumeCollision" type="CollisionShape2D" parent="."]
position = Vector2(0.5, 2)
shape = SubResource("RectangleShape2D_h4hw6")
[node name="PetInformVBox" type="VBoxContainer" parent="."]
offset_left = -72.0
offset_top = -261.0
offset_right = 430.0
offset_bottom = 453.0
scale = Vector2(0.3, 0.3)
alignment = 2
[node name="PetNameRichText" type="RichTextLabel" parent="PetInformVBox"]
layout_mode = 2
size_flags_vertical = 3
theme_override_font_sizes/normal_font_size = 40
bbcode_enabled = true
text = "萌芽小绿人"
horizontal_alignment = 1
vertical_alignment = 2
[node name="ArmorBar" type="ProgressBar" parent="PetInformVBox"]
modulate = Color(0.758192, 0.758192, 0.758192, 1)
custom_minimum_size = Vector2(0, 60)
layout_mode = 2
show_percentage = false
[node name="ArmorLabel" type="Label" parent="PetInformVBox/ArmorBar"]
layout_mode = 0
offset_right = 502.0
offset_bottom = 60.0
theme_override_font_sizes/font_size = 30
text = "盔甲值:100/100"
horizontal_alignment = 1
vertical_alignment = 1
[node name="ShieldBar" type="ProgressBar" parent="PetInformVBox"]
modulate = Color(0, 1, 1, 1)
custom_minimum_size = Vector2(0, 60)
layout_mode = 2
show_percentage = false
[node name="ShieldLabel" type="Label" parent="PetInformVBox/ShieldBar"]
layout_mode = 0
offset_right = 502.0
offset_bottom = 60.0
theme_override_font_sizes/font_size = 30
text = "护盾值:100/100"
horizontal_alignment = 1
vertical_alignment = 1
[node name="HealthBar" type="ProgressBar" parent="PetInformVBox"]
modulate = Color(0, 1, 0, 1)
custom_minimum_size = Vector2(0, 60)
layout_mode = 2
show_percentage = false
[node name="HealthLabel" type="Label" parent="PetInformVBox/HealthBar"]
layout_mode = 0
offset_right = 502.0
offset_bottom = 60.0
theme_override_font_sizes/font_size = 30
text = "生命值:100/100"
horizontal_alignment = 1
vertical_alignment = 1
[node name="StatusEffects" type="HBoxContainer" parent="."]
offset_left = -30.0
offset_top = -65.0
offset_right = 30.0
offset_bottom = -55.0
[node name="AttackTimer" type="Timer" parent="."]
[node name="MoveTimer" type="Timer" parent="."]
wait_time = 0.1
autostart = true
[node name="StatusTimer" type="Timer" parent="."]
autostart = true
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
[node name="HitEffect" type="Node2D" parent="."]
[node name="DeathEffect" type="Node2D" parent="."]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
uid://bt06n5cxip4kr

View File

@@ -0,0 +1,318 @@
[gd_scene load_steps=3 format=3 uid="uid://diwbnwhnq026"]
[ext_resource type="Script" uid="uid://bt06n5cxip4kr" path="res://Scene/NewPet/PetBattlePanel.gd" id="1_0uw4q"]
[ext_resource type="Texture2D" uid="uid://dh0dsw3jr0gra" path="res://assets/宠物对战背景图片/背景2.webp" id="2_c80tv"]
[node name="PetBattlePanel" type="Panel"]
offset_right = 1400.0
offset_bottom = 720.0
script = ExtResource("1_0uw4q")
[node name="MapBackGround" type="TextureRect" parent="."]
layout_mode = 0
offset_right = 1557.0
offset_bottom = 867.0
scale = Vector2(0.9, 0.9)
texture = ExtResource("2_c80tv")
[node name="TeamB" type="Node2D" parent="."]
position = Vector2(1239, 421)
[node name="Pos1" type="Marker2D" parent="TeamB"]
position = Vector2(17, -166)
[node name="Pos2" type="Marker2D" parent="TeamB"]
position = Vector2(42, 160)
[node name="Pos3" type="Marker2D" parent="TeamB"]
position = Vector2(42, -38)
[node name="Pos4" type="Marker2D" parent="TeamB"]
position = Vector2(21, -315)
[node name="Pos5" type="Marker2D" parent="TeamB"]
position = Vector2(42, -102)
[node name="Pos6" type="Marker2D" parent="TeamB"]
position = Vector2(42, 96)
[node name="Pos7" type="Marker2D" parent="TeamB"]
position = Vector2(42, 32)
[node name="Pos8" type="Marker2D" parent="TeamB"]
position = Vector2(21, -251)
[node name="Pos9" type="Marker2D" parent="TeamB"]
position = Vector2(42, -230)
[node name="Pos10" type="Marker2D" parent="TeamB"]
position = Vector2(42, 224)
[node name="TeamA" type="Node2D" parent="."]
position = Vector2(138, 134)
[node name="Pos1" type="Marker2D" parent="TeamA"]
position = Vector2(-37, 408)
[node name="Pos2" type="Marker2D" parent="TeamA"]
position = Vector2(-41, 93)
[node name="Pos3" type="Marker2D" parent="TeamA"]
position = Vector2(-38, 313)
[node name="Pos4" type="Marker2D" parent="TeamA"]
position = Vector2(-38, 223)
[node name="Pos5" type="Marker2D" parent="TeamA"]
position = Vector2(-38, 133)
[node name="Pos6" type="Marker2D" parent="TeamA"]
position = Vector2(-38, 43)
[node name="Pos7" type="Marker2D" parent="TeamA"]
position = Vector2(-38, 358)
[node name="Pos8" type="Marker2D" parent="TeamA"]
position = Vector2(-38, 268)
[node name="Pos9" type="Marker2D" parent="TeamA"]
position = Vector2(-38, 178)
[node name="Pos10" type="Marker2D" parent="TeamA"]
position = Vector2(-38, 453)
[node name="PlayerSkillPanel" type="Panel" parent="."]
layout_mode = 0
offset_left = 1143.0
offset_right = 1400.0
offset_bottom = 720.0
[node name="Title" type="Label" parent="PlayerSkillPanel"]
self_modulate = Color(0, 1, 0, 1)
layout_mode = 0
offset_right = 257.0
offset_bottom = 40.0
theme_override_font_sizes/font_size = 25
text = "辅助功能"
horizontal_alignment = 1
vertical_alignment = 1
[node name="TeamASkills" type="VBoxContainer" parent="PlayerSkillPanel"]
layout_mode = 0
offset_top = 50.0
offset_right = 257.0
offset_bottom = 300.0
[node name="TeamAHeal" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "团队治疗"
[node name="TeamARage" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "团队狂暴"
[node name="TeamAShield" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
text = "团队护盾"
[node name="test" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="test2" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="test3" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="test4" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="test5" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="test6" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="test7" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="test8" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="test9" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="test10" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="test11" type="Button" parent="PlayerSkillPanel/TeamASkills"]
layout_mode = 2
theme_override_font_sizes/font_size = 18
disabled = true
text = "测试"
[node name="BattleControls" type="VBoxContainer" parent="PlayerSkillPanel"]
layout_mode = 0
offset_top = 580.0
offset_right = 257.0
offset_bottom = 720.0
[node name="StartBattleButton" type="Button" parent="PlayerSkillPanel/BattleControls"]
visible = false
layout_mode = 2
theme_override_colors/font_color = Color(0, 1, 0, 1)
theme_override_font_sizes/font_size = 20
text = "开始战斗"
[node name="StopBattleButton" type="Button" parent="PlayerSkillPanel/BattleControls"]
layout_mode = 2
theme_override_colors/font_color = Color(1, 0, 0, 1)
theme_override_font_sizes/font_size = 20
text = "逃跑"
[node name="BattleEndPanel" type="Panel" parent="."]
visible = false
top_level = true
layout_mode = 0
offset_left = 294.0
offset_right = 1071.0
offset_bottom = 720.0
[node name="Title" type="Label" parent="BattleEndPanel"]
layout_mode = 0
offset_right = 777.0
offset_bottom = 104.0
theme_override_colors/font_color = Color(0.991435, 0.798103, 0.357309, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 5
theme_override_constants/shadow_offset_y = 5
theme_override_constants/outline_size = 20
theme_override_constants/shadow_outline_size = 20
theme_override_font_sizes/font_size = 60
text = "战斗结束"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Contents" type="RichTextLabel" parent="BattleEndPanel"]
layout_mode = 0
offset_top = 104.0
offset_right = 777.0
offset_bottom = 567.0
theme_override_font_sizes/normal_font_size = 30
bbcode_enabled = true
text = "[宠物名字]获得300经验
增加200亲密度"
horizontal_alignment = 1
[node name="ReturnFarmButton" type="Button" parent="BattleEndPanel"]
layout_mode = 0
offset_left = 294.0
offset_top = 567.0
offset_right = 502.0
offset_bottom = 644.0
theme_override_font_sizes/font_size = 50
text = "返回农场"
[node name="Title" type="Label" parent="."]
layout_mode = 0
offset_right = 1400.0
offset_bottom = 55.0
theme_override_colors/font_color = Color(0.623819, 1, 0.593898, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 5
theme_override_constants/shadow_offset_y = 5
theme_override_constants/outline_size = 20
theme_override_constants/shadow_outline_size = 10
theme_override_font_sizes/font_size = 50
text = "宠物对战"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Time" type="Label" parent="."]
layout_mode = 0
offset_left = 574.0
offset_top = 60.0
offset_right = 813.0
offset_bottom = 129.0
theme_override_colors/font_color = Color(0.623529, 1, 1, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_x = 5
theme_override_constants/shadow_offset_y = 5
theme_override_constants/outline_size = 20
theme_override_constants/shadow_outline_size = 10
theme_override_font_sizes/font_size = 35
text = "[05:00]"
horizontal_alignment = 1
vertical_alignment = 1
[node name="PetBattleDetailsPanel" type="Panel" parent="."]
layout_mode = 0
offset_right = 257.0
offset_bottom = 720.0
[node name="Title" type="Label" parent="PetBattleDetailsPanel"]
layout_mode = 0
offset_right = 257.0
offset_bottom = 23.0
theme_override_font_sizes/font_size = 30
text = "战斗细节"
horizontal_alignment = 1
vertical_alignment = 1
[node name="BattleDetails" type="RichTextLabel" parent="PetBattleDetailsPanel"]
layout_mode = 0
offset_top = 42.0
offset_right = 257.0
offset_bottom = 720.0
bbcode_enabled = true
[node name="ConfirmDialog" type="ConfirmationDialog" parent="."]
title = "弹窗标题"
initial_position = 1
size = Vector2i(400, 300)
unresizable = true
ok_button_text = "确认"
dialog_text = "弹窗内容"
dialog_autowrap = true
cancel_button_text = "取消"
[connection signal="pressed" from="PlayerSkillPanel/TeamASkills/TeamAHeal" to="." method="_on_team_a_heal_pressed"]
[connection signal="pressed" from="PlayerSkillPanel/TeamASkills/TeamARage" to="." method="_on_team_a_rage_pressed"]
[connection signal="pressed" from="PlayerSkillPanel/TeamASkills/TeamAShield" to="." method="_on_team_a_shield_pressed"]
[connection signal="pressed" from="PlayerSkillPanel/BattleControls/StopBattleButton" to="." method="_on_stop_battle_button_pressed"]

396
Scene/NewPet/PetConfig.gd Normal file
View File

@@ -0,0 +1,396 @@
extends Node
class_name PetConfig
# 每一种宠物的配置数据 方便导出JSON数据放到MongoDB数据库上
# 攻击类型枚举(简化为仅近战)
enum AttackType {
MELEE # 近战攻击
}
enum ElementType {
NONE, METAL, WOOD, WATER, FIRE, EARTH, THUNDER
}
enum PetState {
IDLE, # 待机
MOVING, # 移动
ATTACKING, # 攻击中
SKILL_CASTING, # 释放技能
DEAD # 死亡
}
#==========================以下是导出数据可以被修改的=========================================
# 基本属性
var pet_name: String = "萌芽小绿" # 宠物名称
var pet_id: String = "0001" # 宠物唯一编号
var pet_type: String = "小绿" # 宠物种类
var pet_level: int = 1 # 宠物等级
var pet_experience: int = 0 # 宠物经验值
#性格 出生日期 爱好 个人介绍
var pet_temperament: String = "温顺" # 性格
var pet_birthday: String = "2023-01-01" # 出生日期
var pet_hobby: String = "喜欢吃pet" # 爱好
var pet_introduction: String = "我是一个小绿" # 个人介绍
# 生命与防御
var max_health: float = 200.0 # 最大生命值
var enable_health_regen: bool = true # 是否开启生命恢复
var health_regen: float = 1.0 # 每秒生命恢复大小
var enable_shield_regen: bool = true # 是否开启护盾恢复
var max_shield: float = 100.0 # 最大护盾值
var shield_regen: float = 1.0 # 每秒护盾恢复大小
var max_armor: float = 100.0 # 最大护甲值
# 攻击属性
var base_attack_damage: float = 25.0 # 基础攻击力
var crit_rate: float = 0.1 # 暴击几率0~1
var crit_damage: float = 1.5 # 暴击伤害倍率1.5 = 150%伤害)
var armor_penetration: float = 0.0 # 护甲穿透值(直接减少对方护甲值)
#======================以后有新技能在这里添加==============================
# 技能-多发射击
var enable_multi_projectile_skill: bool = false
var multi_projectile_delay: float = 2.0 # 多发射击延迟时间(秒)
# 技能-狂暴模式
var enable_berserker_skill: bool = false
var berserker_bonus: float = 1.5 # 狂暴伤害加成
var berserker_duration: float = 5.0 # 狂暴持续时间(秒)
#技能-自爆
var enable_self_destruct_skill: bool = false
var self_destruct_damage: float = 50.0 # 自爆伤害值
#技能-召唤小弟
var enable_summon_pet_skill: bool = false
var summon_count: int = 1 # 召唤小弟数量
var summon_scale: float = 0.1 # 召唤小弟属性缩放比例10%
#技能-死亡重生
var enable_death_respawn_skill: bool = false
var respawn_health_percentage: float = 0.3 # 重生时恢复的血量百分比30%
#======================以后有新技能在这里添加==============================
# 移动属性
var move_speed: float = 150.0 # 移动速度(像素/秒)
var dodge_rate: float = 0.05 # 闪避概率0~1
# 元素属性
var element_type: ElementType = ElementType.NONE # 元素类型(例如火、水、雷等)
var element_damage_bonus: float = 50.0 # 元素伤害加成(额外元素伤害)
# 武器系统
var left_weapon: String = "" # 左手武器名称
var right_weapon: String = "" # 右手武器名称
# 宠物配置字典 - 用于导出到MongoDB数据库
var pet_configs: Dictionary = {
"烈焰鸟": {
"pet_name": "树萌芽の烈焰鸟",
"can_purchase": true,
"cost": 1000,
"pet_image": "res://Scene/NewPet/PetType/flying_bird.tscn",
"pet_id": "0001",
"pet_type": "烈焰鸟",
"pet_level": 1,
"pet_experience": 500,
"pet_temperament": "勇猛",
"pet_birthday": "2023-03-15",
"pet_hobby": "喜欢战斗和烈火",
"pet_introduction": "我爱吃虫子",
"max_health": 300,
"enable_health_regen": true,
"health_regen": 2,
"enable_shield_regen": true,
"max_shield": 150,
"shield_regen": 1.5,
"max_armor": 120,
"base_attack_damage": 40,
"crit_rate": 0.15,
"crit_damage": 2,
"armor_penetration": 10,
"enable_multi_projectile_skill": true,
"multi_projectile_delay": 2,
"enable_berserker_skill": true,
"berserker_bonus": 1.8,
"berserker_duration": 6,
"enable_self_destruct_skill": false,
"enable_summon_pet_skill": false,
"enable_death_respawn_skill": true,
"respawn_health_percentage": 0.4,
"move_speed": 180,
"dodge_rate": 0.08,
"element_type": "FIRE",
"element_damage_bonus": 75,
"left_weapon": "钻石剑",
"right_weapon": "钻石剑"
},
"大蓝虫": {
"pet_name": "树萌芽の大蓝虫",
"can_purchase": true,
"cost": 1000,
"pet_image": "res://Scene/NewPet/PetType/big_beetle.tscn",
"pet_id": "0002",
"pet_type": "大蓝虫",
"pet_level": 8,
"pet_experience": 320,
"pet_temperament": "冷静",
"pet_birthday": "2023-06-20",
"pet_hobby": "喜欢和小甲壳虫玩",
"pet_introduction": "我是大蓝虫,不是大懒虫!",
"max_health": 180,
"enable_health_regen": true,
"health_regen": 1.2,
"enable_shield_regen": true,
"max_shield": 200,
"shield_regen": 2.5,
"max_armor": 80,
"base_attack_damage": 35,
"crit_rate": 0.12,
"crit_damage": 1.8,
"armor_penetration": 15,
"enable_multi_projectile_skill": true,
"multi_projectile_delay": 1.5,
"enable_berserker_skill": false,
"enable_self_destruct_skill": false,
"enable_summon_pet_skill": true,
"summon_count": 2,
"summon_scale": 0.15,
"enable_death_respawn_skill": false,
"move_speed": 120,
"dodge_rate": 0.12,
"element_type": "WATER",
"element_damage_bonus": 100,
"left_weapon": "钻石剑",
"right_weapon": "钻石剑"
},
"小蓝虫": {
"pet_name": "树萌芽の小蓝虫",
"can_purchase": true,
"cost": 1000,
"pet_image": "res://Scene/NewPet/PetType/small_beetle.tscn",
"pet_id": "0002",
"pet_type": "小蓝虫",
"pet_level": 1,
"pet_experience": 0,
"pet_temperament": "冷静",
"pet_birthday": "2023-06-20",
"pet_hobby": "喜欢和大蓝虫玩",
"pet_introduction": "我是小蓝虫,不是小懒虫!",
"max_health": 90,
"enable_health_regen": true,
"health_regen": 1.2,
"enable_shield_regen": true,
"max_shield": 200,
"shield_regen": 2.5,
"max_armor": 80,
"base_attack_damage": 35,
"crit_rate": 0.12,
"crit_damage": 1.8,
"armor_penetration": 15,
"enable_multi_projectile_skill": true,
"multi_projectile_delay": 1.5,
"enable_berserker_skill": false,
"enable_self_destruct_skill": false,
"enable_summon_pet_skill": true,
"summon_count": 2,
"summon_scale": 0.15,
"enable_death_respawn_skill": false,
"move_speed": 120,
"dodge_rate": 0.12,
"element_type": "WATER",
"element_damage_bonus": 100,
"left_weapon": "钻石剑",
"right_weapon": "钻石剑"
},
"小蓝": {
"pet_name": "树萌芽の小蓝",
"can_purchase": true,
"cost": 1000,
"pet_image": "res://Scene/NewPet/PetType/small_blue.tscn",
"pet_id": "0002",
"pet_type": "小蓝",
"pet_level": 1,
"pet_experience": 0,
"pet_temperament": "冷静",
"pet_birthday": "2023-06-20",
"pet_hobby": "喜欢和小黄一起玩",
"pet_introduction": "我是小黄!",
"max_health": 120,
"enable_health_regen": true,
"health_regen": 1.2,
"enable_shield_regen": true,
"max_shield": 200,
"shield_regen": 2.5,
"max_armor": 80,
"base_attack_damage": 35,
"crit_rate": 0.12,
"crit_damage": 1.8,
"armor_penetration": 15,
"enable_multi_projectile_skill": true,
"multi_projectile_delay": 1.5,
"enable_berserker_skill": false,
"enable_self_destruct_skill": false,
"enable_summon_pet_skill": true,
"summon_count": 2,
"summon_scale": 0.15,
"enable_death_respawn_skill": false,
"move_speed": 120,
"dodge_rate": 0.12,
"element_type": "WATER",
"element_damage_bonus": 100,
"left_weapon": "钻石剑",
"right_weapon": "钻石剑"
}
}
# 初始化函数
func _ready():
"""节点准备就绪时自动加载JSON配置"""
load_configs_from_json()
# 手动初始化配置的函数
func initialize_configs():
"""手动初始化宠物配置优先从JSON加载"""
if not load_configs_from_json():
print("JSON加载失败使用默认配置")
# 如果JSON加载失败保持使用代码中的默认配置
# 获取宠物配置的函数
func get_pet_config(pet_key: String) -> Dictionary:
"""根据宠物键值获取配置"""
if pet_configs.has(pet_key):
return pet_configs[pet_key]
else:
print("未找到宠物配置: ", pet_key, ",使用默认配置")
return get_default_config()
# 获取所有宠物配置键值的函数
func get_all_pet_keys() -> Array:
"""获取所有可用的宠物配置键值"""
return pet_configs.keys()
# 检查宠物配置是否存在的函数
func has_pet_config(pet_key: String) -> bool:
"""检查指定的宠物配置是否存在"""
return pet_configs.has(pet_key)
# 获取默认配置的函数
func get_default_config() -> Dictionary:
"""获取默认宠物配置"""
return {
"pet_name": pet_name,
"pet_id": pet_id,
"pet_type": pet_type,
"pet_level": pet_level,
"pet_experience": pet_experience,
"pet_temperament": pet_temperament,
"pet_birthday": pet_birthday,
"pet_hobby": pet_hobby,
"pet_introduction": pet_introduction,
"max_health": max_health,
"enable_health_regen": enable_health_regen,
"health_regen": health_regen,
"enable_shield_regen": enable_shield_regen,
"max_shield": max_shield,
"shield_regen": shield_regen,
"max_armor": max_armor,
"base_attack_damage": base_attack_damage,
"crit_rate": crit_rate,
"crit_damage": crit_damage,
"armor_penetration": armor_penetration,
"enable_multi_projectile_skill": enable_multi_projectile_skill,
"multi_projectile_delay": multi_projectile_delay,
"enable_berserker_skill": enable_berserker_skill,
"berserker_bonus": berserker_bonus,
"berserker_duration": berserker_duration,
"enable_self_destruct_skill": enable_self_destruct_skill,
"self_destruct_damage": self_destruct_damage,
"enable_summon_pet_skill": enable_summon_pet_skill,
"summon_count": summon_count,
"summon_scale": summon_scale,
"enable_death_respawn_skill": enable_death_respawn_skill,
"respawn_health_percentage": respawn_health_percentage,
"move_speed": move_speed,
"dodge_rate": dodge_rate,
"element_type": element_type,
"element_damage_bonus": element_damage_bonus,
"left_weapon": left_weapon,
"right_weapon": right_weapon
}
# 字符串转换为ElementType枚举的函数
func string_to_element_type(element_str: String) -> ElementType:
"""将字符串转换为ElementType枚举"""
match element_str.to_upper():
"NONE":#没有元素类型
return ElementType.NONE
"METAL":#金元素
return ElementType.METAL
"WOOD":#木元素
return ElementType.WOOD
"WATER":#水元素
return ElementType.WATER
"FIRE": #火元素
return ElementType.FIRE
"EARTH":#土元素
return ElementType.EARTH
"THUNDER":#雷元素
return ElementType.THUNDER
_:
return ElementType.NONE
# 从JSON文件加载宠物配置的函数
func load_configs_from_json(file_path: String = "res://Scene/NewPet/Pet_data.json") -> bool:
"""从JSON文件加载宠物配置"""
if not FileAccess.file_exists(file_path):
print("宠物配置文件不存在: ", file_path)
return false
var file = FileAccess.open(file_path, FileAccess.READ)
if file == null:
print("无法打开宠物配置文件: ", file_path)
return false
var json_string = file.get_as_text()
file.close()
var json = JSON.new()
var parse_result = json.parse(json_string)
if parse_result != OK:
print("JSON解析失败: ", json.error_string)
return false
var loaded_configs = json.data
if typeof(loaded_configs) != TYPE_DICTIONARY:
print("JSON格式错误期望字典类型")
return false
# 清空现有配置并加载新配置
pet_configs.clear()
# 遍历加载的配置
for pet_key in loaded_configs.keys():
var config = loaded_configs[pet_key]
if typeof(config) != TYPE_DICTIONARY:
print("跳过无效的宠物配置: ", pet_key)
continue
# 处理element_type字符串转换为枚举
if config.has("element_type") and typeof(config["element_type"]) == TYPE_STRING:
config["element_type"] = string_to_element_type(config["element_type"])
# 添加到配置字典
pet_configs[pet_key] = config
print("成功从JSON加载了 ", pet_configs.size(), " 个宠物配置")
return true
# 导出配置到JSON的函数
func export_configs_to_json() -> String:
"""将宠物配置导出为JSON字符串用于保存到MongoDB"""
return JSON.stringify(pet_configs)

View File

@@ -0,0 +1 @@
uid://l31ap5jcuyfl

View File

@@ -0,0 +1,68 @@
[gd_scene load_steps=8 format=3 uid="uid://ba85asiwug57i"]
[ext_resource type="Texture2D" uid="uid://lx0l12qrituk" path="res://assets/宠物图片/一堆小怪.png" id="1_4f76q"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_vbyii"]
[sub_resource type="AtlasTexture" id="AtlasTexture_op7i3"]
atlas = ExtResource("1_4f76q")
region = Rect2(72, 48, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_c36rm"]
atlas = ExtResource("1_4f76q")
region = Rect2(120, 48, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_mjdfm"]
atlas = ExtResource("1_4f76q")
region = Rect2(72, 48, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_q454c"]
atlas = ExtResource("1_4f76q")
region = Rect2(96, 48, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_b73qu"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_op7i3")
}],
"loop": true,
"name": &"idle",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_c36rm")
}],
"loop": true,
"name": &"sleep",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_mjdfm")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_q454c")
}],
"loop": true,
"name": &"walk",
"speed": 5.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_b73qu")
animation = &"walk"
autoplay = "walk"
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_vbyii")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_vbyii")
flip_h = true

View File

@@ -0,0 +1,64 @@
[gd_scene load_steps=8 format=3 uid="uid://bpkq40vvq3cxy"]
[ext_resource type="Texture2D" uid="uid://lx0l12qrituk" path="res://assets/宠物图片/一堆小怪.png" id="1_lxn61"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_wrr70"]
[sub_resource type="AtlasTexture" id="AtlasTexture_lgi35"]
atlas = ExtResource("1_lxn61")
region = Rect2(192, 48, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_wn6km"]
atlas = ExtResource("1_lxn61")
region = Rect2(144, 48, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_qmpjj"]
atlas = ExtResource("1_lxn61")
region = Rect2(168, 48, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_1mpkc"]
atlas = ExtResource("1_lxn61")
region = Rect2(192, 48, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_b73qu"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_lgi35")
}],
"loop": true,
"name": &"idle",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_wn6km")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_qmpjj")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_1mpkc")
}],
"loop": true,
"name": &"walk",
"speed": 10.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_b73qu")
animation = &"walk"
autoplay = "walk"
frame_progress = 0.111287
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_wrr70")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_wrr70")
flip_h = true

View File

@@ -0,0 +1,103 @@
[gd_scene load_steps=13 format=3 uid="uid://dvkix032ikul3"]
[ext_resource type="Texture2D" uid="uid://b75oytao5cgjo" path="res://assets/宠物图片/绿色史莱姆.png" id="1_m1ura"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_58kah"]
[sub_resource type="AtlasTexture" id="AtlasTexture_ou315"]
atlas = ExtResource("1_m1ura")
region = Rect2(0, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_saxlb"]
atlas = ExtResource("1_m1ura")
region = Rect2(72, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_bxslx"]
atlas = ExtResource("1_m1ura")
region = Rect2(48, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_dvhl1"]
atlas = ExtResource("1_m1ura")
region = Rect2(24, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_0t1ns"]
atlas = ExtResource("1_m1ura")
region = Rect2(0, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_sbjn0"]
atlas = ExtResource("1_m1ura")
region = Rect2(72, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_qvnbx"]
atlas = ExtResource("1_m1ura")
region = Rect2(48, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_n0kjo"]
atlas = ExtResource("1_m1ura")
region = Rect2(24, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_obu0n"]
atlas = ExtResource("1_m1ura")
region = Rect2(0, 24, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_yhcbw"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_ou315")
}],
"loop": true,
"name": &"idle",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_saxlb")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_bxslx")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_dvhl1")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_0t1ns")
}],
"loop": false,
"name": &"wake",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_sbjn0")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_qvnbx")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_n0kjo")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_obu0n")
}],
"loop": true,
"name": &"walk",
"speed": 8.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_yhcbw")
animation = &"idle"
autoplay = "walk"
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_58kah")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_58kah")
flip_h = true

View File

@@ -0,0 +1,176 @@
[gd_scene load_steps=24 format=3 uid="uid://dwdoine3llw30"]
[ext_resource type="Texture2D" uid="uid://bal78ts2eq4yu" path="res://assets/宠物图片/护卫.png" id="1_4imwo"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_ywvjf"]
[sub_resource type="AtlasTexture" id="AtlasTexture_rjt8u"]
atlas = ExtResource("1_4imwo")
region = Rect2(224, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_81r1q"]
atlas = ExtResource("1_4imwo")
region = Rect2(192, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_nliwy"]
atlas = ExtResource("1_4imwo")
region = Rect2(160, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_kbr5d"]
atlas = ExtResource("1_4imwo")
region = Rect2(128, 0, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_yhrjc"]
atlas = ExtResource("1_4imwo")
region = Rect2(224, 64, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_2dbgw"]
atlas = ExtResource("1_4imwo")
region = Rect2(192, 64, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_h0n46"]
atlas = ExtResource("1_4imwo")
region = Rect2(160, 64, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_1tk7r"]
atlas = ExtResource("1_4imwo")
region = Rect2(128, 64, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_ogy1e"]
atlas = ExtResource("1_4imwo")
region = Rect2(96, 64, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_mygjj"]
atlas = ExtResource("1_4imwo")
region = Rect2(64, 64, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_rkj0j"]
atlas = ExtResource("1_4imwo")
region = Rect2(32, 64, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_j7anc"]
atlas = ExtResource("1_4imwo")
region = Rect2(0, 64, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_cxgnv"]
atlas = ExtResource("1_4imwo")
region = Rect2(224, 96, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_2itrd"]
atlas = ExtResource("1_4imwo")
region = Rect2(192, 96, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_c7ofb"]
atlas = ExtResource("1_4imwo")
region = Rect2(160, 96, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_aa4e4"]
atlas = ExtResource("1_4imwo")
region = Rect2(128, 96, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_jx5oo"]
atlas = ExtResource("1_4imwo")
region = Rect2(96, 96, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_umo24"]
atlas = ExtResource("1_4imwo")
region = Rect2(64, 96, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_853s8"]
atlas = ExtResource("1_4imwo")
region = Rect2(32, 96, 32, 32)
[sub_resource type="AtlasTexture" id="AtlasTexture_6x5xm"]
atlas = ExtResource("1_4imwo")
region = Rect2(0, 96, 32, 32)
[sub_resource type="SpriteFrames" id="SpriteFrames_yhcbw"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_rjt8u")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_81r1q")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_nliwy")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_kbr5d")
}],
"loop": true,
"name": &"idle",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_yhrjc")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_2dbgw")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_h0n46")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_1tk7r")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ogy1e")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_mygjj")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_rkj0j")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_j7anc")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_cxgnv")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_2itrd")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_c7ofb")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_aa4e4")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_jx5oo")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_umo24")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_853s8")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_6x5xm")
}],
"loop": true,
"name": &"walk",
"speed": 8.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_yhcbw")
animation = &"walk"
autoplay = "walk"
frame_progress = 0.272604
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_ywvjf")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_ywvjf")
flip_h = true

View File

@@ -0,0 +1,104 @@
[gd_scene load_steps=13 format=3 uid="uid://c8siga6au2vqh"]
[ext_resource type="Texture2D" uid="uid://cvpsjlje7q3to" path="res://assets/宠物图片/红色史莱姆.png" id="1_2d2gf"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_ni2i3"]
[sub_resource type="AtlasTexture" id="AtlasTexture_s7ip1"]
atlas = ExtResource("1_2d2gf")
region = Rect2(0, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_ff7pm"]
atlas = ExtResource("1_2d2gf")
region = Rect2(72, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_53j2r"]
atlas = ExtResource("1_2d2gf")
region = Rect2(48, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_0ij01"]
atlas = ExtResource("1_2d2gf")
region = Rect2(24, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_20513"]
atlas = ExtResource("1_2d2gf")
region = Rect2(0, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_3f8fr"]
atlas = ExtResource("1_2d2gf")
region = Rect2(72, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_kbexh"]
atlas = ExtResource("1_2d2gf")
region = Rect2(48, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_njkpw"]
atlas = ExtResource("1_2d2gf")
region = Rect2(24, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_xbspe"]
atlas = ExtResource("1_2d2gf")
region = Rect2(0, 24, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_yhcbw"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_s7ip1")
}],
"loop": true,
"name": &"idle",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_ff7pm")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_53j2r")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_0ij01")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_20513")
}],
"loop": false,
"name": &"wake",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_3f8fr")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_kbexh")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_njkpw")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_xbspe")
}],
"loop": true,
"name": &"walk",
"speed": 8.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_yhcbw")
animation = &"walk"
autoplay = "walk"
frame_progress = 0.528863
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_ni2i3")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_ni2i3")
flip_h = true

View File

@@ -0,0 +1,64 @@
[gd_scene load_steps=7 format=3 uid="uid://bk5di5uq6bo04"]
[ext_resource type="Texture2D" uid="uid://lx0l12qrituk" path="res://assets/宠物图片/一堆小怪.png" id="1_rph6q"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_bks4n"]
[sub_resource type="AtlasTexture" id="AtlasTexture_nswws"]
atlas = ExtResource("1_rph6q")
region = Rect2(0, 48, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_mjdfm"]
atlas = ExtResource("1_rph6q")
region = Rect2(48, 48, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_1eo38"]
atlas = ExtResource("1_rph6q")
region = Rect2(24, 48, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_b73qu"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_nswws")
}],
"loop": true,
"name": &"idle",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_mjdfm")
}],
"loop": true,
"name": &"sleep",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_nswws")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_1eo38")
}],
"loop": true,
"name": &"walk",
"speed": 5.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_b73qu")
animation = &"walk"
autoplay = "walk"
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_bks4n")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_bks4n")
flip_h = true

View File

@@ -0,0 +1,52 @@
[gd_scene load_steps=6 format=3 uid="uid://d1sj6wl3mfpo3"]
[ext_resource type="Texture2D" uid="uid://lx0l12qrituk" path="res://assets/宠物图片/一堆小怪.png" id="1_6fty5"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_4lqxb"]
[sub_resource type="AtlasTexture" id="AtlasTexture_stamd"]
atlas = ExtResource("1_6fty5")
region = Rect2(48, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_v0b4v"]
atlas = ExtResource("1_6fty5")
region = Rect2(72, 0, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_b2ss3"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_stamd")
}],
"loop": true,
"name": &"idle",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_stamd")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_v0b4v")
}],
"loop": true,
"name": &"walk",
"speed": 8.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_b2ss3")
animation = &"walk"
autoplay = "walk"
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_4lqxb")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_4lqxb")
flip_h = true

View File

@@ -0,0 +1,64 @@
[gd_scene load_steps=7 format=3 uid="uid://dkvo63yforem7"]
[ext_resource type="Texture2D" uid="uid://lx0l12qrituk" path="res://assets/宠物图片/一堆小怪.png" id="1_x37sh"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_w6fwq"]
[sub_resource type="AtlasTexture" id="AtlasTexture_j2fq3"]
atlas = ExtResource("1_x37sh")
region = Rect2(144, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_6q1oc"]
atlas = ExtResource("1_x37sh")
region = Rect2(192, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_xvdwk"]
atlas = ExtResource("1_x37sh")
region = Rect2(168, 24, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_6q1oc"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_j2fq3")
}],
"loop": true,
"name": &"idle",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_6q1oc")
}],
"loop": true,
"name": &"sleep",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_j2fq3")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_xvdwk")
}],
"loop": true,
"name": &"walk",
"speed": 8.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_6q1oc")
animation = &"walk"
autoplay = "walk"
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_w6fwq")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_w6fwq")
flip_h = true

View File

@@ -0,0 +1,56 @@
[gd_scene load_steps=7 format=3 uid="uid://bpsoc04xlvhqa"]
[ext_resource type="Texture2D" uid="uid://lx0l12qrituk" path="res://assets/宠物图片/一堆小怪.png" id="1_i7yg5"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_wo7be"]
[sub_resource type="AtlasTexture" id="AtlasTexture_5gxwu"]
atlas = ExtResource("1_i7yg5")
region = Rect2(0, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_pxsqn"]
atlas = ExtResource("1_i7yg5")
region = Rect2(0, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_xxlll"]
atlas = ExtResource("1_i7yg5")
region = Rect2(24, 0, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_k25pl"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_5gxwu")
}],
"loop": true,
"name": &"idle",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_pxsqn")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_xxlll")
}],
"loop": true,
"name": &"walk",
"speed": 8.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_k25pl")
animation = &"idle"
autoplay = "walk"
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_wo7be")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_wo7be")
flip_h = true

View File

@@ -0,0 +1,52 @@
[gd_scene load_steps=6 format=3 uid="uid://bk7wkksxa7150"]
[ext_resource type="Texture2D" uid="uid://lx0l12qrituk" path="res://assets/宠物图片/一堆小怪.png" id="1_4x5tv"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_iom1h"]
[sub_resource type="AtlasTexture" id="AtlasTexture_tdtxh"]
atlas = ExtResource("1_4x5tv")
region = Rect2(0, 24, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_5rxf3"]
atlas = ExtResource("1_4x5tv")
region = Rect2(24, 24, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_ujsmd"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_tdtxh")
}],
"loop": true,
"name": &"idle",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_tdtxh")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_5rxf3")
}],
"loop": true,
"name": &"walk",
"speed": 8.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_ujsmd")
animation = &"walk"
autoplay = "walk"
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_iom1h")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_iom1h")
flip_h = true

View File

@@ -0,0 +1,56 @@
[gd_scene load_steps=7 format=3 uid="uid://cxj61dijvapdt"]
[ext_resource type="Texture2D" uid="uid://lx0l12qrituk" path="res://assets/宠物图片/一堆小怪.png" id="1_wkxhn"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_xic1v"]
[sub_resource type="AtlasTexture" id="AtlasTexture_cxnqb"]
atlas = ExtResource("1_wkxhn")
region = Rect2(96, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_auciw"]
atlas = ExtResource("1_wkxhn")
region = Rect2(96, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_nrp4g"]
atlas = ExtResource("1_wkxhn")
region = Rect2(120, 0, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_b2ss3"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_cxnqb")
}],
"loop": true,
"name": &"idle",
"speed": 8.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_auciw")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_nrp4g")
}],
"loop": true,
"name": &"walk",
"speed": 8.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_b2ss3")
animation = &"idle"
autoplay = "walk"
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_xic1v")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_xic1v")
flip_h = true

View File

@@ -0,0 +1,52 @@
[gd_scene load_steps=6 format=3 uid="uid://is5klrhiktg4"]
[ext_resource type="Texture2D" uid="uid://lx0l12qrituk" path="res://assets/宠物图片/一堆小怪.png" id="1_qrx6w"]
[ext_resource type="Texture2D" uid="uid://dciakkwnchcga" path="res://assets/我的世界图片/武器工具/木剑.png" id="2_dkex0"]
[sub_resource type="AtlasTexture" id="AtlasTexture_trhvc"]
atlas = ExtResource("1_qrx6w")
region = Rect2(144, 0, 24, 24)
[sub_resource type="AtlasTexture" id="AtlasTexture_k5jn7"]
atlas = ExtResource("1_qrx6w")
region = Rect2(168, 0, 24, 24)
[sub_resource type="SpriteFrames" id="SpriteFrames_yhcbw"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_trhvc")
}],
"loop": true,
"name": &"idle",
"speed": 5.0
}, {
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_trhvc")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_k5jn7")
}],
"loop": true,
"name": &"walk",
"speed": 8.0
}]
[node name="PetImage" type="AnimatedSprite2D"]
scale = Vector2(4, 4)
sprite_frames = SubResource("SpriteFrames_yhcbw")
animation = &"walk"
autoplay = "walk"
[node name="LeftToolImage" type="Sprite2D" parent="."]
z_index = 5
position = Vector2(-10.5, 3)
texture = ExtResource("2_dkex0")
flip_h = true
[node name="RightToolImage" type="Sprite2D" parent="."]
show_behind_parent = true
position = Vector2(-7.5, -6.25)
texture = ExtResource("2_dkex0")
flip_h = true

81
Scene/NewPet/Pet_bag.json Normal file
View File

@@ -0,0 +1,81 @@
{
"宠物仓库":{
"烈焰鸟": {
"pet_name": "树萌芽の烈焰鸟",
"pet_image":"res://Scene/NewPet/PetType/flying_bird.tscn",
"pet_id": "wea1212w12",
"pet_type": "烈焰鸟",
"pet_level": 1,
"pet_experience": 500,
"pet_temperament": "勇猛",
"pet_birthday": "2025-07-25",
"pet_hobby": "喜欢战斗和烈火",
"pet_introduction": "我爱吃虫子",
"max_health": 300.0,
"enable_health_regen": true,
"health_regen": 2.0,
"enable_shield_regen": true,
"max_shield": 150.0,
"shield_regen": 1.5,
"max_armor": 120.0,
"base_attack_damage": 40.0,
"crit_rate": 0.15,
"crit_damage": 2.0,
"armor_penetration": 10.0,
"enable_multi_projectile_skill": true,
"multi_projectile_delay": 2.0,
"enable_berserker_skill": true,
"berserker_bonus": 1.8,
"berserker_duration": 6.0,
"enable_self_destruct_skill": false,
"enable_summon_pet_skill": false,
"enable_death_respawn_skill": true,
"respawn_health_percentage": 0.4,
"move_speed": 180.0,
"dodge_rate": 0.08,
"element_type": "FIRE",
"element_damage_bonus": 75.0,
"left_weapon": "钻石剑",
"right_weapon": "钻石剑"
},
"大蓝虫": {
"pet_name": "树萌芽の大蓝虫",
"pet_image":"res://Scene/NewPet/PetType/big_beetle.tscn",
"pet_id": "dlc123123",
"pet_type": "大甲壳虫",
"pet_level": 8,
"pet_experience": 320,
"pet_temperament": "冷静",
"pet_birthday": "2023-06-20",
"pet_hobby": "喜欢和小甲壳虫玩",
"pet_introduction": "我是大蓝虫,不是大懒虫!",
"max_health": 180.0,
"enable_health_regen": true,
"health_regen": 1.2,
"enable_shield_regen": true,
"max_shield": 200.0,
"shield_regen": 2.5,
"max_armor": 80.0,
"base_attack_damage": 35.0,
"crit_rate": 0.12,
"crit_damage": 1.8,
"armor_penetration": 15.0,
"enable_multi_projectile_skill": true,
"multi_projectile_delay": 1.5,
"enable_berserker_skill": false,
"enable_self_destruct_skill": false,
"enable_summon_pet_skill": true,
"summon_count": 2,
"summon_scale": 0.15,
"enable_death_respawn_skill": false,
"move_speed": 120.0,
"dodge_rate": 0.12,
"element_type": "WATER",
"element_damage_bonus": 100.0,
"left_weapon": "钻石剑",
"right_weapon": "钻石剑"
}
},
"巡逻宠物":["wea1212w12"],
"出战宠物":["dlc123123"]
}

165
Scene/NewPet/Pet_data.json Normal file
View File

@@ -0,0 +1,165 @@
{
"_id": {
"$oid": "687cf59b8e77ba00a7414bab"
},
"updated_at": {
"$date": "2025-07-20T22:13:38.521Z"
},
"烈焰鸟": {
"pet_name": "树萌芽の烈焰鸟",
"can_purchase": true,
"cost": 1000,
"pet_image": "res://Scene/NewPet/PetType/flying_bird.tscn",
"pet_id": "0001",
"pet_type": "烈焰鸟",
"pet_level": 1,
"pet_experience": 500,
"pet_temperament": "勇猛",
"pet_birthday": "2023-03-15",
"pet_hobby": "喜欢战斗和烈火",
"pet_introduction": "我爱吃虫子",
"max_health": 300,
"enable_health_regen": true,
"health_regen": 2,
"enable_shield_regen": true,
"max_shield": 150,
"shield_regen": 1.5,
"max_armor": 120,
"base_attack_damage": 40,
"crit_rate": 0.15,
"crit_damage": 2,
"armor_penetration": 10,
"enable_multi_projectile_skill": true,
"multi_projectile_delay": 2,
"enable_berserker_skill": true,
"berserker_bonus": 1.8,
"berserker_duration": 6,
"enable_self_destruct_skill": false,
"enable_summon_pet_skill": false,
"enable_death_respawn_skill": true,
"respawn_health_percentage": 0.4,
"move_speed": 180,
"dodge_rate": 0.08,
"element_type": "FIRE",
"element_damage_bonus": 75,
"left_weapon": "钻石剑",
"right_weapon": "钻石剑"
},
"大蓝虫": {
"pet_name": "树萌芽の大蓝虫",
"can_purchase": true,
"cost": 1000,
"pet_image": "res://Scene/NewPet/PetType/big_beetle.tscn",
"pet_id": "0002",
"pet_type": "大蓝虫",
"pet_level": 8,
"pet_experience": 320,
"pet_temperament": "冷静",
"pet_birthday": "2023-06-20",
"pet_hobby": "喜欢和小甲壳虫玩",
"pet_introduction": "我是大蓝虫,不是大懒虫!",
"max_health": 180,
"enable_health_regen": true,
"health_regen": 1.2,
"enable_shield_regen": true,
"max_shield": 200,
"shield_regen": 2.5,
"max_armor": 80,
"base_attack_damage": 35,
"crit_rate": 0.12,
"crit_damage": 1.8,
"armor_penetration": 15,
"enable_multi_projectile_skill": true,
"multi_projectile_delay": 1.5,
"enable_berserker_skill": false,
"enable_self_destruct_skill": false,
"enable_summon_pet_skill": true,
"summon_count": 2,
"summon_scale": 0.15,
"enable_death_respawn_skill": false,
"move_speed": 120,
"dodge_rate": 0.12,
"element_type": "WATER",
"element_damage_bonus": 100,
"left_weapon": "钻石剑",
"right_weapon": "钻石剑"
},
"小蓝虫": {
"pet_name": "树萌芽の小蓝虫",
"can_purchase": true,
"cost": 1000,
"pet_image": "res://Scene/NewPet/PetType/small_beetle.tscn",
"pet_id": "0002",
"pet_type": "小蓝虫",
"pet_level": 1,
"pet_experience": 0,
"pet_temperament": "冷静",
"pet_birthday": "2023-06-20",
"pet_hobby": "喜欢和大蓝虫玩",
"pet_introduction": "我是小蓝虫,不是小懒虫!",
"max_health": 90,
"enable_health_regen": true,
"health_regen": 1.2,
"enable_shield_regen": true,
"max_shield": 200,
"shield_regen": 2.5,
"max_armor": 80,
"base_attack_damage": 35,
"crit_rate": 0.12,
"crit_damage": 1.8,
"armor_penetration": 15,
"enable_multi_projectile_skill": true,
"multi_projectile_delay": 1.5,
"enable_berserker_skill": false,
"enable_self_destruct_skill": false,
"enable_summon_pet_skill": true,
"summon_count": 2,
"summon_scale": 0.15,
"enable_death_respawn_skill": false,
"move_speed": 120,
"dodge_rate": 0.12,
"element_type": "WATER",
"element_damage_bonus": 100,
"left_weapon": "钻石剑",
"right_weapon": "钻石剑"
},
"小蓝": {
"pet_name": "树萌芽の小蓝",
"can_purchase": true,
"cost": 1000,
"pet_image": "res://Scene/NewPet/PetType/small_blue.tscn",
"pet_id": "0002",
"pet_type": "小蓝",
"pet_level": 1,
"pet_experience": 0,
"pet_temperament": "冷静",
"pet_birthday": "2023-06-20",
"pet_hobby": "喜欢和小黄一起玩",
"pet_introduction": "我是小黄!",
"max_health": 120,
"enable_health_regen": true,
"health_regen": 1.2,
"enable_shield_regen": true,
"max_shield": 200,
"shield_regen": 2.5,
"max_armor": 80,
"base_attack_damage": 35,
"crit_rate": 0.12,
"crit_damage": 1.8,
"armor_penetration": 15,
"enable_multi_projectile_skill": true,
"multi_projectile_delay": 1.5,
"enable_berserker_skill": false,
"enable_self_destruct_skill": false,
"enable_summon_pet_skill": true,
"summon_count": 2,
"summon_scale": 0.15,
"enable_death_respawn_skill": false,
"move_speed": 120,
"dodge_rate": 0.12,
"element_type": "WATER",
"element_damage_bonus": 100,
"left_weapon": "钻石剑",
"right_weapon": "钻石剑"
}
}

128
Scene/NewPet/WeaponBase.gd Normal file
View File

@@ -0,0 +1,128 @@
extends Node
class_name WeaponBase
#武器系统
var weapon_data = {
"钻石剑": {
"icon": 'res://assets/我的世界图片/武器工具/钻石剑.png',
"function": "apply_diamond_sword_effect"
},
"铁剑": {
"icon": 'res://assets/我的世界图片/武器工具/铁剑.png',
"function": "apply_iron_sword_effect"
},
"钻石斧": {
"icon": 'res://assets/我的世界图片/武器工具/钻石斧.png',
"function": "apply_diamond_axe_effect"
},
"铁镐": {
"icon": 'res://assets/我的世界图片/武器工具/铁镐.png',
"function": "apply_iron_pickaxe_effect"
}
}
# 武器效果函数 - 每种武器单独一个函数
#================钻石剑效果========================
# 钻石剑效果
func apply_diamond_sword_effect(pet):
pet.base_attack_damage += 15.0
pet.crit_rate += 0.1
pet.attack_speed += 0.2
# 钻石剑效果已应用
# 移除钻石剑效果
func remove_diamond_sword_effect(pet):
pet.base_attack_damage -= 15.0
pet.crit_rate -= 0.1
pet.attack_speed -= 0.2
# 钻石剑效果已移除
#================钻石剑效果========================
#================铁剑效果========================
# 铁剑效果
func apply_iron_sword_effect(pet):
pet.base_attack_damage += 10.0
pet.crit_rate += 0.05
pet.attack_speed += 0.1
# 铁剑效果已应用
# 移除铁剑效果
func remove_iron_sword_effect(pet):
pet.base_attack_damage -= 10.0
pet.crit_rate -= 0.05
pet.attack_speed -= 0.1
# 铁剑效果已移除
#================铁剑效果========================
#================钻石斧效果========================
# 钻石斧效果
func apply_diamond_axe_effect(pet):
pet.base_attack_damage += 20.0
pet.armor_penetration += 0.2
pet.knockback_force += 100.0
# 钻石斧效果已应用
# 移除钻石斧效果
func remove_diamond_axe_effect(pet):
pet.base_attack_damage -= 20.0
pet.armor_penetration -= 0.2
pet.knockback_force -= 100.0
# 钻石斧效果已移除
#================钻石斧效果========================
#================铁镐效果========================
# 铁镐效果
func apply_iron_pickaxe_effect(pet):
pet.base_attack_damage += 8.0
pet.armor_penetration += 0.3
pet.attack_range += 20.0
# 铁镐效果已应用
# 移除铁镐效果
func remove_iron_pickaxe_effect(pet):
pet.base_attack_damage -= 8.0
pet.armor_penetration -= 0.3
pet.attack_range -= 20.0
# 铁镐效果已移除
#================铁镐效果========================
#======================武器系统通用函数==========================
# 应用武器效果的主函数
func apply_weapon_effect(pet, weapon_name: String):
if not weapon_data.has(weapon_name):
return
var weapon = weapon_data[weapon_name]
var function_name = weapon.get("function", "")
if function_name != "":
call(function_name, pet)
# 移除武器效果的函数
func remove_weapon_effect(pet, weapon_name: String):
if not weapon_data.has(weapon_name):
return
var weapon = weapon_data[weapon_name]
var function_name = weapon.get("function", "")
if function_name != "":
# 将apply替换为remove来调用移除函数
var remove_function_name = function_name.replace("apply_", "remove_")
call(remove_function_name, pet)
# 获取武器图标路径
func get_weapon_icon(weapon_name: String) -> String:
if weapon_data.has(weapon_name):
return weapon_data[weapon_name].get("icon", "")
return ""
# 获取所有武器名称列表
func get_all_weapon_names() -> Array:
return weapon_data.keys()
#======================武器系统通用函数==========================

View File

@@ -0,0 +1 @@
uid://bpa6hp1mm6sj1

View File

@@ -293,7 +293,7 @@ func _show_item_info(item_name: String, item_count: int):
info_text += "描述: " + description info_text += "描述: " + description
if not _is_item_usable(item_name): if not _is_item_usable(item_name):
info_text += "\n注意: 此道具功能暂未实现" pass
else: else:
info_text = item_name + " (数量: " + str(item_count) + ")\n描述: 暂无信息" info_text = item_name + " (数量: " + str(item_count) + ")\n描述: 暂无信息"
@@ -363,7 +363,7 @@ func _send_farm_item_use_request(item_name: String):
# 发送请求 # 发送请求
tcp_network_manager_panel.send_message(message) tcp_network_manager_panel.send_message(message)
Toast.show("正在使用道具...", Color.BLUE, 2.0, 1.0) #Toast.show("正在使用道具...", Color.BLUE, 2.0, 1.0)
# 显示宠物使用道具确认对话框 # 显示宠物使用道具确认对话框
func _show_pet_item_confirmation_dialog(item_name: String, item_count: int): func _show_pet_item_confirmation_dialog(item_name: String, item_count: int):
@@ -431,13 +431,12 @@ func _send_pet_item_use_request(item_name: String, pet_id: String):
# 退出宠物使用道具模式 # 退出宠物使用道具模式
_exit_pet_item_mode() _exit_pet_item_mode()
Toast.show("正在使用道具...", Color.BLUE, 2.0, 1.0) #Toast.show("正在使用道具...", Color.BLUE, 2.0, 1.0)
# 退出宠物使用道具模式 # 退出宠物使用道具模式
func _exit_pet_item_mode(): func _exit_pet_item_mode():
is_pet_item_mode = false is_pet_item_mode = false
current_pet_data = {} current_pet_data = {}
# 刷新UI # 刷新UI
update_item_bag_ui() update_item_bag_ui()
@@ -496,13 +495,12 @@ func _on_quit_button_pressed() -> void:
func _on_refresh_button_pressed() -> void: func _on_refresh_button_pressed() -> void:
# 刷新道具背包UI # 刷新道具背包UI
update_item_bag_ui() update_item_bag_ui()
Toast.show("道具背包已刷新", Color.GREEN, 2.0, 1.0) #Toast.show("道具背包已刷新", Color.GREEN, 2.0, 1.0)
#面板显示与隐藏切换处理 #面板显示与隐藏切换处理
func _on_visibility_changed(): func _on_visibility_changed():
if visible: if visible:
GlobalVariables.isZoomDisabled = true GlobalVariables.isZoomDisabled = true
# 面板显示时自动刷新数据
update_item_bag_ui() update_item_bag_ui()
pass pass
else: else:

View File

@@ -433,6 +433,7 @@ func _handle_login_success(user_data: Dictionary):
main_game.item_bag = user_data.get("道具背包", []) main_game.item_bag = user_data.get("道具背包", [])
main_game.pet_bag = user_data.get("宠物背包", []) main_game.pet_bag = user_data.get("宠物背包", [])
main_game.patrol_pets = user_data.get("巡逻宠物", []) main_game.patrol_pets = user_data.get("巡逻宠物", [])
main_game.battle_pets = user_data.get("出战宠物", [])
# 启动游戏并隐藏登录面板 # 启动游戏并隐藏登录面板
main_game.start_game = true main_game.start_game = true

View File

@@ -61,9 +61,9 @@ func update_pet_bag_ui():
# 为背包中的每个宠物创建按钮 # 为背包中的每个宠物创建按钮
for pet_data in main_game.pet_bag: for pet_data in main_game.pet_bag:
var pet_name = pet_data.get("基本信息", {}).get("宠物类型", "未知宠物") var pet_name = pet_data.get("pet_type", "未知宠物")
var pet_level = pet_data.get("等级经验", {}).get("宠物等级", 1) var pet_level = pet_data.get("pet_level", 1)
var pet_owner_name = pet_data.get("基本信息", {}).get("宠物名称", pet_name) var pet_owner_name = pet_data.get("pet_name", pet_name)
# 创建宠物按钮 # 创建宠物按钮
var button = _create_pet_button(pet_name, pet_level, pet_owner_name) var button = _create_pet_button(pet_name, pet_level, pet_owner_name)
@@ -118,31 +118,45 @@ func _update_button_pet_image(button: Button, pet_name: String):
# 检查按钮是否有CropImage节点 # 检查按钮是否有CropImage节点
var pet_image = button.get_node_or_null("CropImage") var pet_image = button.get_node_or_null("CropImage")
if not pet_image: if not pet_image:
print("宠物背包按钮没有找到CropImage节点", button.name)
return return
# 从宠物配置获取场景路径 # 从服务器的宠物配置获取场景路径
var texture = null var texture = null
var pet_config = _load_pet_config() var pet_config = main_game.pet_config # 使用服务器返回的宠物配置
if pet_config.has(pet_name): if pet_config.has(pet_name):
var pet_info = pet_config[pet_name] var pet_info = pet_config[pet_name]
var scene_path = pet_info.get("场景路径", "") var scene_path = pet_info.get("pet_image", "") # 使用服务器数据的pet_image字段
print("宠物背包 ", pet_name, " 的图片路径:", scene_path)
if scene_path != "" and ResourceLoader.exists(scene_path): if scene_path != "" and ResourceLoader.exists(scene_path):
print("宠物背包开始加载宠物场景:", scene_path)
# 加载宠物场景并获取PetImage的纹理 # 加载宠物场景并获取PetImage的纹理
var pet_scene = load(scene_path) var pet_scene = load(scene_path)
if pet_scene: if pet_scene:
var pet_instance = pet_scene.instantiate() var pet_instance = pet_scene.instantiate()
var pet_image_node = pet_instance.get_node_or_null("PetImage") # 直接使用实例化的场景根节点,因为根节点就是PetImage
if pet_image_node and pet_image_node.sprite_frames: if pet_instance and pet_instance.sprite_frames:
# 获取默认动画的第一帧 # 获取默认动画的第一帧
var animation_names = pet_image_node.sprite_frames.get_animation_names() var animation_names = pet_instance.sprite_frames.get_animation_names()
if animation_names.size() > 0: if animation_names.size() > 0:
var default_animation = animation_names[0] var default_animation = animation_names[0]
var frame_count = pet_image_node.sprite_frames.get_frame_count(default_animation) var frame_count = pet_instance.sprite_frames.get_frame_count(default_animation)
if frame_count > 0: if frame_count > 0:
texture = pet_image_node.sprite_frames.get_frame_texture(default_animation, 0) texture = pet_instance.sprite_frames.get_frame_texture(default_animation, 0)
print("宠物背包成功获取宠物纹理:", pet_name)
else:
print("宠物背包场景没有动画:", pet_name)
else:
print("宠物背包场景没有PetImage节点或sprite_frames", pet_name)
pet_instance.queue_free() pet_instance.queue_free()
else:
print("宠物背包无法加载宠物场景:", scene_path)
else:
print("宠物背包图片路径无效或文件不存在:", scene_path)
else:
print("宠物背包配置中没有找到:", pet_name)
# 设置图片 # 设置图片
if texture: if texture:
@@ -151,8 +165,10 @@ func _update_button_pet_image(button: Button, pet_name: String):
pet_image.scale = Vector2(10, 10) pet_image.scale = Vector2(10, 10)
# 确保图片居中显示 # 确保图片居中显示
pet_image.centered = true pet_image.centered = true
print("宠物背包成功设置宠物图片:", pet_name)
else: else:
pet_image.visible = false pet_image.visible = false
print("宠物背包无法获取宠物图片:", pet_name)
# 加载宠物配置数据 # 加载宠物配置数据
func _load_pet_config() -> Dictionary: func _load_pet_config() -> Dictionary:

View File

@@ -24,6 +24,8 @@ extends Panel
# 宠物配置数据 # 宠物配置数据
var pet_config: Dictionary = {} var pet_config: Dictionary = {}
# 请求状态标志,防止重复请求
var is_requesting_config: bool = false
# 准备函数 # 准备函数
func _ready(): func _ready():
@@ -57,20 +59,23 @@ func update_pet_store_ui():
child.queue_free() child.queue_free()
print("更新宠物商店UI宠物种类", pet_config.size()) print("更新宠物商店UI宠物种类", pet_config.size())
print("宠物配置数据:", pet_config)
# 为每个宠物配置创建按钮 # 为每个宠物配置创建按钮
for pet_name in pet_config.keys(): for pet_name in pet_config.keys():
var pet_info = pet_config[pet_name] var pet_info = pet_config[pet_name]
var purchase_info = pet_info.get("购买信息", {}) print("处理宠物:", pet_name, ",数据:", pet_info)
var can_buy = purchase_info.get("能否购买", false)
# 适配扁平化数据格式
var can_buy = pet_info.get("can_purchase", false)
# 只显示可购买的宠物 # 只显示可购买的宠物
if not can_buy: if not can_buy:
print("宠物 ", pet_name, " 不可购买,跳过")
continue continue
var pet_cost = purchase_info.get("购买价格", 0) var pet_cost = pet_info.get("cost", 0)
var basic_info = pet_info.get("基本信息", {}) var pet_desc = pet_info.get("description", "可爱的宠物伙伴")
var pet_desc = basic_info.get("简介", "可爱的宠物伙伴")
# 检查玩家是否已购买该宠物 # 检查玩家是否已购买该宠物
var is_owned = _check_pet_owned(pet_name) var is_owned = _check_pet_owned(pet_name)
@@ -88,6 +93,7 @@ func update_pet_store_ui():
button.pressed.connect(func(): _on_store_pet_selected(pet_name, pet_cost, pet_desc)) button.pressed.connect(func(): _on_store_pet_selected(pet_name, pet_cost, pet_desc))
store_grid.add_child(button) store_grid.add_child(button)
print("已添加宠物按钮:", pet_name)
# 检查玩家是否已拥有某种宠物 # 检查玩家是否已拥有某种宠物
func _check_pet_owned(pet_name: String) -> bool: func _check_pet_owned(pet_name: String) -> bool:
@@ -95,8 +101,7 @@ func _check_pet_owned(pet_name: String) -> bool:
return false return false
for pet_data in main_game.pet_bag: for pet_data in main_game.pet_bag:
var basic_info = pet_data.get("基本信息", {}) var pet_type = pet_data.get("pet_type", "")
var pet_type = basic_info.get("宠物类型", "")
if pet_type == pet_name: if pet_type == pet_name:
return true return true
return false return false
@@ -144,28 +149,44 @@ func _update_button_pet_image(button: Button, pet_name: String):
# 检查按钮是否有CropImage节点 # 检查按钮是否有CropImage节点
var pet_image = button.get_node_or_null("CropImage") var pet_image = button.get_node_or_null("CropImage")
if not pet_image: if not pet_image:
print("按钮没有CropImage节点跳过图片设置")
return return
# 从宠物配置获取场景路径 # 从宠物配置获取场景路径
var texture = null var texture = null
if pet_config.has(pet_name): if pet_config.has(pet_name):
var pet_info = pet_config[pet_name] var pet_info = pet_config[pet_name]
var scene_path = pet_info.get("场景路径", "") var scene_path = pet_info.get("pet_image", "")
print("宠物 ", pet_name, " 的图片路径:", scene_path)
if scene_path != "" and ResourceLoader.exists(scene_path): if scene_path != "" and ResourceLoader.exists(scene_path):
print("开始加载宠物场景:", scene_path)
# 加载宠物场景并获取PetImage的纹理 # 加载宠物场景并获取PetImage的纹理
var pet_scene = load(scene_path) var pet_scene = load(scene_path)
if pet_scene: if pet_scene:
var pet_instance = pet_scene.instantiate() var pet_instance = pet_scene.instantiate()
var pet_image_node = pet_instance.get_node_or_null("PetImage") # 场景的根节点就是PetImage,直接使用
var pet_image_node = pet_instance
if pet_image_node and pet_image_node.sprite_frames: if pet_image_node and pet_image_node.sprite_frames:
# 获取默认动画的第一帧 # 获取默认动画的第一帧
var default_animation = pet_image_node.sprite_frames.get_animation_names()[0] var animation_names = pet_image_node.sprite_frames.get_animation_names()
var frame_count = pet_image_node.sprite_frames.get_frame_count(default_animation) if animation_names.size() > 0:
if frame_count > 0: var default_animation = animation_names[0]
texture = pet_image_node.sprite_frames.get_frame_texture(default_animation, 0) var frame_count = pet_image_node.sprite_frames.get_frame_count(default_animation)
if frame_count > 0:
texture = pet_image_node.sprite_frames.get_frame_texture(default_animation, 0)
print("成功获取宠物纹理:", pet_name)
else:
print("宠物场景没有动画:", pet_name)
else:
print("宠物场景没有PetImage节点或sprite_frames", pet_name)
pet_instance.queue_free() pet_instance.queue_free()
else:
print("无法加载宠物场景:", scene_path)
else:
print("宠物图片路径无效或文件不存在:", scene_path)
else:
print("宠物配置中没有找到:", pet_name)
# 设置图片 # 设置图片
if texture: if texture:
@@ -174,31 +195,52 @@ func _update_button_pet_image(button: Button, pet_name: String):
pet_image.scale = Vector2(10, 10) pet_image.scale = Vector2(10, 10)
# 确保图片居中显示 # 确保图片居中显示
pet_image.centered = true pet_image.centered = true
print("成功设置宠物图片:", pet_name)
else: else:
# 如果无法获取图片,隐藏图片节点但保留按钮
pet_image.visible = false pet_image.visible = false
print("无法获取宠物图片,隐藏图片节点:", pet_name)
# 从主游戏脚本获取宠物配置数据 # 从服务器获取MongoDB中的宠物配置数据
func _load_pet_config_from_main(): func _load_pet_config_from_main():
# 从宠物数据文件加载配置 # 如果正在请求中,避免重复发送
var file = FileAccess.open("res://Data/pet_data.json", FileAccess.READ) if is_requesting_config:
if file == null: print("宠物商店:正在请求配置数据中,跳过重复请求")
print("宠物商店:无法打开宠物配置文件")
pet_config = {}
return return
var json = JSON.new() # 发送请求到服务器获取宠物配置
var json_string = file.get_as_text() if tcp_network_manager_panel and tcp_network_manager_panel.has_method("sendGetPetConfig"):
file.close() is_requesting_config = true
if tcp_network_manager_panel.sendGetPetConfig():
var parse_result = json.parse(json_string) print("宠物商店:已发送获取宠物配置请求")
if parse_result != OK: # 等待服务器响应,配置数据将通过网络回调更新
print("宠物商店:解析宠物配置文件失败") else:
print("宠物商店:发送获取宠物配置请求失败")
pet_config = {}
is_requesting_config = false
else:
print("宠物商店:网络管理器不可用,无法获取宠物配置")
pet_config = {} pet_config = {}
return is_requesting_config = false
# 处理服务器返回的宠物配置数据
func _on_pet_config_received(response_data: Dictionary):
"""处理从服务器接收到的宠物配置数据"""
# 重置请求状态
is_requesting_config = false
pet_config = json.data var success = response_data.get("success", false)
print("宠物商店:成功加载宠物配置数据,宠物种类:", pet_config.size()) if success:
pet_config = response_data.get("pet_config", {})
print("宠物商店:成功接收宠物配置数据,宠物种类:", pet_config.size())
# 只更新UI不重新发送请求
update_pet_store_ui()
else:
var error_message = response_data.get("message", "获取宠物配置失败")
print("宠物商店:获取宠物配置失败:", error_message)
pet_config = {}
# 显示错误提示
Toast.show(error_message, Color.RED, 3.0, 1.0)
# 商店宠物点击处理 - 购买宠物 # 商店宠物点击处理 - 购买宠物
func _on_store_pet_selected(pet_name: String, pet_cost: int, pet_desc: String): func _on_store_pet_selected(pet_name: String, pet_cost: int, pet_desc: String):
@@ -269,9 +311,12 @@ func _send_buy_pet_request(pet_name: String, pet_cost: int):
#=========================面板通用处理========================= #=========================面板通用处理=========================
# 手动刷新宠物商店面板 # 手动刷新宠物商店面板
func _on_refresh_button_pressed() -> void: func _on_refresh_button_pressed() -> void:
# 清空现有配置和请求状态,强制重新获取
pet_config = {}
is_requesting_config = false
# 重新初始化宠物商店 # 重新初始化宠物商店
init_pet_store() init_pet_store()
Toast.show("宠物商店已刷新", Color.GREEN, 2.0, 1.0) #Toast.show("宠物商店已刷新", Color.GREEN, 2.0, 1.0)
# 关闭宠物商店面板 # 关闭宠物商店面板
func _on_quit_button_pressed() -> void: func _on_quit_button_pressed() -> void:
@@ -283,8 +328,12 @@ func _on_quit_button_pressed() -> void:
func _on_visibility_changed(): func _on_visibility_changed():
if visible: if visible:
GlobalVariables.isZoomDisabled = true GlobalVariables.isZoomDisabled = true
# 面板显示时自动刷新数据 # 面板显示时只在没有配置数据时才请求
update_pet_store_ui() if pet_config.is_empty():
init_pet_store()
else:
# 如果已有配置数据直接更新UI
update_pet_store_ui()
pass pass
else: else:
GlobalVariables.isZoomDisabled = false GlobalVariables.isZoomDisabled = false

View File

@@ -53,15 +53,10 @@ extends CharacterBody2D
#- 亲密度(额外加属性) #- 亲密度(额外加属性)
#- 品质(白/绿/蓝/橙/红/紫) #- 品质(白/绿/蓝/橙/红/紫)
#基本攻击方式:
#近战 #近战
#近战攻击伤害 #近战攻击伤害
#近战攻击速度 #近战攻击速度
#远程
#远程攻击伤害
#远程攻击速度
#附录 #附录
#- 护甲公式示例:实际伤害 = 基础伤害 × (1 - 护甲值/(护甲值 + 100)),搭配"护甲穿透"可直接减少目标护甲值 #- 护甲公式示例:实际伤害 = 基础伤害 × (1 - 护甲值/(护甲值 + 100)),搭配"护甲穿透"可直接减少目标护甲值
#- 元素克制火属性攻击对冰属性敌人造成150%伤害同时被水属性克制仅造成80%伤害) #- 元素克制火属性攻击对冰属性敌人造成150%伤害同时被水属性克制仅造成80%伤害)
@@ -111,7 +106,7 @@ var current_armor: float = 100.0 # 当前护甲值
# 攻击属性 # 攻击属性
var attack_type: AttackType = AttackType.RANGED # 攻击类型 var attack_type: AttackType = AttackType.RANGED # 攻击类型
var attack_damage: float = 20.0 # 基础攻击伤害 var attack_damage: float = 20.0 # 基础攻击伤害
var attack_range: float = 300.0 # 攻击距离 var attack_range: float = 400.0 # 攻击距离
var crit_rate: float = 0.1 # 暴击率0.0-1.0 var crit_rate: float = 0.1 # 暴击率0.0-1.0
var crit_damage: float = 1.5 # 暴击伤害倍数 var crit_damage: float = 1.5 # 暴击伤害倍数
var life_steal: float = 0.1 # 生命汲取0.0-1.0 var life_steal: float = 0.1 # 生命汲取0.0-1.0
@@ -152,7 +147,7 @@ enum RangedAttackMode {
PIERCING # 穿透攻击 PIERCING # 穿透攻击
} }
# 内部状态变量(不需要导出)
var attack_speed: float = 1.0 # 当前攻击速度(根据攻击类型动态设置) var attack_speed: float = 1.0 # 当前攻击速度(根据攻击类型动态设置)
var gatling_firing: bool = false # 是否正在加特林射击 var gatling_firing: bool = false # 是否正在加特林射击
var gatling_current_bullet: int = 0 # 当前加特林子弹计数 var gatling_current_bullet: int = 0 # 当前加特林子弹计数
@@ -219,13 +214,57 @@ var is_attacking: bool = false # 是否正在攻击
var is_berserker: bool = false # 是否处于狂暴状态 var is_berserker: bool = false # 是否处于狂暴状态
var is_stunned: bool = false # 是否被眩晕 var is_stunned: bool = false # 是否被眩晕
var is_invulnerable: bool = false # 是否无敌 var is_invulnerable: bool = false # 是否无敌
var is_being_knocked_back: bool = false # 是否正在被击退
var current_target: CharacterBody2D = null # 当前目标 var current_target: CharacterBody2D = null # 当前目标
var last_attacker: CharacterBody2D = null # 最后攻击者(用于击杀奖励) var last_attacker: CharacterBody2D = null # 最后攻击者(用于击杀奖励)
var last_attack_time: float = 0.0 # 上次攻击时间 var last_attack_time: float = 0.0 # 上次攻击时间
var last_regen_time: float = 0.0 # 上次恢复时间 var last_regen_time: float = 0.0 # 上次恢复时间
var last_target_check_time: float = 0.0 # 上次目标检查时间 var last_target_check_time: float = 0.0 # 上次目标检查时间
var knockback_velocity: Vector2 = Vector2.ZERO # 击退速度
# 受伤动画相关
var hurt_tween: Tween = null # 受伤动画缓动
var original_modulate: Color = Color.WHITE # 原始颜色
var last_hurt_time: float = 0.0 # 上次受伤时间(防止受伤动画过于频繁)
var hurt_animation_cooldown: float = 0.3 # 受伤动画冷却时间
# 攻击频率控制
var min_attack_interval: float = 0.5 # 最小攻击间隔(防止攻击过于频繁)
# 伤害反弹保护
var damage_reflect_depth: int = 0 # 伤害反弹递归深度
var max_reflect_depth: int = 3 # 最大反弹深度(防止无限递归)
# 性能保护
var performance_mode: bool = false # 性能模式(减少特效和计算)
var frame_skip_counter: int = 0 # 帧跳跃计数器
# 升级系统 - 基础属性列表(每次升级随机选择加点)
var base_upgrade_attributes: Array[String] = [
"max_health", # 最大生命值
"attack_damage", # 攻击伤害
"move_speed", # 移动速度
"max_shield", # 最大护盾值
"max_armor", # 最大护甲值
"crit_rate", # 暴击率
"health_regen", # 生命恢复
"attack_range" # 攻击距离
]
# 每次升级随机选择的属性数量
var attributes_per_level: int = 3
# 每5级额外属性奖励表
var level_milestone_bonuses: Dictionary = {
5: {"max_health": 20, "attack_damage": 5, "crit_rate": 0.02},
10: {"max_shield": 30, "armor_penetration": 5, "life_steal": 0.05},
15: {"max_armor": 25, "knockback_resist": 0.1, "dodge_rate": 0.03},
20: {"health_regen": 2, "move_speed": 15, "attack_range": 30},
25: {"max_health": 40, "attack_damage": 10, "enable_berserker_mode": true},
30: {"max_shield": 50, "shield_regen": 1, "enable_damage_reflect": true},
35: {"crit_damage": 0.3, "berserker_bonus": 0.2, "damage_reflect": 0.05},
40: {"max_armor": 40, "control_resist": 0.15, "enable_aid_system": true},
45: {"projectile_speed": 50, "pierce_count": 1, "enable_death_immunity": true},
50: {"max_health": 100, "attack_damage": 25, "enable_resurrection": true}
}
# 巡逻状态 # 巡逻状态
var is_patrolling: bool = false # 是否正在巡逻 var is_patrolling: bool = false # 是否正在巡逻
@@ -642,6 +681,10 @@ func _ready():
# 初始化生日 # 初始化生日
initialize_birthday() initialize_birthday()
# 保存原始颜色
if pet_image:
original_modulate = pet_image.modulate
# 延迟初始化UI显示确保所有节点都已准备好 # 延迟初始化UI显示确保所有节点都已准备好
call_deferred("update_ui") call_deferred("update_ui")
@@ -702,35 +745,50 @@ func clamp_to_battle_area():
global_position.x = clamp(global_position.x, battle_area_min.x, battle_area_max.x) global_position.x = clamp(global_position.x, battle_area_min.x, battle_area_max.x)
global_position.y = clamp(global_position.y, battle_area_min.y, battle_area_max.y) global_position.y = clamp(global_position.y, battle_area_min.y, battle_area_max.y)
#宠物物理更新 #宠物物理更新(带性能保护)
func _physics_process(delta): func _physics_process(delta):
if not is_alive or is_dying: if not is_alive or is_dying:
return return
# 性能保护每3帧执行一次非关键逻辑
frame_skip_counter += 1
var should_skip_frame = performance_mode and (frame_skip_counter % 3 != 0)
# 检测性能问题(如果帧时间过长,自动启用性能模式)
if delta > 0.025: # 帧时间超过25ms低于40FPS
if not performance_mode:
performance_mode = true
print("" + pet_name + " 启用性能模式(帧时间: " + str("%.3f" % delta) + "s")
# 巡逻宠物特殊处理 # 巡逻宠物特殊处理
if is_patrolling: if is_patrolling:
handle_patrol(delta) handle_patrol(delta)
return return
# 处理生命和护盾恢复 # 处理生命和护盾恢复
handle_regeneration(delta) if not should_skip_frame:
handle_regeneration(delta)
# 更新年龄和亲密度 # 更新年龄和亲密度(低优先级,可跳帧)
update_age_and_intimacy(delta) if not should_skip_frame:
update_age_and_intimacy(delta)
# 检查狂暴状态 # 检查狂暴状态
check_berserker_mode() if not should_skip_frame:
check_berserker_mode()
# 检查援助系统 # 检查援助系统(低优先级,可跳帧)
check_aid_system() if not should_skip_frame:
check_aid_system()
# 如果被眩晕则不能行动 # 如果被眩晕则不能行动
if is_stunned: if is_stunned:
return return
# 定期检查目标状态(每0.5秒检查一次 # 定期检查目标状态(性能模式下降低检查频率
var current_time = Time.get_ticks_msec() / 1000.0 var current_time = Time.get_ticks_msec() / 1000.0
if current_time - last_target_check_time >= 0.5: var check_interval = 0.5 if not performance_mode else 1.0
if current_time - last_target_check_time >= check_interval:
check_target_validity() check_target_validity()
last_target_check_time = current_time last_target_check_time = current_time
@@ -791,15 +849,7 @@ func update_ai_state(delta):
#宠物移动 #宠物移动
func handle_movement(delta): func handle_movement(delta):
# 处理击退效果 if current_state == PetState.MOVING_TO_TARGET and current_target:
if is_being_knocked_back:
velocity = knockback_velocity
# 击退衰减
knockback_velocity = knockback_velocity.lerp(Vector2.ZERO, 5.0 * delta)
if knockback_velocity.length() < 10.0:
is_being_knocked_back = false
knockback_velocity = Vector2.ZERO
elif current_state == PetState.MOVING_TO_TARGET and current_target:
var distance_to_target = global_position.distance_to(current_target.global_position) var distance_to_target = global_position.distance_to(current_target.global_position)
var direction = (current_target.global_position - global_position).normalized() var direction = (current_target.global_position - global_position).normalized()
@@ -832,7 +882,7 @@ func handle_movement(delta):
else: else:
velocity = Vector2.ZERO velocity = Vector2.ZERO
#宠物攻击 #宠物攻击(带频率保护)
func handle_attack(delta): func handle_attack(delta):
if current_state == PetState.ATTACKING and current_target: if current_state == PetState.ATTACKING and current_target:
var current_time = Time.get_ticks_msec() / 1000.0 # 转换为秒 var current_time = Time.get_ticks_msec() / 1000.0 # 转换为秒
@@ -841,8 +891,9 @@ func handle_attack(delta):
if ranged_mode == RangedAttackMode.GATLING: if ranged_mode == RangedAttackMode.GATLING:
handle_gatling_attack(current_time, delta) handle_gatling_attack(current_time, delta)
else: else:
# 普通攻击频率控制 # 普通攻击频率控制(确保最小攻击间隔)
if current_time - last_attack_time >= 1.0 / attack_speed: var attack_interval = max(1.0 / attack_speed, min_attack_interval)
if current_time - last_attack_time >= attack_interval:
perform_attack(current_target) perform_attack(current_target)
last_attack_time = current_time last_attack_time = current_time
@@ -959,9 +1010,9 @@ func perform_melee_attack(target: CharacterBody2D):
var heal_amount = damage * life_steal var heal_amount = damage * life_steal
heal(heal_amount) heal(heal_amount)
# 击退效果 # 击退效果已禁用
if knockback_force > 0: # if knockback_force > 0:
apply_knockback_to_target(target) # apply_knockback_to_target(target)
# 根据攻击模式发射子弹 # 根据攻击模式发射子弹
func fire_projectile_by_mode(target: CharacterBody2D): func fire_projectile_by_mode(target: CharacterBody2D):
@@ -1090,15 +1141,29 @@ func create_and_fire_projectile(start_pos: Vector2, target_pos: Vector2, damage:
RangedAttackMode.PIERCING: RangedAttackMode.PIERCING:
projectile.get_node("ProjectileSprite").modulate = Color.PURPLE projectile.get_node("ProjectileSprite").modulate = Color.PURPLE
#宠物受到伤害 #宠物受到伤害(带死循环保护)
func take_damage(damage: float, armor_pen: float = 0.0, attacker_element: ElementType = ElementType.NONE, attacker: CharacterBody2D = null): func take_damage(damage: float, armor_pen: float = 0.0, attacker_element: ElementType = ElementType.NONE, attacker: CharacterBody2D = null):
if not is_alive or is_invulnerable: if not is_alive or is_invulnerable:
return return
# 防止过于频繁的伤害处理(性能保护)
var current_time = Time.get_ticks_msec() / 1000.0
if current_time - last_attack_time < 0.05: # 50ms最小伤害间隔
return
# 增加伤害反弹递归深度
damage_reflect_depth += 1
# 递归深度保护(防止无限反弹)
if damage_reflect_depth > max_reflect_depth:
damage_reflect_depth = max(0, damage_reflect_depth - 1)
return
# 闪避检测 # 闪避检测
if randf() < dodge_rate: if randf() < dodge_rate:
if attacker and is_instance_valid(attacker): if attacker and is_instance_valid(attacker):
add_battle_detail_to_panel("" + pet_name + " 闪避了 " + attacker.pet_name + " 的攻击!", Color.CYAN) add_battle_detail_to_panel("" + pet_name + " 闪避了 " + attacker.pet_name + " 的攻击!", Color.CYAN)
damage_reflect_depth = max(0, damage_reflect_depth - 1)
return return
var actual_damage = damage var actual_damage = damage
@@ -1123,8 +1188,11 @@ func take_damage(damage: float, armor_pen: float = 0.0, attacker_element: Elemen
if actual_damage > 0: if actual_damage > 0:
current_health -= actual_damage current_health -= actual_damage
# 添加受伤细节 # 播放受伤动画(带冷却保护)
if attacker and is_instance_valid(attacker): play_hurt_animation()
# 添加受伤细节(性能模式下减少文本输出)
if not performance_mode and attacker and is_instance_valid(attacker):
var damage_text = "💔 " + pet_name + " 受到 " + str(int(actual_damage)) + " 点伤害" var damage_text = "💔 " + pet_name + " 受到 " + str(int(actual_damage)) + " 点伤害"
if element_extra_damage > 0: if element_extra_damage > 0:
damage_text += " (元素克制 +" + str(int(element_extra_damage)) + "" damage_text += " (元素克制 +" + str(int(element_extra_damage)) + ""
@@ -1135,15 +1203,19 @@ func take_damage(damage: float, armor_pen: float = 0.0, attacker_element: Elemen
last_attacker = attacker last_attacker = attacker
# 反击机制:立即将攻击者设为目标(只有启用战斗时才反击) # 反击机制:立即将攻击者设为目标(只有启用战斗时才反击)
# 添加反击冷却,防止过于频繁的目标切换
if combat_enabled and attacker and is_instance_valid(attacker) and attacker.is_alive: if combat_enabled and attacker and is_instance_valid(attacker) and attacker.is_alive:
if attacker.get_team() != pet_team: # 确保不攻击队友 if attacker.get_team() != pet_team: # 确保不攻击队友
current_target = attacker # 只有当前没有目标或当前目标已死亡时才切换目标
current_state = PetState.MOVING_TO_TARGET if not current_target or not is_instance_valid(current_target) or not current_target.is_alive:
current_target = attacker
current_state = PetState.MOVING_TO_TARGET
# 伤害反弹 # 伤害反弹(带递归深度保护)
if enable_damage_reflect and damage_reflect > 0.0 and attacker and is_instance_valid(attacker): if enable_damage_reflect and damage_reflect > 0.0 and attacker and is_instance_valid(attacker) and damage_reflect_depth <= max_reflect_depth:
var reflect_damage = damage * damage_reflect var reflect_damage = damage * damage_reflect * 0.5 # 反弹伤害减半,防止无限递归
attacker.take_damage(reflect_damage, 0.0, element_type, self) # 反弹伤害也会触发反击 # 延迟反弹,避免同帧内的递归调用
call_deferred("apply_reflect_damage", attacker, reflect_damage)
# 检查死亡 # 检查死亡
if current_health <= 0: if current_health <= 0:
@@ -1159,9 +1231,17 @@ func take_damage(damage: float, armor_pen: float = 0.0, attacker_element: Elemen
if not is_dying: # 防止重复调用die() if not is_dying: # 防止重复调用die()
call_deferred("die") call_deferred("die")
# 减少伤害反弹递归深度
damage_reflect_depth = max(0, damage_reflect_depth - 1)
# 更新UI # 更新UI
call_deferred("update_ui") call_deferred("update_ui")
# 延迟应用反弹伤害(防止递归调用)
func apply_reflect_damage(target: CharacterBody2D, reflect_damage: float):
if target and is_instance_valid(target) and target.is_alive:
target.take_damage(reflect_damage, 0.0, element_type, self)
#宠物死亡 #宠物死亡
func die(): func die():
if is_dying: # 如果已经在死亡过程中,直接返回 if is_dying: # 如果已经在死亡过程中,直接返回
@@ -1416,6 +1496,10 @@ func apply_quality_bonuses():
func get_team() -> String: func get_team() -> String:
return pet_team return pet_team
# 获取攻击类型(调试用)
func get_attack_type() -> AttackType:
return attack_type
# 处理生命和护盾恢复 # 处理生命和护盾恢复
func handle_regeneration(delta: float): func handle_regeneration(delta: float):
var current_time = Time.get_ticks_msec() / 1000.0 var current_time = Time.get_ticks_msec() / 1000.0
@@ -1516,7 +1600,7 @@ func gain_experience(amount: float):
while pet_experience >= max_experience and pet_level < 50: while pet_experience >= max_experience and pet_level < 50:
level_up() level_up()
# 升级 # 升级(新的随机属性系统)
func level_up(): func level_up():
pet_experience -= max_experience pet_experience -= max_experience
pet_level += 1 pet_level += 1
@@ -1524,25 +1608,197 @@ func level_up():
# 计算新的升级经验需求(指数增长) # 计算新的升级经验需求(指数增长)
max_experience = 100.0 * pow(1.2, pet_level - 1) max_experience = 100.0 * pow(1.2, pet_level - 1)
# 升级属性加成 # 随机选择属性进行升级
var level_bonus = 1.1 # 每级10%属性加成 var upgraded_attributes = apply_random_attribute_upgrade()
max_health *= level_bonus # 检查是否有里程碑奖励每5级
current_health = max_health # 升级回满血 var milestone_rewards = apply_milestone_bonus()
attack_damage *= level_bonus
max_shield *= level_bonus # 升级回血和护盾护甲
current_shield = max_shield # 升级回满护盾 current_health = max_health
max_armor *= level_bonus current_shield = max_shield
current_armor = max_armor # 升级回满护甲 current_armor = max_armor
# 升级特效 # 升级特效
show_level_up_effect() show_level_up_effect()
# 添加升级细节 # 添加升级细节
add_battle_detail_to_panel("🎉 " + pet_name + " 升级到 " + str(pet_level) + " 级!", Color.GOLD) var upgrade_text = "🎉 " + pet_name + " 升级到 " + str(pet_level) + " 级!"
upgrade_text += "\n📈 随机提升:" + ", ".join(upgraded_attributes)
if milestone_rewards.size() > 0:
upgrade_text += "\n🏆 里程碑奖励:" + ", ".join(milestone_rewards)
add_battle_detail_to_panel(upgrade_text, Color.GOLD)
call_deferred("update_ui") call_deferred("update_ui")
# 应用随机属性升级
func apply_random_attribute_upgrade() -> Array[String]:
var upgraded_attributes: Array[String] = []
var available_attributes = base_upgrade_attributes.duplicate()
# 随机选择几个属性进行升级
for i in range(min(attributes_per_level, available_attributes.size())):
var random_index = randi() % available_attributes.size()
var selected_attribute = available_attributes[random_index]
available_attributes.remove_at(random_index)
# 应用属性升级
var upgrade_applied = apply_single_attribute_upgrade(selected_attribute)
if upgrade_applied:
upgraded_attributes.append(upgrade_applied)
return upgraded_attributes
# 应用单个属性升级
func apply_single_attribute_upgrade(attribute_name: String) -> String:
match attribute_name:
"max_health":
var bonus = randf_range(8.0, 15.0) # 随机8-15点生命值
max_health += bonus
return "生命值 +" + str(int(bonus))
"attack_damage":
var bonus = randf_range(2.0, 5.0) # 随机2-5点攻击力
attack_damage += bonus
return "攻击力 +" + str(int(bonus))
"move_speed":
var bonus = randf_range(3.0, 8.0) # 随机3-8点移动速度
move_speed += bonus
return "移动速度 +" + str(int(bonus))
"max_shield":
var bonus = randf_range(5.0, 12.0) # 随机5-12点护盾值
max_shield += bonus
return "护盾值 +" + str(int(bonus))
"max_armor":
var bonus = randf_range(4.0, 10.0) # 随机4-10点护甲值
max_armor += bonus
return "护甲值 +" + str(int(bonus))
"crit_rate":
var bonus = randf_range(0.01, 0.03) # 随机1-3%暴击率
crit_rate = min(1.0, crit_rate + bonus) # 暴击率上限100%
return "暴击率 +" + str(int(bonus * 100)) + "%"
"health_regen":
var bonus = randf_range(0.3, 0.8) # 随机0.3-0.8点生命恢复
health_regen += bonus
return "生命恢复 +" + str("%.1f" % bonus)
"attack_range":
var bonus = randf_range(8.0, 20.0) # 随机8-20点攻击距离
attack_range += bonus
return "攻击距离 +" + str(int(bonus))
_:
return ""
# 应用里程碑奖励
func apply_milestone_bonus() -> Array[String]:
var milestone_rewards: Array[String] = []
if not level_milestone_bonuses.has(pet_level):
return milestone_rewards
var bonuses = level_milestone_bonuses[pet_level]
for bonus_key in bonuses.keys():
var bonus_value = bonuses[bonus_key]
var reward_text = apply_milestone_bonus_single(bonus_key, bonus_value)
if reward_text != "":
milestone_rewards.append(reward_text)
return milestone_rewards
# 应用单个里程碑奖励
func apply_milestone_bonus_single(bonus_key: String, bonus_value) -> String:
match bonus_key:
"max_health":
max_health += bonus_value
return "生命值 +" + str(bonus_value)
"attack_damage":
attack_damage += bonus_value
return "攻击力 +" + str(bonus_value)
"max_shield":
max_shield += bonus_value
return "护盾值 +" + str(bonus_value)
"max_armor":
max_armor += bonus_value
return "护甲值 +" + str(bonus_value)
"crit_rate":
crit_rate = min(1.0, crit_rate + bonus_value)
return "暴击率 +" + str(int(bonus_value * 100)) + "%"
"armor_penetration":
armor_penetration += bonus_value
return "护甲穿透 +" + str(bonus_value)
"life_steal":
life_steal = min(1.0, life_steal + bonus_value)
return "生命汲取 +" + str(int(bonus_value * 100)) + "%"
"knockback_resist":
knockback_resist = min(1.0, knockback_resist + bonus_value)
return "击退抗性 +" + str(int(bonus_value * 100)) + "%"
"dodge_rate":
dodge_rate = min(1.0, dodge_rate + bonus_value)
return "闪避率 +" + str(int(bonus_value * 100)) + "%"
"health_regen":
health_regen += bonus_value
return "生命恢复 +" + str(bonus_value)
"move_speed":
move_speed += bonus_value
return "移动速度 +" + str(bonus_value)
"attack_range":
attack_range += bonus_value
return "攻击距离 +" + str(bonus_value)
"shield_regen":
shield_regen += bonus_value
return "护盾恢复 +" + str(bonus_value)
"crit_damage":
crit_damage += bonus_value
return "暴击伤害 +" + str(int(bonus_value * 100)) + "%"
"berserker_bonus":
berserker_bonus += bonus_value
return "狂暴加成 +" + str(int(bonus_value * 100)) + "%"
"damage_reflect":
damage_reflect = min(1.0, damage_reflect + bonus_value)
return "伤害反弹 +" + str(int(bonus_value * 100)) + "%"
"control_resist":
control_resist = min(1.0, control_resist + bonus_value)
return "控制抗性 +" + str(int(bonus_value * 100)) + "%"
"projectile_speed":
projectile_speed += bonus_value
return "子弹速度 +" + str(bonus_value)
"pierce_count":
pierce_count += bonus_value
return "穿透数量 +" + str(bonus_value)
"enable_berserker_mode":
if bonus_value:
enable_berserker_mode = true
return "解锁狂暴模式"
else:
return ""
"enable_damage_reflect":
if bonus_value:
enable_damage_reflect = true
return "解锁伤害反弹"
else:
return ""
"enable_aid_system":
if bonus_value:
enable_aid_system = true
return "解锁援助召唤"
else:
return ""
"enable_death_immunity":
if bonus_value:
enable_death_immunity = true
death_immunity = true
return "解锁死亡免疫"
else:
return ""
"enable_resurrection":
if bonus_value:
enable_resurrection = true
return "解锁死亡重生"
else:
return ""
_:
return ""
# 显示升级特效 # 显示升级特效
func show_level_up_effect(): func show_level_up_effect():
if not pet_image: if not pet_image:
@@ -1677,34 +1933,24 @@ func heal(amount: float):
current_health = min(max_health, current_health + amount) current_health = min(max_health, current_health + amount)
call_deferred("update_ui") call_deferred("update_ui")
# 对目标应用击退效果 # 击退效果已禁用
func apply_knockback_to_target(target: CharacterBody2D): func apply_knockback_to_target(target: CharacterBody2D):
if not target or not is_instance_valid(target): # 击退功能暂时禁用
return pass
# 计算击退方向
var direction = (target.global_position - global_position).normalized()
# 计算击退力度(考虑目标的击退抗性)
var effective_knockback = knockback_force * (1.0 - target.knockback_resist)
if effective_knockback > 0:
target.apply_knockback(direction, effective_knockback)
add_battle_detail_to_panel(pet_name + " 击退了 " + target.pet_name)
# 击退时调 # 击退效果已禁
func apply_knockback(direction: Vector2, force: float): func apply_knockback(direction: Vector2, force: float):
if not is_alive: # 击退功能暂时禁用
return pass
# 将位置限制在战斗区域内
func clamp_position_to_battle_area(pos: Vector2) -> Vector2:
var battle_area_min = Vector2(50, 50)
var battle_area_max = Vector2(1350, 670)
# 设置击退状态 pos.x = clamp(pos.x, battle_area_min.x, battle_area_max.x)
is_being_knocked_back = true pos.y = clamp(pos.y, battle_area_min.y, battle_area_max.y)
knockback_velocity = direction * force return pos
# 击退时短暂失去目标(可选)
if current_target and randf() < 0.3: # 30%概率失去目标
current_target = null
current_state = PetState.IDLE
# 元素克制计算 # 元素克制计算
func get_element_multiplier(attacker_element: ElementType, defender_element: ElementType) -> float: func get_element_multiplier(attacker_element: ElementType, defender_element: ElementType) -> float:
@@ -1827,3 +2073,82 @@ func clamp_to_patrol_area():
# 限制位置 # 限制位置
position.x = clamp(position.x, min_x, max_x) position.x = clamp(position.x, min_x, max_x)
position.y = clamp(position.y, min_y, max_y) position.y = clamp(position.y, min_y, max_y)
# 播放受伤动画(带冷却保护)
func play_hurt_animation():
if not pet_image:
return
# 检查受伤动画冷却时间
var current_time = Time.get_ticks_msec() / 1000.0
if current_time - last_hurt_time < hurt_animation_cooldown:
return # 冷却中,不播放动画
last_hurt_time = current_time
# 如果已经有受伤动画在播放,停止之前的
if hurt_tween:
hurt_tween.kill()
hurt_tween = null
# 性能模式下简化动画
if performance_mode:
# 简单的颜色变化无需Tween
pet_image.modulate = Color.RED
# 使用计时器恢复颜色(更轻量)
await get_tree().create_timer(0.1).timeout
if pet_image: # 确保宠物还存在
pet_image.modulate = original_modulate
return
# 创建受伤动画(闪红效果)
hurt_tween = create_tween()
# 立即变红
pet_image.modulate = Color.RED
# 0.2秒后恢复原色
hurt_tween.tween_property(pet_image, "modulate", original_modulate, 0.2)
# 动画结束后清理
hurt_tween.tween_callback(func():
hurt_tween = null
)
# 切换性能模式
func toggle_performance_mode():
performance_mode = !performance_mode
var mode_text = "性能模式" if performance_mode else "正常模式"
add_battle_detail_to_panel("" + pet_name + " 切换到 " + mode_text, Color.YELLOW)
print("" + pet_name + " 切换到 " + mode_text)
# 输出宠物性能状态
func debug_performance_status():
print("=== " + pet_name + " 性能状态调试 ===")
print("性能模式: " + str(performance_mode))
print("伤害反弹深度: " + str(damage_reflect_depth))
print("帧跳跃计数: " + str(frame_skip_counter))
print("上次受伤时间: " + str(last_hurt_time))
print("上次攻击时间: " + str(last_attack_time))
print("当前状态: " + str(current_state))
print("是否存活: " + str(is_alive))
print("是否正在死亡: " + str(is_dying))
print("============================")
# 重置性能状态(紧急恢复)
func reset_performance_state():
performance_mode = false
damage_reflect_depth = 0
frame_skip_counter = 0
# 清理可能卡住的动画
if hurt_tween:
hurt_tween.kill()
hurt_tween = null
# 恢复正常颜色
if pet_image:
pet_image.modulate = original_modulate
print("🔄 " + pet_name + " 性能状态已重置")
add_battle_detail_to_panel("🔄 " + pet_name + " 性能状态已重置", Color.GREEN)

View File

@@ -57,7 +57,7 @@ var current_attacker_name: String = "" # 当前进攻者用户名
func _ready(): func _ready():
# 加载宠物配置 visibility_changed.connect(_on_visibility_changed)
load_pet_configs() load_pet_configs()
# 连接返回农场按钮 # 连接返回农场按钮
@@ -69,7 +69,6 @@ func _ready():
battle_end_panel.visible = false battle_end_panel.visible = false
if pet_battle_details_panel: if pet_battle_details_panel:
pet_battle_details_panel.visible = false pet_battle_details_panel.visible = false
# 加载宠物配置 # 加载宠物配置
func load_pet_configs(): func load_pet_configs():
@@ -115,10 +114,17 @@ func clear_battle_details():
if battle_details: if battle_details:
battle_details.text = "" battle_details.text = ""
# 战斗结束检查计时器
var battle_check_timer: float = 0.0
var battle_check_interval: float = 0.5 # 每0.5秒检查一次,减少性能开销
func _process(delta): func _process(delta):
# 只有启用自动对战时才检查战斗结束 # 只有启用自动对战时才检查战斗结束,并使用计时器减少检查频率
if auto_battle_enabled and battle_started and not battle_ended: if auto_battle_enabled and battle_started and not battle_ended:
check_battle_end() battle_check_timer += delta
if battle_check_timer >= battle_check_interval:
battle_check_timer = 0.0
check_battle_end()
# 获取队伍节点 - 供宠物调用 # 获取队伍节点 - 供宠物调用
@@ -224,12 +230,6 @@ func end_battle(winner: String):
# 显示战斗结算面板 # 显示战斗结算面板
func show_battle_end_panel(winner: String): func show_battle_end_panel(winner: String):
var result_text = "" var result_text = ""
var team1_survivors = 0
var team2_survivors = 0
var team1_total_damage = 0.0
var team2_total_damage = 0.0
var team1_pets_info: Array[String] = []
var team2_pets_info: Array[String] = []
# 统计存活宠物和详细信息 - 从宠物组中获取 # 统计存活宠物和详细信息 - 从宠物组中获取
var all_pets = get_tree().get_nodes_in_group("pets") var all_pets = get_tree().get_nodes_in_group("pets")
@@ -237,22 +237,6 @@ func show_battle_end_panel(winner: String):
if not is_instance_valid(pet): if not is_instance_valid(pet):
continue continue
var status = "💀死亡"
if pet.is_alive:
status = "❤️存活(" + str(int(pet.current_health)) + ")"
if pet.pet_team == "team1":
team1_survivors += 1
elif pet.pet_team == "team2":
team2_survivors += 1
# 统计战力
if pet.pet_team == "team1":
team1_total_damage += pet.attack_damage
team1_pets_info.append(pet.pet_name + " " + status)
elif pet.pet_team == "team2":
team2_total_damage += pet.attack_damage
team2_pets_info.append(pet.pet_name + " " + status)
# 构建结算文本 # 构建结算文本
result_text += "=== 战斗结算 ===\n\n" result_text += "=== 战斗结算 ===\n\n"
@@ -416,39 +400,46 @@ func clear_all_pets():
# 清空对战细节 # 清空对战细节
clear_battle_details() clear_battle_details()
# 先移除宠物组标签 # 批量处理宠物清理,提高性能
var all_pets = get_tree().get_nodes_in_group("pets") var nodes_to_clear = [team1_node, team2_node, neutral_node]
for pet in all_pets:
if is_instance_valid(pet):
# 检查是否是当前面板下的宠物
if pet.get_parent() == team1_node or pet.get_parent() == team2_node or pet.get_parent() == neutral_node:
pet.remove_from_group("pets")
pet.remove_from_group("team1")
pet.remove_from_group("team2")
pet.remove_from_group("neutral")
# 清理现有宠物 for node in nodes_to_clear:
for child in team1_node.get_children(): if not is_instance_valid(node):
if is_instance_valid(child): continue
child.queue_free()
# 先移除组标签,再清理节点
for child in team2_node.get_children(): for child in node.get_children():
if is_instance_valid(child): if is_instance_valid(child):
child.queue_free() # 停止宠物的所有行为,防止在清理过程中继续执行逻辑
if child.has_method("set_combat_enabled"):
for child in neutral_node.get_children(): child.set_combat_enabled(false)
if is_instance_valid(child):
child.queue_free() # 移除所有组标签
child.remove_from_group("pets")
child.remove_from_group("team1")
child.remove_from_group("team2")
child.remove_from_group("neutral")
child.remove_from_group("aid_minions")
# 立即销毁,避免延迟
node.remove_child(child)
child.queue_free()
# 清空队伍数组 # 清空队伍数组
team1_pets.clear() team1_pets.clear()
team2_pets.clear() team2_pets.clear()
# 清理所有子弹 # 清理所有子弹和援助宠物
var all_projectiles = get_tree().get_nodes_in_group("projectiles") var groups_to_clear = ["projectiles", "aid_minions"]
for projectile in all_projectiles: for group_name in groups_to_clear:
if is_instance_valid(projectile): var group_nodes = get_tree().get_nodes_in_group(group_name)
projectile.queue_free() for node in group_nodes:
if is_instance_valid(node):
node.remove_from_group(group_name)
node.queue_free()
# 等待一帧确保清理完成
await get_tree().process_frame
# 处理偷菜对战结果 # 处理偷菜对战结果
func handle_steal_battle_result(winner: String): func handle_steal_battle_result(winner: String):
@@ -556,7 +547,9 @@ func update_battle_pet_data(pet_id: String, attacker_name: String, exp_gained: f
"new_max_experience": max_exp, "new_max_experience": max_exp,
"new_intimacy": current_intimacy, "new_intimacy": current_intimacy,
"level_ups": level_ups, "level_ups": level_ups,
"level_bonus_multiplier": level_bonus_multiplier "level_bonus_multiplier": level_bonus_multiplier,
"is_steal_battle": is_steal_battle,
"battle_winner": winner_team
} }
# 发送数据到服务器 # 发送数据到服务器

View File

@@ -1 +0,0 @@
uid://b4p4xk0pdf7yg

View File

@@ -95,8 +95,9 @@ func _add_message_to_history(data: Dictionary):
# 如果有玩家昵称,优先显示昵称 # 如果有玩家昵称,优先显示昵称
var display_name = player_name if player_name != "" else username var display_name = player_name if player_name != "" else username
# 格式化时间 # 格式化时间 - 确保timestamp是整数类型
var datetime = Time.get_datetime_dict_from_unix_time(timestamp) var timestamp_int = int(timestamp) if typeof(timestamp) == TYPE_STRING else timestamp
var datetime = Time.get_datetime_dict_from_unix_time(timestamp_int)
var time_str = "%04d%02d%02d%02d:%02d:%02d" % [datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second] var time_str = "%04d%02d%02d%02d:%02d:%02d" % [datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second]
# 创建消息记录 # 创建消息记录

View File

@@ -427,7 +427,7 @@ func _on_harvest_button_pressed():
#=================面板通用函数========================== #===================面板通用函数==========================
#退出 #退出
func _on_quit_button_pressed(): func _on_quit_button_pressed():
self.hide() self.hide()
@@ -447,7 +447,7 @@ func _on_visibility_changed():
GlobalVariables.isZoomDisabled = false GlobalVariables.isZoomDisabled = false
pass pass
#=================面板通用函数========================== #===================面板通用函数==========================
# 更新面板信息显示 # 更新面板信息显示
func _update_panel_information(): func _update_panel_information():

View File

@@ -60,9 +60,8 @@ func show_pet_info(pet_name: String, pet_data: Dictionary):
# 设置宠物图片 # 设置宠物图片
_set_pet_image(pet_name) _set_pet_image(pet_name)
# 设置宠物名称 # 设置宠物名称新格式直接从pet_name字段获取
var basic_info = pet_data.get("基本信息", {}) var pet_owner_name = pet_data.get("pet_name", pet_name)
var pet_owner_name = basic_info.get("宠物名称", pet_name)
pet_name_edit.text = pet_owner_name pet_name_edit.text = pet_owner_name
# 设置宠物详细信息 # 设置宠物详细信息
@@ -85,26 +84,40 @@ func _set_pet_image(pet_name: String):
# 获取宠物纹理 # 获取宠物纹理
func _get_pet_texture(pet_name: String) -> Texture2D: func _get_pet_texture(pet_name: String) -> Texture2D:
var pet_config = _load_pet_config() # 从服务器的宠物配置获取场景路径
var pet_config = main_game.pet_config # 使用服务器返回的宠物配置
if pet_config.has(pet_name): if pet_config.has(pet_name):
var pet_info = pet_config[pet_name] var pet_info = pet_config[pet_name]
var scene_path = pet_info.get("场景路径", "") var scene_path = pet_info.get("pet_image", "") # 使用服务器数据的pet_image字段
print("宠物信息面板 ", pet_name, " 的图片路径:", scene_path)
if scene_path != "" and ResourceLoader.exists(scene_path): if scene_path != "" and ResourceLoader.exists(scene_path):
print("宠物信息面板开始加载宠物场景:", scene_path)
var pet_scene = load(scene_path) var pet_scene = load(scene_path)
if pet_scene: if pet_scene:
var pet_instance = pet_scene.instantiate() var pet_instance = pet_scene.instantiate()
var pet_image_node = pet_instance.get_node_or_null("PetImage") # 直接使用实例化的场景根节点,因为根节点就是PetImage
if pet_image_node and pet_image_node.sprite_frames: if pet_instance and pet_instance.sprite_frames:
var animation_names = pet_image_node.sprite_frames.get_animation_names() var animation_names = pet_instance.sprite_frames.get_animation_names()
if animation_names.size() > 0: if animation_names.size() > 0:
var default_animation = animation_names[0] var default_animation = animation_names[0]
var frame_count = pet_image_node.sprite_frames.get_frame_count(default_animation) var frame_count = pet_instance.sprite_frames.get_frame_count(default_animation)
if frame_count > 0: if frame_count > 0:
var texture = pet_image_node.sprite_frames.get_frame_texture(default_animation, 0) var texture = pet_instance.sprite_frames.get_frame_texture(default_animation, 0)
print("宠物信息面板成功获取宠物纹理:", pet_name)
pet_instance.queue_free() pet_instance.queue_free()
return texture return texture
else:
print("宠物信息面板场景没有动画:", pet_name)
else:
print("宠物信息面板场景没有PetImage节点或sprite_frames", pet_name)
pet_instance.queue_free() pet_instance.queue_free()
else:
print("宠物信息面板无法加载宠物场景:", scene_path)
else:
print("宠物信息面板图片路径无效或文件不存在:", scene_path)
else:
print("宠物信息面板配置中没有找到:", pet_name)
return null return null
# 加载宠物配置数据 # 加载宠物配置数据
@@ -123,19 +136,10 @@ func _load_pet_config() -> Dictionary:
return json.data return json.data
# 设置宠物详细信息使用bbcode美化 # 设置宠物详细信息使用bbcode美化- 新格式
func _set_pet_detailed_info(pet_name: String, pet_data: Dictionary): func _set_pet_detailed_info(pet_name: String, pet_data: Dictionary):
var basic_info = pet_data.get("基本信息", {})
var level_exp = pet_data.get("等级经验", {})
var purchase_info = pet_data.get("购买信息", {})
var health_defense = pet_data.get("生命与防御", {})
var attack_info = pet_data.get("基础攻击属性", {})
var movement = pet_data.get("移动与闪避", {})
var element = pet_data.get("元素属性", {})
var quality = pet_data.get("品质系统", {})
# 计算宠物年龄 # 计算宠物年龄
var pet_birthday = basic_info.get("生日", "") var pet_birthday = pet_data.get("pet_birthday", "")
var pet_age = 0 var pet_age = 0
if pet_birthday != "": if pet_birthday != "":
pet_age = _calculate_pet_age(pet_birthday) pet_age = _calculate_pet_age(pet_birthday)
@@ -145,76 +149,64 @@ func _set_pet_detailed_info(pet_name: String, pet_data: Dictionary):
# 基本信息 # 基本信息
info_text += "[color=pink][b]🐾 基本信息[/b][/color]\n" info_text += "[color=pink][b]🐾 基本信息[/b][/color]\n"
info_text += "宠物类型:[color=yellow]" + str(basic_info.get("宠物类型", "未知")) + "[/color]\n" info_text += "宠物类型:[color=yellow]" + str(pet_data.get("pet_type", "未知")) + "[/color]\n"
info_text += "宠物编号:[color=gray]" + str(basic_info.get("宠物ID", "")) + "[/color]\n" info_text += "宠物编号:[color=gray]" + str(pet_data.get("pet_id", "")) + "[/color]\n"
info_text += "性格特点:[color=cyan]" + str(basic_info.get("性格", "活泼")) + "[/color]\n" info_text += "性格特点:[color=cyan]" + str(pet_data.get("pet_temperament", "活泼")) + "[/color]\n"
info_text += "出生日期:[color=green]" + str(pet_birthday) + "[/color]\n" info_text += "出生日期:[color=green]" + str(pet_birthday) + "[/color]\n"
info_text += "年龄天数:[color=orange]" + str(pet_age) + " 天[/color]\n" info_text += "年龄天数:[color=orange]" + str(pet_age) + " 天[/color]\n"
info_text += "爱好:[color=magenta]" + str(pet_data.get("pet_hobby", "")) + "[/color]\n"
info_text += "介绍:[color=lime]" + str(pet_data.get("pet_introduction", "")) + "[/color]\n\n"
# 等级经验 # 等级经验
info_text += "[color=gold][b]⭐ 等级经验[/b][/color]\n" info_text += "[color=gold][b]⭐ 等级经验[/b][/color]\n"
info_text += "当前等级:[color=yellow]" + str(level_exp.get("宠物等级", 1)) + " 级[/color]\n" info_text += "当前等级:[color=yellow]" + str(pet_data.get("pet_level", 1)) + " 级[/color]\n"
info_text += "经验值:[color=cyan]" + str(level_exp.get("当前经验", 0)) + "/" + str(level_exp.get("最大经验", 100)) + "[/color]\n" info_text += "经验值:[color=cyan]" + str(pet_data.get("pet_experience", 0)) + "/" + str(pet_data.get("pet_max_experience", 1000)) + "[/color]\n"
info_text += "亲密度:[color=pink]" + str(level_exp.get("亲密度", 0)) + "/" + str(level_exp.get("最大亲密度", 1000)) + "[/color]\n\n" info_text += "亲密度:[color=pink]" + str(pet_data.get("pet_intimacy", 0)) + "/" + str(pet_data.get("pet_max_intimacy", 1000)) + "[/color]\n\n"
# 生命与防御 # 生命与防御
info_text += "[color=red][b]❤️ 生命与防御[/b][/color]\n" info_text += "[color=red][b]❤️ 生命与防御[/b][/color]\n"
info_text += "生命值:[color=red]" + str(health_defense.get("当前生命值", 0)) + "/" + str(health_defense.get("最大生命值", 0)) + "[/color]\n" info_text += "生命值:[color=red]" + str(pet_data.get("pet_current_health", pet_data.get("max_health", 100))) + "/" + str(pet_data.get("max_health", 100)) + "[/color]\n"
info_text += "护甲值:[color=blue]" + str(health_defense.get("当前护甲值", 0)) + "/" + str(health_defense.get("最大护甲值", 0)) + "[/color]\n" info_text += "护甲值:[color=blue]" + str(pet_data.get("pet_current_armor", pet_data.get("max_armor", 0))) + "/" + str(pet_data.get("max_armor", 0)) + "[/color]\n"
info_text += "护盾值:[color=cyan]" + str(health_defense.get("当前护盾值", 0)) + "/" + str(health_defense.get("最大护盾值", 0)) + "[/color]\n" info_text += "护盾值:[color=cyan]" + str(pet_data.get("pet_current_shield", pet_data.get("max_shield", 0))) + "/" + str(pet_data.get("max_shield", 0)) + "[/color]\n"
info_text += "生命恢复:[color=lime]" + str(health_defense.get("生命恢复速度", 0)) + "/秒[/color]\n\n" info_text += "生命恢复:[color=lime]" + str(pet_data.get("health_regen", 0)) + "/秒[/color]\n"
info_text += "护盾恢复:[color=cyan]" + str(pet_data.get("shield_regen", 0)) + "/秒[/color]\n\n"
# 攻击属性 # 攻击属性
info_text += "[color=orange][b]⚔️ 攻击属性[/b][/color]\n" info_text += "[color=orange][b]⚔️ 攻击属性[/b][/color]\n"
info_text += "攻击类型[color=yellow]" + _get_attack_type_name(str(attack_info.get("攻击类型", "MELEE"))) + "[/color]\n" info_text += "攻击伤害[color=red]" + str(pet_data.get("base_attack_damage", 0)) + "[/color]\n"
info_text += "攻击伤害[color=red]" + str(attack_info.get("基础攻击伤害", 0)) + "[/color]\n" info_text += "暴击几率[color=purple]" + str(pet_data.get("crit_rate", 0) * 100) + "%[/color]\n"
info_text += "攻击距离[color=green]" + str(attack_info.get("攻击距离", 0)) + " 像素[/color]\n" info_text += "暴击倍数[color=purple]" + str(pet_data.get("crit_damage", 1.0)) + " [/color]\n"
info_text += "暴击几率[color=purple]" + str(attack_info.get("暴击率", 0) * 100) + "%[/color]\n" info_text += "护甲穿透[color=orange]" + str(pet_data.get("armor_penetration", 0)) + "[/color]\n"
info_text += "暴击倍数[color=purple]" + str(attack_info.get("暴击伤害倍数", 1.0)) + "[/color]\n" info_text += "左手武器[color=yellow]" + str(pet_data.get("left_weapon", "")) + "[/color]\n"
info_text += "生命汲取[color=magenta]" + str(attack_info.get("生命汲取", 0) * 100) + "%[/color]\n\n" info_text += "右手武器[color=yellow]" + str(pet_data.get("right_weapon", "")) + "[/color]\n\n"
# 移动与闪避 # 移动与闪避
info_text += "[color=green][b]🏃 移动与闪避[/b][/color]\n" info_text += "[color=green][b]🏃 移动与闪避[/b][/color]\n"
info_text += "移动速度:[color=cyan]" + str(movement.get("移动速度", 0)) + " 像素/秒[/color]\n" info_text += "移动速度:[color=cyan]" + str(pet_data.get("move_speed", 0)) + " 像素/秒[/color]\n"
info_text += "闪避几率:[color=yellow]" + str(movement.get("闪避率", 0) * 100) + "%[/color]\n" info_text += "闪避几率:[color=yellow]" + str(pet_data.get("dodge_rate", 0) * 100) + "%[/color]\n\n"
info_text += "击退力度:[color=red]" + str(movement.get("击退力度", 0)) + " 点[/color]\n"
info_text += "击退抗性:[color=blue]" + str(movement.get("击退抗性", 0) * 100) + "%[/color]\n\n"
# 元素属性 # 元素属性
info_text += "[color=purple][b]🔥 元素属性[/b][/color]\n" info_text += "[color=purple][b]🔥 元素属性[/b][/color]\n"
info_text += "元素类型:[color=yellow]" + _get_element_name(str(element.get("元素类型", "NONE"))) + "[/color]\n" info_text += "元素类型:[color=yellow]" + _get_element_name(str(pet_data.get("element_type", "NONE"))) + "[/color]\n"
info_text += "元素伤害:[color=orange]" + str(element.get("元素克制额外伤害", 0)) + " 点[/color]\n\n" info_text += "元素伤害:[color=orange]" + str(pet_data.get("element_damage_bonus", 0)) + " 点[/color]\n\n"
# 品质系统 # 技能系统
var quality_text = str(quality.get("宠物品质", "COMMON")) info_text += "[color=gold][b]✨ 技能系统[/b][/color]\n"
var quality_color = "white" if pet_data.get("enable_multi_projectile_skill", false):
var quality_name = "" info_text += "多重弹射:[color=green]已激活[/color] (延迟: " + str(pet_data.get("multi_projectile_delay", 0)) + "秒)\n"
if quality_text == "COMMON": if pet_data.get("enable_berserker_skill", false):
quality_color = "gray" info_text += "狂暴技能:[color=red]已激活[/color] (倍数: " + str(pet_data.get("berserker_bonus", 1.0)) + ", 持续: " + str(pet_data.get("berserker_duration", 0)) + "秒)\n"
quality_name = "普通" if pet_data.get("enable_self_destruct_skill", false):
elif quality_text == "RARE": info_text += "自爆技能:[color=orange]已激活[/color]\n"
quality_color = "blue" if pet_data.get("enable_summon_pet_skill", false):
quality_name = "稀有" info_text += "召唤技能:[color=cyan]已激活[/color] (数量: " + str(pet_data.get("summon_count", 0)) + ", 缩放: " + str(pet_data.get("summon_scale", 1.0)) + ")\n"
elif quality_text == "EPIC": if pet_data.get("enable_death_respawn_skill", false):
quality_color = "purple" info_text += "死亡重生:[color=purple]已激活[/color] (生命: " + str(pet_data.get("respawn_health_percentage", 0) * 100) + "%)\n"
quality_name = "史诗" info_text += "\n"
elif quality_text == "LEGENDARY":
quality_color = "orange"
quality_name = "传说"
else:
quality_name = quality_text
info_text += "[color=gold][b]✨ 品质系统[/b][/color]\n"
info_text += "宠物品质:[color=" + quality_color + "]" + quality_name + "[/color]\n\n"
# 购买信息
info_text += "[color=gold][b]💰 购买信息[/b][/color]\n"
info_text += "购买价格:[color=yellow]" + str(purchase_info.get("购买价格", 0)) + " 金币[/color]\n"
# 设置文本 # 设置文本
pet_inform.text = info_text pet_inform.text = info_text
# 获取攻击类型名称 # 获取攻击类型名称
func _get_attack_type_name(attack_type: String) -> String: func _get_attack_type_name(attack_type: String) -> String:
match attack_type: match attack_type:
@@ -340,9 +332,8 @@ func on_edit_inform_button_pressed():
Toast.show("宠物名字太长最多20个字符", Color.RED, 2.0, 1.0) Toast.show("宠物名字太长最多20个字符", Color.RED, 2.0, 1.0)
return return
# 获取当前宠物名字 # 获取当前宠物名字(新格式)
var basic_info = current_pet_data.get("基本信息", {}) var current_name = current_pet_data.get("pet_name", "")
var current_name = basic_info.get("宠物名称", "")
# 检查名字是否有变化 # 检查名字是否有变化
if new_pet_name == current_name: if new_pet_name == current_name:
@@ -383,9 +374,8 @@ func _on_confirm_rename_pet(new_name: String, dialog: AcceptDialog):
# 取消重命名宠物 # 取消重命名宠物
func _on_cancel_rename_pet(dialog: AcceptDialog): func _on_cancel_rename_pet(dialog: AcceptDialog):
# 恢复原名字 # 恢复原名字(新格式)
var basic_info = current_pet_data.get("基本信息", {}) var original_name = current_pet_data.get("pet_name", "")
var original_name = basic_info.get("宠物名称", "")
pet_name_edit.text = original_name pet_name_edit.text = original_name
dialog.queue_free() dialog.queue_free()
@@ -395,9 +385,8 @@ func _send_rename_pet_request(new_name: String):
Toast.show("网络功能不可用", Color.RED, 2.0, 1.0) Toast.show("网络功能不可用", Color.RED, 2.0, 1.0)
return return
# 获取宠物ID # 获取宠物ID(新格式)
var basic_info = current_pet_data.get("基本信息", {}) var pet_id = current_pet_data.get("pet_id", "")
var pet_id = basic_info.get("宠物ID", "")
if pet_id == "": if pet_id == "":
Toast.show("宠物ID无效", Color.RED, 2.0, 1.0) Toast.show("宠物ID无效", Color.RED, 2.0, 1.0)
@@ -411,9 +400,9 @@ func _send_rename_pet_request(new_name: String):
# 处理重命名成功的响应(从宠物背包或其他地方调用) # 处理重命名成功的响应(从宠物背包或其他地方调用)
func on_rename_pet_success(pet_id: String, new_name: String): func on_rename_pet_success(pet_id: String, new_name: String):
# 更新当前宠物数据 # 更新当前宠物数据(新格式)
if current_pet_data.get("基本信息", {}).get("宠物ID", "") == pet_id: if current_pet_data.get("pet_id", "") == pet_id:
current_pet_data["基本信息"]["宠物名称"] = new_name current_pet_data["pet_name"] = new_name
pet_name_edit.text = new_name pet_name_edit.text = new_name
Toast.show("宠物名字修改成功!", Color.GREEN, 2.0, 1.0) Toast.show("宠物名字修改成功!", Color.GREEN, 2.0, 1.0)
@@ -469,11 +458,6 @@ func on_use_item_button_pressed():
# 巡逻按钮点击事件 # 巡逻按钮点击事件
func _on_patrol_button_pressed(): func _on_patrol_button_pressed():
#直接在客户端
patro_button.text = "取消巡逻"
patro_button.modulate = Color.ORANGE
if current_pet_data.is_empty(): if current_pet_data.is_empty():
Toast.show("没有选择宠物", Color.RED, 2.0, 1.0) Toast.show("没有选择宠物", Color.RED, 2.0, 1.0)
return return
@@ -484,65 +468,61 @@ func _on_patrol_button_pressed():
return return
# 获取宠物ID # 获取宠物ID
var basic_info = current_pet_data.get("基本信息", {}) var pet_id = current_pet_data.get("pet_id", "")
var pet_id = basic_info.get("宠物ID", "")
if pet_id == "": if pet_id == "":
Toast.show("宠物ID无效", Color.RED, 2.0, 1.0) Toast.show("宠物ID无效", Color.RED, 2.0, 1.0)
return return
# 检查当前宠物是否已在巡逻 # 检查是否已在巡逻
var is_currently_patrolling = _is_pet_patrolling(pet_id) var is_patrolling = _is_pet_patrolling(pet_id)
if is_currently_patrolling: if is_patrolling:
# 取消巡逻 # 取消巡逻 - 发送到服务器
_remove_from_patrol(pet_id) _send_patrol_request(pet_id, false)
var pet_name = current_pet_data.get("pet_name", "宠物")
Toast.show("正在取消 " + pet_name + " 的巡逻...", Color.YELLOW, 2.0, 1.0)
else: else:
# 添加到巡逻 # 检查巡逻宠物数量限制
_add_to_patrol(pet_id) if main_game.patrol_pet_instances.size() >= 4:
Toast.show("最多只能设置4个巡逻宠物", Color.RED, 2.0, 1.0)
return
# 开始巡逻 - 发送到服务器
_send_patrol_request(pet_id, true)
var pet_name = current_pet_data.get("pet_name", "宠物")
#Toast.show("正在设置 " + pet_name + " 为巡逻宠物...", Color.GREEN, 2.0, 1.0)
# 检查宠物是否正在巡逻(基于服务器数据) # 发送巡逻请求到服务器
func _send_patrol_request(pet_id: String, is_patrolling: bool):
var message = {
"type": "set_patrol_pet",
"pet_id": pet_id,
"is_patrolling": is_patrolling
}
tcp_network_manager_panel.client.send_data(message)
# 检查宠物是否在巡逻
func _is_pet_patrolling(pet_id: String) -> bool: func _is_pet_patrolling(pet_id: String) -> bool:
# 检查服务器的巡逻宠物数据 # 检查本地 patrol_pet_instances 数组
if main_game.patrol_pets == null or main_game.patrol_pets.size() == 0: for pet_instance in main_game.patrol_pet_instances:
return false if pet_instance and is_instance_valid(pet_instance):
if pet_instance.pet_id == pet_id:
# 遍历巡逻宠物列表查找匹配的ID return true
for patrol_pet in main_game.patrol_pets:
var patrol_pet_id = patrol_pet.get("基本信息", {}).get("宠物ID", "")
if patrol_pet_id == pet_id:
return true
return false return false
# 添加到巡逻新的基于ID的逻辑 # 移除巡逻宠物
func _add_to_patrol(pet_id: String): func _remove_patrol_pet(pet_id: String):
# 检查巡逻宠物数量限制目前服务器设置最多3个 # 查找并移除对应的巡逻宠物实例
if main_game.patrol_pets != null and main_game.patrol_pets.size() >= 3: for pet_instance in main_game.patrol_pet_instances:
Toast.show("最多只能设置3个巡逻宠物", Color.ORANGE, 3.0, 1.0) if pet_instance and is_instance_valid(pet_instance):
return # 检查是否是对应的巡逻宠物
if pet_instance.pet_id == pet_id:
pet_instance.queue_free()
main_game.patrol_pet_instances.erase(pet_instance)
print("移除巡逻宠物实例: " + pet_instance.pet_name)
return
# 目前简化为只允许一个巡逻宠物 print("未找到对应的巡逻宠物实例: " + pet_id)
if main_game.patrol_pets != null and main_game.patrol_pets.size() >= 1:
Toast.show("已有宠物在巡逻,请先取消当前巡逻", Color.ORANGE, 3.0, 1.0)
return
# 如果不是访问模式,则发送到服务器保存
if not main_game.is_visiting_mode:
# 发送到服务器保存
tcp_network_manager_panel.sendSetPatrolPet(pet_id, true)
var pet_name = current_pet_data.get("基本信息", {}).get("宠物名称", "未知")
else:
Toast.show("访问模式下无法设置巡逻宠物", Color.ORANGE, 2.0, 1.0)
# 从巡逻中移除新的基于ID的逻辑
func _remove_from_patrol(pet_id: String):
# 如果不是访问模式,则发送到服务器保存
if not main_game.is_visiting_mode:
# 发送到服务器移除
tcp_network_manager_panel.sendSetPatrolPet(pet_id, false)
else:
Toast.show("访问模式下无法取消巡逻宠物", Color.ORANGE, 2.0, 1.0)
# 更新巡逻按钮文本 # 更新巡逻按钮文本
func _update_patrol_button_text(is_patrolling: bool): func _update_patrol_button_text(is_patrolling: bool):
@@ -558,8 +538,7 @@ func _refresh_patrol_button():
if current_pet_data.is_empty(): if current_pet_data.is_empty():
return return
var basic_info = current_pet_data.get("基本信息", {}) var pet_id = current_pet_data.get("pet_id", "")
var pet_id = basic_info.get("宠物ID", "")
if pet_id == "": if pet_id == "":
return return
@@ -578,9 +557,8 @@ func _on_battle_button_pressed():
Toast.show("访问模式下无法设置出战宠物", Color.ORANGE, 2.0, 1.0) Toast.show("访问模式下无法设置出战宠物", Color.ORANGE, 2.0, 1.0)
return return
# 获取宠物ID # 获取宠物ID(新格式)
var basic_info = current_pet_data.get("基本信息", {}) var pet_id = current_pet_data.get("pet_id", "")
var pet_id = basic_info.get("宠物ID", "")
if pet_id == "": if pet_id == "":
Toast.show("宠物ID无效", Color.RED, 2.0, 1.0) Toast.show("宠物ID无效", Color.RED, 2.0, 1.0)
@@ -602,9 +580,9 @@ func _is_pet_battling(pet_id: String) -> bool:
if main_game.battle_pets == null or main_game.battle_pets.size() == 0: if main_game.battle_pets == null or main_game.battle_pets.size() == 0:
return false return false
# 遍历出战宠物列表查找匹配的ID # 遍历出战宠物列表查找匹配的ID(新格式)
for battle_pet in main_game.battle_pets: for battle_pet in main_game.battle_pets:
var battle_pet_id = battle_pet.get("基本信息", {}).get("宠物ID", "") var battle_pet_id = battle_pet.get("pet_id", "")
if battle_pet_id == pet_id: if battle_pet_id == pet_id:
return true return true
@@ -612,9 +590,9 @@ func _is_pet_battling(pet_id: String) -> bool:
# 添加到出战新的基于ID的逻辑 # 添加到出战新的基于ID的逻辑
func _add_to_battle(pet_id: String): func _add_to_battle(pet_id: String):
# 检查出战宠物数量限制(目前服务器设置最多1个) # 检查出战宠物数量限制(目前服务器设置最多4个)
if main_game.battle_pets != null and main_game.battle_pets.size() >= 1: if main_game.battle_pets != null and main_game.battle_pets.size() >= 4:
Toast.show("最多只能设置1个出战宠物", Color.ORANGE, 3.0, 1.0) Toast.show("最多只能设置4个出战宠物", Color.ORANGE, 3.0, 1.0)
return return
# 检查是否在巡逻中(出战宠物不能是巡逻宠物) # 检查是否在巡逻中(出战宠物不能是巡逻宠物)
@@ -626,7 +604,7 @@ func _add_to_battle(pet_id: String):
if not main_game.is_visiting_mode: if not main_game.is_visiting_mode:
# 发送到服务器保存 # 发送到服务器保存
tcp_network_manager_panel.sendSetBattlePet(pet_id, true) tcp_network_manager_panel.sendSetBattlePet(pet_id, true)
var pet_name = current_pet_data.get("基本信息", {}).get("宠物名称", "未知") var pet_name = current_pet_data.get("pet_name", "未知")
Toast.show("正在设置 " + pet_name + " 为出战宠物...", Color.YELLOW, 2.0, 1.0) Toast.show("正在设置 " + pet_name + " 为出战宠物...", Color.YELLOW, 2.0, 1.0)
else: else:
Toast.show("访问模式下无法设置出战宠物", Color.ORANGE, 2.0, 1.0) Toast.show("访问模式下无法设置出战宠物", Color.ORANGE, 2.0, 1.0)
@@ -655,8 +633,7 @@ func _refresh_battle_button():
if current_pet_data.is_empty(): if current_pet_data.is_empty():
return return
var basic_info = current_pet_data.get("基本信息", {}) var pet_id = current_pet_data.get("pet_id", "")
var pet_id = basic_info.get("宠物ID", "")
if pet_id == "": if pet_id == "":
return return

View File

@@ -247,15 +247,20 @@ func handle_wisdom_tree_operation_response(success: bool, message: String, opera
# 根据操作类型显示不同的提示 # 根据操作类型显示不同的提示
match operation_type: match operation_type:
"water": "water":
Toast.show("浇水成功!" + message, Color.CYAN) #Toast.show("浇水成功!" + message, Color.CYAN)
pass
"fertilize": "fertilize":
Toast.show("施肥成功!" + message, Color.PURPLE) #Toast.show("施肥成功!" + message, Color.PURPLE)
pass
"kill_grass": "kill_grass":
Toast.show("除草成功!" + message, Color.GREEN) #Toast.show("除草成功!" + message, Color.GREEN)
pass
"kill_bug": "kill_bug":
Toast.show("杀虫成功!" + message, Color.GREEN) #Toast.show("杀虫成功!" + message, Color.GREEN)
pass
"play_music": "play_music":
Toast.show("放音乐成功!" + message, Color.MAGENTA) #Toast.show("放音乐成功!" + message, Color.MAGENTA)
pass
# 放音乐时可能获得随机消息,需要特殊处理 # 放音乐时可能获得随机消息,需要特殊处理
if updated_data.has("random_message"): if updated_data.has("random_message"):
var random_message = updated_data["random_message"] var random_message = updated_data["random_message"]
@@ -293,7 +298,7 @@ func handle_wisdom_tree_message_response(success: bool, message: String, updated
main_game.money = updated_data["钱币"] main_game.money = updated_data["钱币"]
main_game._update_ui() main_game._update_ui()
Toast.show("消息发送成功!", Color.GREEN) #Toast.show("消息发送成功!", Color.GREEN)
else: else:
Toast.show(message, Color.RED) Toast.show(message, Color.RED)

View File

@@ -25,24 +25,24 @@ class ConsoleCommandsAPI:
""" """
self.server = server self.server = server
self.commands = { self.commands = {
"addmoney": self.cmd_add_money, "addmoney": self.cmd_add_money, # 给玩家添加金币
"addxp": self.cmd_add_experience, "addxp": self.cmd_add_experience, # 给玩家添加经验值
"addlevel": self.cmd_add_level, "addlevel": self.cmd_add_level, # 给玩家添加等级
"addseed": self.cmd_add_seed, "addseed": self.cmd_add_seed, # 给玩家添加种子
"lsplayer": self.cmd_list_players, "lsplayer": self.cmd_list_players, # 列出所有玩家
"playerinfo": self.cmd_player_info, "playerinfo": self.cmd_player_info, # 查看玩家信息
"resetland": self.cmd_reset_land, "resetland": self.cmd_reset_land, # 重置玩家土地
"weather": self.cmd_weather, "weather": self.cmd_weather, # 设置天气
"help": self.cmd_help, "help": self.cmd_help, # 显示帮助信息
"stop": self.cmd_stop, "stop": self.cmd_stop, # 停止服务器
"save": self.cmd_save_all, "save": self.cmd_save_all, # 保存所有玩家数据
"reload": self.cmd_reload_config, "reload": self.cmd_reload_config, # 重新加载配置文件
# MongoDB管理命令 # MongoDB管理命令
"dbtest": self.cmd_db_test, "dbtest": self.cmd_db_test, # 测试MongoDB连接
"dbconfig": self.cmd_db_config, "dbconfig": self.cmd_db_config, # 配置MongoDB连接
"dbchat": self.cmd_db_chat, "dbchat": self.cmd_db_chat, # 管理聊天数据
"dbclean": self.cmd_db_clean, "dbclean": self.cmd_db_clean, # 清理数据库
"dbbackup": self.cmd_db_backup "dbbackup": self.cmd_db_backup # 备份数据库
} }
# 初始化MongoDB API # 初始化MongoDB API
@@ -227,36 +227,36 @@ class ConsoleCommandsAPI:
def cmd_list_players(self, args: List[str]): def cmd_list_players(self, args: List[str]):
"""列出所有玩家命令: /lsplayer""" """列出所有玩家命令: /lsplayer"""
saves_dir = "game_saves" try:
if not os.path.exists(saves_dir): # 使用MongoDB获取玩家数据
print("❌ 游戏存档目录不存在") if hasattr(self.server, 'mongo_api') and self.server.mongo_api:
return players_data = self.server.mongo_api.get_all_players_basic_info()
player_files = [f for f in os.listdir(saves_dir) if f.endswith('.json')] if not players_data:
if not player_files: print("📭 暂无已注册玩家")
print("📭 暂无已注册玩家") return
return
print(f"📋 已注册玩家列表 (共 {len(players_data)} 人):")
print(f"📋 已注册玩家列表 (共 {len(player_files)} 人):") print("-" * 80)
print("-" * 80) print(f"{'QQ号':<12} {'昵称':<15} {'等级':<6} {'金币':<10} {'最后登录':<20}")
print(f"{'QQ号':<12} {'昵称':<15} {'等级':<6} {'金币':<10} {'最后登录':<20}") print("-" * 80)
print("-" * 80)
for player in players_data:
for i, filename in enumerate(sorted(player_files), 1): qq_number = player.get("玩家账号", "未知")
qq_number = filename.replace('.json', '') nickname = player.get("玩家昵称", "未设置")
try: level = player.get("等级", 1)
player_data = self.server._load_player_data_from_file(qq_number) money = player.get("钱币", 0)
if player_data: last_login = player.get("最后登录时间", "从未登录")
nickname = player_data.get("玩家昵称", "未设置")
level = player_data.get("等级", 1)
money = player_data.get("钱币", 0)
last_login = player_data.get("最后登录时间", "从未登录")
print(f"{qq_number:<12} {nickname:<15} {level:<6} {money:<10} {last_login:<20}") print(f"{qq_number:<12} {nickname:<15} {level:<6} {money:<10} {last_login:<20}")
except Exception as e:
print(f"{qq_number:<12} {'数据错误':<15} {'--':<6} {'--':<10} {'无法读取':<20}") print("-" * 80)
else:
print("-" * 80) print("❌ 未配置MongoDB连接")
except Exception as e:
print(f"❌ 列出玩家时出错: {str(e)}")
def cmd_player_info(self, args: List[str]): def cmd_player_info(self, args: List[str]):
"""查看玩家信息命令: /playerinfo QQ号""" """查看玩家信息命令: /playerinfo QQ号"""

View File

@@ -211,7 +211,13 @@ class EmailVerification:
# 优先尝试使用MongoDB # 优先尝试使用MongoDB
try: try:
from SMYMongoDBAPI import SMYMongoDBAPI from SMYMongoDBAPI import SMYMongoDBAPI
mongo_api = SMYMongoDBAPI("test") import os
# 根据环境动态选择MongoDB配置
if os.path.exists('/.dockerenv') or os.environ.get('PRODUCTION', '').lower() == 'true':
environment = "production"
else:
environment = "test"
mongo_api = SMYMongoDBAPI(environment)
if mongo_api.is_connected(): if mongo_api.is_connected():
success = mongo_api.save_verification_code(qq_number, verification_code, expiry_time, code_type) success = mongo_api.save_verification_code(qq_number, verification_code, expiry_time, code_type)
if success: if success:
@@ -279,7 +285,13 @@ class EmailVerification:
# 优先尝试使用MongoDB # 优先尝试使用MongoDB
try: try:
from SMYMongoDBAPI import SMYMongoDBAPI from SMYMongoDBAPI import SMYMongoDBAPI
mongo_api = SMYMongoDBAPI("test") import os
# 根据环境动态选择MongoDB配置
if os.path.exists('/.dockerenv') or os.environ.get('PRODUCTION', '').lower() == 'true':
environment = "production"
else:
environment = "test"
mongo_api = SMYMongoDBAPI(environment)
if mongo_api.is_connected(): if mongo_api.is_connected():
success, message = mongo_api.verify_verification_code(qq_number, input_code, code_type) success, message = mongo_api.verify_verification_code(qq_number, input_code, code_type)
print(f"[验证码系统-MongoDB] QQ {qq_number} 验证结果: {success}, 消息: {message}") print(f"[验证码系统-MongoDB] QQ {qq_number} 验证结果: {success}, 消息: {message}")
@@ -364,7 +376,13 @@ class EmailVerification:
# 优先尝试使用MongoDB # 优先尝试使用MongoDB
try: try:
from SMYMongoDBAPI import SMYMongoDBAPI from SMYMongoDBAPI import SMYMongoDBAPI
mongo_api = SMYMongoDBAPI("test") import os
# 根据环境动态选择MongoDB配置
if os.path.exists('/.dockerenv') or os.environ.get('PRODUCTION', '').lower() == 'true':
environment = "production"
else:
environment = "test"
mongo_api = SMYMongoDBAPI(environment)
if mongo_api.is_connected(): if mongo_api.is_connected():
expired_count = mongo_api.clean_expired_verification_codes() expired_count = mongo_api.clean_expired_verification_codes()
print(f"[验证码系统-MongoDB] 清理完成,删除了 {expired_count} 个过期验证码") print(f"[验证码系统-MongoDB] 清理完成,删除了 {expired_count} 个过期验证码")
@@ -433,7 +451,13 @@ class EmailVerification:
# 优先尝试使用MongoDB # 优先尝试使用MongoDB
try: try:
from SMYMongoDBAPI import SMYMongoDBAPI from SMYMongoDBAPI import SMYMongoDBAPI
mongo_api = SMYMongoDBAPI("test") import os
# 根据环境动态选择MongoDB配置
if os.path.exists('/.dockerenv') or os.environ.get('PRODUCTION', '').lower() == 'true':
environment = "production"
else:
environment = "test"
mongo_api = SMYMongoDBAPI(environment)
if mongo_api.is_connected(): if mongo_api.is_connected():
verification_codes = mongo_api.get_verification_codes() verification_codes = mongo_api.get_verification_codes()
if verification_codes and qq_number in verification_codes: if verification_codes and qq_number in verification_codes:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,6 @@ show_help() {
echo " logs - 查看日志" echo " logs - 查看日志"
echo " status - 查看状态" echo " status - 查看状态"
echo " build - 重新构建镜像" echo " build - 重新构建镜像"
echo " clean - 清理停止的容器和未使用的镜像"
echo " help - 显示此帮助信息" echo " help - 显示此帮助信息"
} }
@@ -41,17 +40,10 @@ check_docker() {
start_server() { start_server() {
echo "🚀 启动萌芽农场服务器..." echo "🚀 启动萌芽农场服务器..."
# 检查配置文件是否存在
if [ ! -f "config/crop_data.json" ]; then
echo "⚠️ 警告: 配置文件不存在,请确保 config 目录包含必要的配置文件"
fi
# 启动容器 # 启动容器
docker-compose up -d docker-compose up -d
echo "✅ 服务器启动成功!" echo "✅ 服务器启动成功!"
echo "📡 服务器地址: localhost:6060"
echo "📝 查看日志: $0 logs"
} }
# 停止服务器 # 停止服务器
@@ -83,11 +75,6 @@ show_status() {
if docker-compose ps | grep -q "Up"; then if docker-compose ps | grep -q "Up"; then
echo "✅ 服务器正在运行" echo "✅ 服务器正在运行"
echo "🔗 端口映射: 6060:6060" echo "🔗 端口映射: 6060:6060"
# 显示资源使用情况
echo ""
echo "📈 资源使用情况:"
docker stats --no-stream $CONTAINER_NAME 2>/dev/null || echo "无法获取资源使用情况"
else else
echo "❌ 服务器未运行" echo "❌ 服务器未运行"
fi fi
@@ -100,13 +87,6 @@ build_image() {
echo "✅ 镜像构建完成" echo "✅ 镜像构建完成"
} }
# 清理
clean_up() {
echo "🧹 清理停止的容器和未使用的镜像..."
docker-compose down
docker system prune -f
echo "✅ 清理完成"
}
# 主函数 # 主函数
main() { main() {
@@ -131,9 +111,6 @@ main() {
"build") "build")
build_image build_image
;; ;;
"clean")
clean_up
;;
"help"|*) "help"|*)
show_help show_help
;; ;;

View File

@@ -18,6 +18,7 @@ services:
- PYTHONUNBUFFERED=1 - PYTHONUNBUFFERED=1
- LANG=C.UTF-8 - LANG=C.UTF-8
- LC_ALL=C.UTF-8 - LC_ALL=C.UTF-8
- PRODUCTION=true
networks: networks:
- mengyafarm-network - mengyafarm-network
logging: logging:
@@ -28,4 +29,4 @@ services:
networks: networks:
mengyafarm-network: mengyafarm-network:
driver: bridge driver: bridge

File diff suppressed because it is too large Load Diff

View File

@@ -1,577 +0,0 @@
{
"经验值": 396,
"等级": 5,
"钱币": 11476,
"农场名称": "123",
"玩家昵称": "123",
"玩家账号": "2804775686",
"玩家密码": "123",
"最后登录时间": "2025年07月22日08时51分11秒",
"总游玩时间": "0时3分4秒",
"注册时间": "2025年07月21日20时35分51秒",
"个人简介": "21323123",
"农场土地": [
{
"crop_type": "杂交树2",
"grow_time": 860,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 25200,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "小麦",
"grow_time": 300,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "土豆",
"grow_time": 480,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 480,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "小麦",
"grow_time": 300,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "小麦",
"grow_time": 300,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "小麦",
"grow_time": 300,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "小麦",
"grow_time": 300,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "胡萝卜",
"grow_time": 240,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 240,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "小麦",
"grow_time": 300,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "龙果",
"grow_time": 840,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 14400,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "玉米",
"grow_time": 840,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 900,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "土豆",
"grow_time": 480,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 480,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "玉米",
"grow_time": 830,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 900,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "辣椒",
"grow_time": 650,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 650,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "辣椒",
"grow_time": 650,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 650,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "小麦",
"grow_time": 300,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "胡萝卜",
"grow_time": 240,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 240,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "胡萝卜",
"grow_time": 240,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 240,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "小麦",
"grow_time": 300,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 300,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "玉米",
"grow_time": 810,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 900,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
},
{
"crop_type": "",
"grow_time": 0,
"is_dead": false,
"is_diged": false,
"is_planted": false,
"max_grow_time": 5,
"已浇水": false,
"已施肥": false,
"土地等级": 0
}
],
"种子仓库": [
{
"name": "杂交树1",
"quality": "传奇",
"count": 1
},
{
"name": "小麦",
"quality": "普通",
"count": 6
},
{
"name": "辣椒",
"quality": "普通",
"count": 1
},
{
"name": "胡萝卜",
"quality": "普通",
"count": 8
},
{
"name": "椰子",
"quality": "优良",
"count": 2
}
],
"作物仓库": [
{
"name": "辣椒",
"quality": "普通",
"count": 33
}
],
"道具背包": [],
"宠物背包": [],
"巡逻宠物": [],
"出战宠物": [],
"稻草人配置": {
"已拥有稻草人类型": [
"稻草人1"
],
"稻草人展示类型": "",
"稻草人昵称": "稻草人",
"稻草人说的话": {
"第一句话": {
"内容": "第一句话",
"颜色": "52dceeff"
},
"第二句话": {
"内容": "第二句话",
"颜色": "80d5ffff"
},
"第三句话": {
"内容": "第三句话",
"颜色": "ac52ffff"
},
"第四句话": {
"内容": "第四句话",
"颜色": "f881ffff"
}
},
"稻草人昵称颜色": "b38282ff"
},
"智慧树配置": {
"距离上一次杀虫时间": 1753004237,
"距离上一次除草时间": 1753004237,
"智慧树显示的话": "",
"等级": 1,
"当前经验值": 0,
"最大经验值": 100,
"最大生命值": 100,
"当前生命值": 100,
"高度": 20,
"上次护理时间": 1753101378
},
"签到历史": {
"2025年07月21日21时13分12秒": "金币276 经验56 土豆x2 小麦x4"
},
"在线礼包": {
"当前日期": "2025-07-22",
"今日在线时长": 78.0709433555603,
"已领取礼包": [
"1分钟"
],
"登录时间": 1753145471.320933
},
"点赞系统": {
"今日剩余点赞次数": 10,
"点赞上次刷新时间": "2025-07-22",
"总点赞数": 0
},
"新手礼包": {
"已领取": true,
"领取时间": "2025-07-21 21:13:05"
},
"体力系统": {
"当前体力值": 25,
"最大体力值": 25,
"上次刷新时间": "2025-07-22",
"上次恢复时间": 1753145471.3187816
},
"小卖部配置": {
"商品列表": [],
"格子数": 10
},
"游戏设置": {
"背景音乐音量": 1.0,
"天气显示": true
},
"": "123"
}

View File

@@ -1,4 +1,5 @@
# Game Server Dependencies # Game Server Dependencies
colorama>=0.4.6 # For colored terminal output colorama>=0.4.6 # For colored terminal output
pymongo>=4.6.0 # MongoDB driver for Python
# Email Requirements # Email Requirements
# Standard library dependencies are not listed (socket, threading, json, etc.) # Standard library dependencies are not listed (socket, threading, json, etc.)

View File

@@ -0,0 +1,341 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
宠物数据格式迁移测试脚本
用于验证从旧的嵌套数据格式到新的扁平化数据格式的迁移是否正确
"""
import json
import sys
import os
# 添加当前目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
def test_old_to_new_format_conversion():
"""测试旧格式到新格式的转换"""
print("=== 测试旧格式到新格式的转换 ===")
# 模拟旧格式的宠物数据
old_pet_data = {
"基本信息": {
"宠物ID": "pet_001",
"宠物名称": "小火龙",
"宠物类型": "火系",
"拥有者": "player123",
"场景路径": "res://Scene/Pet/FireDragon.tscn"
},
"等级经验": {
"等级": 5,
"经验值": 150,
"最大经验值": 200
},
"生命与防御": {
"当前生命值": 80,
"最大生命值": 100,
"最大护甲值": 20
},
"基础攻击属性": {
"攻击伤害": 25
},
"移动与闪避": {
"移动速度": 150
},
"亲密度": 75
}
# 转换为新格式
def convert_to_new_format(old_data):
"""将旧格式转换为新格式"""
basic_info = old_data.get("基本信息", {})
level_exp = old_data.get("等级经验", {})
health_defense = old_data.get("生命与防御", {})
attack_attrs = old_data.get("基础攻击属性", {})
movement = old_data.get("移动与闪避", {})
return {
"pet_id": basic_info.get("宠物ID", ""),
"pet_name": basic_info.get("宠物名称", ""),
"pet_type": basic_info.get("宠物类型", ""),
"pet_owner": basic_info.get("拥有者", ""),
"pet_image": basic_info.get("场景路径", ""),
"pet_level": level_exp.get("等级", 1),
"pet_experience": level_exp.get("经验值", 0),
"pet_max_experience": level_exp.get("最大经验值", 100),
"pet_current_health": health_defense.get("当前生命值", 100),
"pet_max_health": health_defense.get("最大生命值", 100),
"pet_max_armor": health_defense.get("最大护甲值", 0),
"pet_attack_damage": attack_attrs.get("攻击伤害", 10),
"pet_move_speed": movement.get("移动速度", 100),
"pet_intimacy": old_data.get("亲密度", 0)
}
new_pet_data = convert_to_new_format(old_pet_data)
print("旧格式数据:")
print(json.dumps(old_pet_data, ensure_ascii=False, indent=2))
print("\n新格式数据:")
print(json.dumps(new_pet_data, ensure_ascii=False, indent=2))
# 验证转换结果
assert new_pet_data["pet_id"] == "pet_001"
assert new_pet_data["pet_name"] == "小火龙"
assert new_pet_data["pet_type"] == "火系"
assert new_pet_data["pet_owner"] == "player123"
assert new_pet_data["pet_level"] == 5
assert new_pet_data["pet_experience"] == 150
assert new_pet_data["pet_max_experience"] == 200
assert new_pet_data["pet_current_health"] == 80
assert new_pet_data["pet_max_health"] == 100
assert new_pet_data["pet_max_armor"] == 20
assert new_pet_data["pet_attack_damage"] == 25
assert new_pet_data["pet_move_speed"] == 150
assert new_pet_data["pet_intimacy"] == 75
print("✅ 旧格式到新格式转换测试通过")
return new_pet_data
def test_new_format_operations(pet_data):
"""测试新格式数据的各种操作"""
print("\n=== 测试新格式数据操作 ===")
# 测试宠物升级
def level_up_pet(pet):
"""模拟宠物升级"""
pet = pet.copy()
pet["pet_level"] += 1
pet["pet_experience"] = 0
pet["pet_max_experience"] = pet["pet_level"] * 100
pet["pet_max_health"] += 10
pet["pet_current_health"] = pet["pet_max_health"]
pet["pet_attack_damage"] += 5
return pet
# 测试宠物喂食
def feed_pet(pet, exp_gain=20):
"""模拟宠物喂食"""
pet = pet.copy()
pet["pet_experience"] = min(pet["pet_experience"] + exp_gain, pet["pet_max_experience"])
pet["pet_intimacy"] = min(pet["pet_intimacy"] + 5, 100)
return pet
# 测试宠物治疗
def heal_pet(pet, heal_amount=20):
"""模拟宠物治疗"""
pet = pet.copy()
pet["pet_current_health"] = min(pet["pet_current_health"] + heal_amount, pet["pet_max_health"])
return pet
print("原始宠物数据:")
print(f"等级: {pet_data['pet_level']}, 经验: {pet_data['pet_experience']}/{pet_data['pet_max_experience']}")
print(f"生命值: {pet_data['pet_current_health']}/{pet_data['pet_max_health']}")
print(f"攻击力: {pet_data['pet_attack_damage']}, 亲密度: {pet_data['pet_intimacy']}")
# 测试喂食
fed_pet = feed_pet(pet_data)
print("\n喂食后:")
print(f"经验: {fed_pet['pet_experience']}/{fed_pet['pet_max_experience']}")
print(f"亲密度: {fed_pet['pet_intimacy']}")
# 测试升级
leveled_pet = level_up_pet(fed_pet)
print("\n升级后:")
print(f"等级: {leveled_pet['pet_level']}, 经验: {leveled_pet['pet_experience']}/{leveled_pet['pet_max_experience']}")
print(f"生命值: {leveled_pet['pet_current_health']}/{leveled_pet['pet_max_health']}")
print(f"攻击力: {leveled_pet['pet_attack_damage']}")
# 测试治疗
# 先模拟受伤
injured_pet = leveled_pet.copy()
injured_pet["pet_current_health"] = 50
print("\n受伤后:")
print(f"生命值: {injured_pet['pet_current_health']}/{injured_pet['pet_max_health']}")
healed_pet = heal_pet(injured_pet)
print("\n治疗后:")
print(f"生命值: {healed_pet['pet_current_health']}/{healed_pet['pet_max_health']}")
print("✅ 新格式数据操作测试通过")
def test_pet_bag_operations():
"""测试宠物背包操作"""
print("\n=== 测试宠物背包操作 ===")
# 创建测试宠物背包
pet_bag = [
{
"pet_id": "pet_001",
"pet_name": "小火龙",
"pet_type": "火系",
"pet_owner": "player123",
"pet_image": "res://Scene/Pet/FireDragon.tscn",
"pet_level": 5,
"pet_experience": 150,
"pet_max_experience": 200,
"pet_current_health": 80,
"pet_max_health": 100,
"pet_max_armor": 20,
"pet_attack_damage": 25,
"pet_move_speed": 150,
"pet_intimacy": 75
},
{
"pet_id": "pet_002",
"pet_name": "水精灵",
"pet_type": "水系",
"pet_owner": "player123",
"pet_image": "res://Scene/Pet/WaterSpirit.tscn",
"pet_level": 3,
"pet_experience": 80,
"pet_max_experience": 150,
"pet_current_health": 60,
"pet_max_health": 80,
"pet_max_armor": 15,
"pet_attack_damage": 20,
"pet_move_speed": 120,
"pet_intimacy": 50
}
]
print(f"宠物背包中有 {len(pet_bag)} 只宠物")
# 测试遍历宠物背包
for i, pet in enumerate(pet_bag):
print(f"\n宠物 {i+1}:")
print(f" ID: {pet['pet_id']}")
print(f" 名称: {pet['pet_name']}")
print(f" 类型: {pet['pet_type']}")
print(f" 等级: {pet['pet_level']}")
print(f" 生命值: {pet['pet_current_health']}/{pet['pet_max_health']}")
print(f" 攻击力: {pet['pet_attack_damage']}")
print(f" 亲密度: {pet['pet_intimacy']}")
# 测试查找特定宠物
def find_pet_by_id(pet_bag, pet_id):
for pet in pet_bag:
if pet.get("pet_id") == pet_id:
return pet
return None
found_pet = find_pet_by_id(pet_bag, "pet_002")
if found_pet:
print(f"\n找到宠物: {found_pet['pet_name']} (ID: {found_pet['pet_id']})")
# 测试按类型筛选宠物
def filter_pets_by_type(pet_bag, pet_type):
return [pet for pet in pet_bag if pet.get("pet_type") == pet_type]
fire_pets = filter_pets_by_type(pet_bag, "火系")
print(f"\n火系宠物数量: {len(fire_pets)}")
# 测试计算总战力
def calculate_total_power(pet_bag):
total_power = 0
for pet in pet_bag:
power = pet.get("pet_level", 1) * 10 + pet.get("pet_attack_damage", 0) + pet.get("pet_max_health", 0)
total_power += power
return total_power
total_power = calculate_total_power(pet_bag)
print(f"\n总战力: {total_power}")
print("✅ 宠物背包操作测试通过")
def test_data_validation():
"""测试数据验证"""
print("\n=== 测试数据验证 ===")
def validate_pet_data(pet):
"""验证宠物数据的完整性"""
required_fields = [
"pet_id", "pet_name", "pet_type", "pet_owner", "pet_image",
"pet_level", "pet_experience", "pet_max_experience",
"pet_current_health", "pet_max_health", "pet_max_armor",
"pet_attack_damage", "pet_move_speed", "pet_intimacy"
]
missing_fields = []
for field in required_fields:
if field not in pet:
missing_fields.append(field)
if missing_fields:
return False, f"缺少字段: {', '.join(missing_fields)}"
# 验证数值范围
if pet["pet_level"] < 1:
return False, "宠物等级不能小于1"
if pet["pet_experience"] < 0:
return False, "宠物经验值不能为负数"
if pet["pet_current_health"] > pet["pet_max_health"]:
return False, "当前生命值不能超过最大生命值"
if pet["pet_intimacy"] < 0 or pet["pet_intimacy"] > 100:
return False, "亲密度必须在0-100之间"
return True, "数据验证通过"
# 测试有效数据
valid_pet = {
"pet_id": "pet_001",
"pet_name": "测试宠物",
"pet_type": "普通",
"pet_owner": "player123",
"pet_image": "res://Scene/Pet/Test.tscn",
"pet_level": 1,
"pet_experience": 0,
"pet_max_experience": 100,
"pet_current_health": 100,
"pet_max_health": 100,
"pet_max_armor": 0,
"pet_attack_damage": 10,
"pet_move_speed": 100,
"pet_intimacy": 0
}
is_valid, message = validate_pet_data(valid_pet)
print(f"有效数据验证: {message}")
assert is_valid, "有效数据应该通过验证"
# 测试无效数据
invalid_pet = valid_pet.copy()
del invalid_pet["pet_name"] # 删除必需字段
is_valid, message = validate_pet_data(invalid_pet)
print(f"无效数据验证: {message}")
assert not is_valid, "无效数据应该不通过验证"
print("✅ 数据验证测试通过")
def main():
"""主测试函数"""
print("开始宠物数据格式迁移测试...\n")
try:
# 测试格式转换
new_pet_data = test_old_to_new_format_conversion()
# 测试新格式操作
test_new_format_operations(new_pet_data)
# 测试宠物背包操作
test_pet_bag_operations()
# 测试数据验证
test_data_validation()
print("\n🎉 所有测试通过!宠物数据格式迁移工作正常。")
except Exception as e:
print(f"\n❌ 测试失败: {str(e)}")
import traceback
traceback.print_exc()
return False
return True
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)

View File

@@ -0,0 +1,219 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
玩家数据MongoDB迁移测试脚本
作者: AI Assistant
功能: 测试玩家数据从JSON文件到MongoDB的迁移和操作功能
"""
import json
import sys
import os
import time
from SMYMongoDBAPI import SMYMongoDBAPI
def test_player_data_operations():
"""测试玩家数据操作"""
print("=== 玩家数据MongoDB操作测试 ===")
# 1. 连接MongoDB
print("\n1. 连接MongoDB...")
try:
api = SMYMongoDBAPI("test")
if not api.is_connected():
print("❌ MongoDB连接失败")
return False
print("✅ MongoDB连接成功")
except Exception as e:
print(f"❌ MongoDB连接异常: {e}")
return False
# 2. 测试获取玩家数据
print("\n2. 测试获取玩家数据...")
test_accounts = ["2143323382", "2804775686", "3205788256"]
for account_id in test_accounts:
try:
player_data = api.get_player_data(account_id)
if player_data:
print(f"✅ 成功获取玩家 {account_id} 的数据")
print(f" 昵称: {player_data.get('玩家昵称', 'N/A')}")
print(f" 等级: {player_data.get('等级', 'N/A')}")
print(f" 金币: {player_data.get('钱币', 'N/A')}")
print(f" 农场土地数量: {len(player_data.get('农场土地', []))}")
else:
print(f"⚠️ 未找到玩家 {account_id} 的数据")
except Exception as e:
print(f"❌ 获取玩家 {account_id} 数据时异常: {e}")
# 3. 测试获取所有玩家基本信息
print("\n3. 测试获取所有玩家基本信息...")
try:
players_info = api.get_all_players_basic_info()
print(f"✅ 成功获取 {len(players_info)} 个玩家的基本信息")
for i, player in enumerate(players_info[:3]): # 只显示前3个
print(f" 玩家{i+1}: {player.get('玩家账号')} - {player.get('玩家昵称')} (等级{player.get('等级')})")
if len(players_info) > 3:
print(f" ... 还有 {len(players_info) - 3} 个玩家")
except Exception as e:
print(f"❌ 获取玩家基本信息时异常: {e}")
# 4. 测试统计玩家总数
print("\n4. 测试统计玩家总数...")
try:
total_count = api.count_total_players()
print(f"✅ 玩家总数: {total_count}")
except Exception as e:
print(f"❌ 统计玩家总数时异常: {e}")
# 5. 测试获取离线玩家
print("\n5. 测试获取离线玩家...")
try:
offline_players = api.get_offline_players(offline_days=1) # 1天内未登录
print(f"✅ 找到 {len(offline_players)} 个离线超过1天的玩家")
for player in offline_players[:3]: # 只显示前3个
account_id = player.get('玩家账号')
last_login = player.get('最后登录时间', 'N/A')
print(f" {account_id}: 最后登录 {last_login}")
except Exception as e:
print(f"❌ 获取离线玩家时异常: {e}")
# 6. 测试更新玩家字段
print("\n6. 测试更新玩家字段...")
if test_accounts:
test_account = test_accounts[0]
try:
# 更新测试字段
update_fields = {
"测试字段": f"测试时间_{int(time.time())}",
"测试更新": True
}
success = api.update_player_field(test_account, update_fields)
if success:
print(f"✅ 成功更新玩家 {test_account} 的字段")
# 验证更新
updated_data = api.get_player_data(test_account)
if updated_data and "测试字段" in updated_data:
print(f" 验证成功: 测试字段 = {updated_data['测试字段']}")
else:
print("⚠️ 更新验证失败")
else:
print(f"❌ 更新玩家 {test_account} 字段失败")
except Exception as e:
print(f"❌ 更新玩家字段时异常: {e}")
# 7. 测试条件查询
print("\n7. 测试条件查询...")
try:
# 查询等级大于等于5的玩家
condition = {"等级": {"$gte": 5}}
projection = {"玩家账号": 1, "玩家昵称": 1, "等级": 1, "钱币": 1}
high_level_players = api.get_players_by_condition(condition, projection, limit=5)
print(f"✅ 找到 {len(high_level_players)} 个等级≥5的玩家")
for player in high_level_players:
print(f" {player.get('玩家账号')}: {player.get('玩家昵称')} (等级{player.get('等级')}, 金币{player.get('钱币')})")
except Exception as e:
print(f"❌ 条件查询时异常: {e}")
# 8. 性能测试
print("\n8. 性能测试...")
try:
start_time = time.time()
# 批量获取玩家基本信息
players_info = api.get_all_players_basic_info()
end_time = time.time()
duration = end_time - start_time
print(f"✅ 获取 {len(players_info)} 个玩家基本信息耗时: {duration:.3f}")
if duration < 1.0:
print(" 性能良好 ✅")
elif duration < 3.0:
print(" 性能一般 ⚠️")
else:
print(" 性能较差,建议优化 ❌")
except Exception as e:
print(f"❌ 性能测试时异常: {e}")
print("\n=== 测试完成 ===")
return True
def test_compatibility_with_file_system():
"""测试与文件系统的兼容性"""
print("\n=== 文件系统兼容性测试 ===")
try:
# 模拟服务器环境
from TCPGameServer import TCPGameServer
# 创建服务器实例(不启动网络服务)
server = TCPGameServer()
# 测试加载玩家数据
test_account = "2143323382"
print(f"\n测试加载玩家数据: {test_account}")
player_data = server.load_player_data(test_account)
if player_data:
print("✅ 成功加载玩家数据")
print(f" 数据源: {'MongoDB' if server.use_mongodb else '文件系统'}")
print(f" 玩家昵称: {player_data.get('玩家昵称', 'N/A')}")
print(f" 等级: {player_data.get('等级', 'N/A')}")
# 测试保存玩家数据
print("\n测试保存玩家数据...")
player_data["测试兼容性"] = f"测试时间_{int(time.time())}"
success = server.save_player_data(test_account, player_data)
if success:
print("✅ 成功保存玩家数据")
# 验证保存
reloaded_data = server.load_player_data(test_account)
if reloaded_data and "测试兼容性" in reloaded_data:
print("✅ 保存验证成功")
else:
print("❌ 保存验证失败")
else:
print("❌ 保存玩家数据失败")
else:
print("❌ 加载玩家数据失败")
except Exception as e:
print(f"❌ 兼容性测试异常: {e}")
import traceback
traceback.print_exc()
def main():
"""主函数"""
try:
# 基本操作测试
test_player_data_operations()
# 兼容性测试
test_compatibility_with_file_system()
except KeyboardInterrupt:
print("\n测试被用户中断")
except Exception as e:
print(f"测试过程中发生异常: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,401 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
服务器宠物功能测试脚本
用于测试TCPGameServer中宠物相关功能是否正常工作
"""
import json
import sys
import os
from unittest.mock import Mock, patch
# 添加当前目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
def test_pet_data_conversion_functions():
"""测试宠物数据转换函数"""
print("=== 测试宠物数据转换函数 ===")
# 模拟TCPGameServer类的部分方法
class MockTCPGameServer:
def _convert_patrol_pets_to_full_data(self, patrol_pets):
"""模拟巡逻宠物数据转换"""
full_pets = []
for pet in patrol_pets:
# 使用新的扁平化数据格式
scene_path = pet.get("pet_image", "")
full_pet = {
"pet_id": pet.get("pet_id", ""),
"pet_name": pet.get("pet_name", ""),
"pet_type": pet.get("pet_type", ""),
"pet_level": pet.get("pet_level", 1),
"pet_current_health": pet.get("pet_current_health", 100),
"pet_max_health": pet.get("pet_max_health", 100),
"pet_attack_damage": pet.get("pet_attack_damage", 10),
"pet_move_speed": pet.get("pet_move_speed", 100),
"scene_path": scene_path
}
full_pets.append(full_pet)
return full_pets
def _convert_battle_pets_to_full_data(self, battle_pets):
"""模拟战斗宠物数据转换"""
return self._convert_patrol_pets_to_full_data(battle_pets)
def _player_has_pet(self, pet_bag, pet_type):
"""检查玩家是否拥有指定类型的宠物"""
for pet in pet_bag:
if pet.get("pet_type", "") == pet_type:
return True
return False
server = MockTCPGameServer()
# 测试数据
test_pets = [
{
"pet_id": "pet_001",
"pet_name": "小火龙",
"pet_type": "火系",
"pet_level": 5,
"pet_current_health": 80,
"pet_max_health": 100,
"pet_attack_damage": 25,
"pet_move_speed": 150,
"pet_image": "res://Scene/Pet/FireDragon.tscn"
},
{
"pet_id": "pet_002",
"pet_name": "水精灵",
"pet_type": "水系",
"pet_level": 3,
"pet_current_health": 60,
"pet_max_health": 80,
"pet_attack_damage": 20,
"pet_move_speed": 120,
"pet_image": "res://Scene/Pet/WaterSpirit.tscn"
}
]
# 测试巡逻宠物转换
patrol_pets = server._convert_patrol_pets_to_full_data(test_pets)
print(f"巡逻宠物转换结果: {len(patrol_pets)} 只宠物")
for pet in patrol_pets:
print(f" {pet['pet_name']} (ID: {pet['pet_id']}) - 场景路径: {pet['scene_path']}")
# 测试战斗宠物转换
battle_pets = server._convert_battle_pets_to_full_data(test_pets)
print(f"\n战斗宠物转换结果: {len(battle_pets)} 只宠物")
# 测试宠物类型检查
has_fire_pet = server._player_has_pet(test_pets, "火系")
has_grass_pet = server._player_has_pet(test_pets, "草系")
print(f"\n玩家是否拥有火系宠物: {has_fire_pet}")
print(f"玩家是否拥有草系宠物: {has_grass_pet}")
assert has_fire_pet == True
assert has_grass_pet == False
print("✅ 宠物数据转换函数测试通过")
def test_pet_feeding_system():
"""测试宠物喂食系统"""
print("\n=== 测试宠物喂食系统 ===")
class MockTCPGameServer:
def _process_pet_feeding(self, pet_data, food_item):
"""模拟宠物喂食处理"""
# 使用新的扁平化数据格式
exp_gain = food_item.get("经验加成", 10)
intimacy_gain = food_item.get("亲密度加成", 5)
# 更新宠物数据
pet_data["pet_experience"] = min(
pet_data.get("pet_experience", 0) + exp_gain,
pet_data.get("pet_max_experience", 100)
)
pet_data["pet_intimacy"] = min(
pet_data.get("pet_intimacy", 0) + intimacy_gain,
100
)
return {
"success": True,
"message": f"{pet_data['pet_name']} 获得了 {exp_gain} 经验和 {intimacy_gain} 亲密度",
"pet_data": pet_data
}
def _apply_level_up_bonus(self, pet_data):
"""模拟宠物升级加成"""
level = pet_data.get("pet_level", 1)
# 使用新的扁平化数据格式
pet_data["pet_max_health"] = pet_data.get("pet_max_health", 100) + 10
pet_data["pet_max_armor"] = pet_data.get("pet_max_armor", 0) + 2
pet_data["pet_attack_damage"] = pet_data.get("pet_attack_damage", 10) + 5
pet_data["pet_move_speed"] = pet_data.get("pet_move_speed", 100) + 5
# 恢复满血
pet_data["pet_current_health"] = pet_data["pet_max_health"]
return pet_data
server = MockTCPGameServer()
# 测试宠物数据
pet_data = {
"pet_id": "pet_001",
"pet_name": "小火龙",
"pet_type": "火系",
"pet_level": 5,
"pet_experience": 180,
"pet_max_experience": 200,
"pet_current_health": 80,
"pet_max_health": 100,
"pet_max_armor": 20,
"pet_attack_damage": 25,
"pet_move_speed": 150,
"pet_intimacy": 75
}
# 测试食物道具
food_item = {
"物品名称": "高级宠物食物",
"经验加成": 25,
"亲密度加成": 10
}
print(f"喂食前: {pet_data['pet_name']} - 经验: {pet_data['pet_experience']}/{pet_data['pet_max_experience']}, 亲密度: {pet_data['pet_intimacy']}")
# 执行喂食
result = server._process_pet_feeding(pet_data, food_item)
if result["success"]:
updated_pet = result["pet_data"]
print(f"喂食后: {updated_pet['pet_name']} - 经验: {updated_pet['pet_experience']}/{updated_pet['pet_max_experience']}, 亲密度: {updated_pet['pet_intimacy']}")
print(f"消息: {result['message']}")
# 检查是否需要升级
if updated_pet["pet_experience"] >= updated_pet["pet_max_experience"]:
print("\n宠物可以升级!")
updated_pet["pet_level"] += 1
updated_pet["pet_experience"] = 0
updated_pet["pet_max_experience"] = updated_pet["pet_level"] * 100
# 应用升级加成
updated_pet = server._apply_level_up_bonus(updated_pet)
print(f"升级后: {updated_pet['pet_name']} - 等级: {updated_pet['pet_level']}, 生命值: {updated_pet['pet_current_health']}/{updated_pet['pet_max_health']}, 攻击力: {updated_pet['pet_attack_damage']}")
print("✅ 宠物喂食系统测试通过")
def test_pet_item_usage():
"""测试宠物道具使用"""
print("\n=== 测试宠物道具使用 ===")
class MockTCPGameServer:
def _process_pet_item_use(self, pet_data, item_data):
"""模拟宠物道具使用处理"""
item_name = item_data.get("物品名称", "")
# 使用新的扁平化数据格式获取宠物名称
pet_name = pet_data.get("pet_name", "未知宠物")
if "治疗" in item_name:
# 治疗道具
heal_amount = item_data.get("治疗量", 20)
pet_data["pet_current_health"] = min(
pet_data.get("pet_current_health", 0) + heal_amount,
pet_data.get("pet_max_health", 100)
)
return {
"success": True,
"message": f"{pet_name} 使用了 {item_name},恢复了 {heal_amount} 生命值"
}
elif "经验" in item_name:
# 经验道具
exp_gain = item_data.get("经验加成", 50)
pet_data["pet_experience"] = min(
pet_data.get("pet_experience", 0) + exp_gain,
pet_data.get("pet_max_experience", 100)
)
return {
"success": True,
"message": f"{pet_name} 使用了 {item_name},获得了 {exp_gain} 经验值"
}
else:
return {
"success": False,
"message": f"未知的道具类型: {item_name}"
}
server = MockTCPGameServer()
# 测试宠物数据
pet_data = {
"pet_id": "pet_001",
"pet_name": "小火龙",
"pet_type": "火系",
"pet_level": 3,
"pet_experience": 50,
"pet_max_experience": 150,
"pet_current_health": 40,
"pet_max_health": 80,
"pet_attack_damage": 20,
"pet_intimacy": 60
}
# 测试治疗道具
heal_item = {
"物品名称": "高级治疗药水",
"治疗量": 30
}
print(f"使用治疗道具前: {pet_data['pet_name']} - 生命值: {pet_data['pet_current_health']}/{pet_data['pet_max_health']}")
result = server._process_pet_item_use(pet_data, heal_item)
if result["success"]:
print(f"使用治疗道具后: {pet_data['pet_name']} - 生命值: {pet_data['pet_current_health']}/{pet_data['pet_max_health']}")
print(f"消息: {result['message']}")
# 测试经验道具
exp_item = {
"物品名称": "经验药水",
"经验加成": 80
}
print(f"\n使用经验道具前: {pet_data['pet_name']} - 经验: {pet_data['pet_experience']}/{pet_data['pet_max_experience']}")
result = server._process_pet_item_use(pet_data, exp_item)
if result["success"]:
print(f"使用经验道具后: {pet_data['pet_name']} - 经验: {pet_data['pet_experience']}/{pet_data['pet_max_experience']}")
print(f"消息: {result['message']}")
print("✅ 宠物道具使用测试通过")
def test_pet_bag_operations():
"""测试宠物背包操作"""
print("\n=== 测试宠物背包操作 ===")
# 模拟宠物背包数据
pet_bag = [
{
"pet_id": "pet_001",
"pet_name": "小火龙",
"pet_type": "火系",
"pet_owner": "player123",
"pet_image": "res://Scene/Pet/FireDragon.tscn",
"pet_level": 5,
"pet_experience": 150,
"pet_max_experience": 200,
"pet_current_health": 80,
"pet_max_health": 100,
"pet_max_armor": 20,
"pet_attack_damage": 25,
"pet_move_speed": 150,
"pet_intimacy": 75
},
{
"pet_id": "pet_002",
"pet_name": "水精灵",
"pet_type": "水系",
"pet_owner": "player123",
"pet_image": "res://Scene/Pet/WaterSpirit.tscn",
"pet_level": 3,
"pet_experience": 80,
"pet_max_experience": 150,
"pet_current_health": 60,
"pet_max_health": 80,
"pet_max_armor": 15,
"pet_attack_damage": 20,
"pet_move_speed": 120,
"pet_intimacy": 50
}
]
print(f"宠物背包中有 {len(pet_bag)} 只宠物")
# 测试遍历宠物背包模拟TCPGameServer中的for pet in pet_bag循环
print("\n遍历宠物背包:")
for pet in pet_bag:
# 使用新的扁平化数据格式
pet_id = pet.get("pet_id", "")
pet_name = pet.get("pet_name", "")
pet_type = pet.get("pet_type", "")
pet_level = pet.get("pet_level", 1)
pet_health = pet.get("pet_current_health", 0)
pet_max_health = pet.get("pet_max_health", 100)
pet_attack = pet.get("pet_attack_damage", 10)
pet_intimacy = pet.get("pet_intimacy", 0)
print(f" 宠物ID: {pet_id}")
print(f" 名称: {pet_name} ({pet_type})")
print(f" 等级: {pet_level}")
print(f" 生命值: {pet_health}/{pet_max_health}")
print(f" 攻击力: {pet_attack}")
print(f" 亲密度: {pet_intimacy}")
print(" ---")
# 测试查找特定宠物
target_pet_id = "pet_002"
found_pet = None
for pet in pet_bag:
if pet.get("pet_id") == target_pet_id:
found_pet = pet
break
if found_pet:
print(f"\n找到宠物 {target_pet_id}: {found_pet['pet_name']}")
else:
print(f"\n未找到宠物 {target_pet_id}")
# 测试统计信息
total_pets = len(pet_bag)
total_level = sum(pet.get("pet_level", 1) for pet in pet_bag)
avg_level = total_level / total_pets if total_pets > 0 else 0
total_intimacy = sum(pet.get("pet_intimacy", 0) for pet in pet_bag)
avg_intimacy = total_intimacy / total_pets if total_pets > 0 else 0
print(f"\n统计信息:")
print(f" 总宠物数: {total_pets}")
print(f" 平均等级: {avg_level:.1f}")
print(f" 平均亲密度: {avg_intimacy:.1f}")
print("✅ 宠物背包操作测试通过")
def main():
"""主测试函数"""
print("开始服务器宠物功能测试...\n")
try:
# 测试宠物数据转换函数
test_pet_data_conversion_functions()
# 测试宠物喂食系统
test_pet_feeding_system()
# 测试宠物道具使用
test_pet_item_usage()
# 测试宠物背包操作
test_pet_bag_operations()
print("\n🎉 所有服务器宠物功能测试通过!")
print("\n✅ 确认事项:")
print(" - 宠物数据转换函数正常工作")
print(" - 宠物喂食系统使用新的扁平化数据格式")
print(" - 宠物道具使用系统正确访问宠物名称")
print(" - 宠物背包遍历操作正常")
print(" - 所有宠物相关功能已适配新数据格式")
except Exception as e:
print(f"\n❌ 测试失败: {str(e)}")
import traceback
traceback.print_exc()
return False
return True
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)

BIN
assets/子弹图片/01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://by01joyt7e4qh"
path="res://.godot/imported/01.png-95d14629d6075888bdfa42cfcf0c603f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/01.png"
dest_files=["res://.godot/imported/01.png-95d14629d6075888bdfa42cfcf0c603f.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cw337up7enoqo"
path="res://.godot/imported/02.png-8c04c6e2ccab9682d7ebe159c604764a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/02.png"
dest_files=["res://.godot/imported/02.png-8c04c6e2ccab9682d7ebe159c604764a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/03.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bf27ywrn16wcv"
path="res://.godot/imported/03.png-dab68a06be5dfaf312394a4d0cee9345.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/03.png"
dest_files=["res://.godot/imported/03.png-dab68a06be5dfaf312394a4d0cee9345.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/04.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bwfr3uilkxq6a"
path="res://.godot/imported/04.png-847c786ac8c8e35fec1adc87f18c6efa.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/04.png"
dest_files=["res://.godot/imported/04.png-847c786ac8c8e35fec1adc87f18c6efa.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/05.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c20yr5fi7byd"
path="res://.godot/imported/05.png-d36e682cb08cded77cc6343a325c052f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/05.png"
dest_files=["res://.godot/imported/05.png-d36e682cb08cded77cc6343a325c052f.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/06.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bavb0dpa8pbsd"
path="res://.godot/imported/06.png-553dafed3a6433f4ccb08f17c6350162.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/06.png"
dest_files=["res://.godot/imported/06.png-553dafed3a6433f4ccb08f17c6350162.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/07.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dh1wy2mn54a36"
path="res://.godot/imported/07.png-585fa9b6df3f18f4c8863246085a00f3.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/07.png"
dest_files=["res://.godot/imported/07.png-585fa9b6df3f18f4c8863246085a00f3.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/08.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dqwum77jcqkdy"
path="res://.godot/imported/08.png-5040cae4ec067dac0757eaa028cf89c3.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/08.png"
dest_files=["res://.godot/imported/08.png-5040cae4ec067dac0757eaa028cf89c3.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/09.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cleyjr7css15h"
path="res://.godot/imported/09.png-9238e10e67248408a3bf17849b66aceb.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/09.png"
dest_files=["res://.godot/imported/09.png-9238e10e67248408a3bf17849b66aceb.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://csmi7hdbgjqjv"
path="res://.godot/imported/21.png-5303d7aebe0a4b42c955d30435004edf.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/21.png"
dest_files=["res://.godot/imported/21.png-5303d7aebe0a4b42c955d30435004edf.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/22.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bknpmcntsy5lb"
path="res://.godot/imported/22.png-570b7d75cb7a42beedccaf1ee60b755d.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/22.png"
dest_files=["res://.godot/imported/22.png-570b7d75cb7a42beedccaf1ee60b755d.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/23.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://htnv7xp8fpu4"
path="res://.godot/imported/23.png-211603348421cbb9dc3c19157b492009.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/23.png"
dest_files=["res://.godot/imported/23.png-211603348421cbb9dc3c19157b492009.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://qwjqjsp56d5s"
path="res://.godot/imported/24.png-fc0117a03f48e5c6c011413ae5ff24ec.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/24.png"
dest_files=["res://.godot/imported/24.png-fc0117a03f48e5c6c011413ae5ff24ec.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/25.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://omdy6jm6mbbn"
path="res://.godot/imported/25.png-5fb7f030a337625c846241a4f9950920.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/25.png"
dest_files=["res://.godot/imported/25.png-5fb7f030a337625c846241a4f9950920.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/26.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b3av75j22a5ux"
path="res://.godot/imported/26.png-0694d83edb39904e612c803997cab92a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/26.png"
dest_files=["res://.godot/imported/26.png-0694d83edb39904e612c803997cab92a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/30.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bq4yl28vrqg0n"
path="res://.godot/imported/30.png-6d3aacaba3ae939e0d65327529fda88c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/30.png"
dest_files=["res://.godot/imported/30.png-6d3aacaba3ae939e0d65327529fda88c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/31.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://pcgkxxyh2vtq"
path="res://.godot/imported/31.png-150a0be9a006adebb26ac0942b5f1c58.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/31.png"
dest_files=["res://.godot/imported/31.png-150a0be9a006adebb26ac0942b5f1c58.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bpu8yonk72iqf"
path="res://.godot/imported/32.png-3a0f744edb5eab8df015c04dd875c0e9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/子弹图片/32.png"
dest_files=["res://.godot/imported/32.png-3a0f744edb5eab8df015c04dd875c0e9.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.01
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

BIN
assets/子弹图片/33.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Some files were not shown because too many files have changed in this diff Show More