大更新,太多了,具体进游戏查看详细更新内容

反正很多
This commit is contained in:
2025-05-27 11:09:09 +08:00
parent a1e71a6a79
commit 8215cfa3ee
382 changed files with 13838 additions and 2974 deletions

View File

@@ -1,19 +0,0 @@
extends Panel
#用户登录账号用QQ号代替
@onready var username_input = $username_input
#用户登录密码
@onready var password_input = $password_input
#登录按钮
@onready var login_button = $login_button
func _ready():
pass
func _process(delta):
pass
func _on_login_button_pressed():
pass

22
GUI/SMY_ProgressBar.gd Normal file
View File

@@ -0,0 +1,22 @@
extends ProgressBar
var target_value: float = 0.0
var animation_speed: float = 2.0
func _ready():
# 初始化进度条的颜色
modulate = Color(0.6, 0, 0.0) # 从红色到绿色的渐变
func _process(delta):
update_progress_visuals()
func set_target_value(new_value: float):
value = new_value
func update_progress_visuals():
# 改变进度条的颜色
var fill_ratio = value / max_value
modulate = Color(0.6 - fill_ratio, fill_ratio, 0.0) # 从红色到绿色的渐变
#modulate = Color(1.0 - fill_ratio, fill_ratio, 0.0) # 从红色到绿色的渐变
#modulate = Color(0.0, 1.0 - fill_ratio, fill_ratio) # 从蓝色到绿色的渐变
#modulate = Color(0.0, 1.0 - fill_ratio, fill_ratio * 0.75) # 从绿色到淡蓝色的渐变

View File

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

494
GUI/crop_store_panel.gd Normal file
View File

@@ -0,0 +1,494 @@
extends Panel
#种子商店面板
#种子商店格子
@onready var crop_grid_container : GridContainer = $ScrollContainer/Crop_Grid
@onready var quit_button : Button = $QuitButton
#各种排序过滤按钮
@onready var sort_all_button : Button = $SortContainer/Sort_All#全部
@onready var sort_common_button : Button = $SortContainer/Sort_Common#普通
@onready var sort_superior_button : Button = $SortContainer/Sort_Superior#优良
@onready var sort_rare_button : Button = $SortContainer/Sort_Rare#稀有
@onready var sort_epic_button : Button = $SortContainer/Sort_Epic#史诗
@onready var sort_legendary_button : Button = $SortContainer/Sort_Legendary#传奇
@onready var sort_price_button : Button = $SortContainer/Sort_Price#价格
@onready var sort_growtime_button : Button = $SortContainer/Sort_GrowTime#生长时间
@onready var sort_profit_button : Button = $SortContainer/Sort_Profit#收益
@onready var sort_level_button : Button = $SortContainer/Sort_Level#等级
#预添加常用的面板
@onready var main_game = get_node("/root/main")
@onready var land_panel = get_node("/root/main/UI/LandPanel")
@onready var crop_store_panel = get_node("/root/main/UI/PlayerBagPanel")
@onready var player_ranking_panel = get_node("/root/main/UI/PlayerRankingPanel")
@onready var player_bag_panel = get_node("/root/main/UI/PlayerBagPanel")
@onready var network_manager = get_node("/root/main/UI/TCPNetworkManager")
# 作物图片缓存(复用主游戏的缓存系统)
var crop_textures_cache : Dictionary = {}
var crop_frame_counts : Dictionary = {}
# 当前过滤和排序设置
var current_filter_quality = ""
var current_sort_key = ""
var current_sort_ascending = true
# 准备函数
func _ready():
# 连接按钮信号
_connect_buttons()
# 隐藏面板(初始默认隐藏)
self.hide()
# 连接所有按钮信号
func _connect_buttons():
# 关闭按钮
quit_button.pressed.connect(self._on_quit_button_pressed)
# 过滤按钮
sort_all_button.pressed.connect(func(): _filter_by_quality(""))
sort_common_button.pressed.connect(func(): _filter_by_quality("普通"))
sort_superior_button.pressed.connect(func(): _filter_by_quality("优良"))
sort_rare_button.pressed.connect(func(): _filter_by_quality("稀有"))
sort_epic_button.pressed.connect(func(): _filter_by_quality("史诗"))
sort_legendary_button.pressed.connect(func(): _filter_by_quality("传奇"))
# 排序按钮
sort_price_button.pressed.connect(func(): _sort_by("花费"))
sort_growtime_button.pressed.connect(func(): _sort_by("生长时间"))
sort_profit_button.pressed.connect(func(): _sort_by("收益"))
sort_level_button.pressed.connect(func(): _sort_by("等级"))
# 初始化商店
func init_store():
print("初始化商店...")
# 清空已有的作物按钮
for child in crop_grid_container.get_children():
child.queue_free()
# 遍历可种植的作物数据并添加到商店
print("初始化商店,显示所有作物...")
for crop_name in main_game.can_planted_crop:
var crop = main_game.can_planted_crop[crop_name]
# 只显示当前等级可以种植的作物
if crop["等级"] <= main_game.level:
var store_btn = _create_store_button(crop_name, crop["品质"])
crop_grid_container.add_child(store_btn)
#print("添加商店按钮: " + crop_name)
print("商店初始化完成,共添加按钮: " + str(crop_grid_container.get_child_count()) + "")
# 更新金钱显示
_update_money_display()
# 创建商店按钮
func _create_store_button(crop_name: String, crop_quality: String) -> Button:
# 根据品质选择相应的按钮
var button = null
match crop_quality:
"普通":
button = main_game.green_bar.duplicate()
"优良":
button = main_game.orange_bar.duplicate()
"稀有":
button = main_game.white_blue_bar.duplicate()
"史诗":
button = main_game.pink_bar.duplicate()
"传奇":
button = main_game.black_blue_bar.duplicate()
_: # 默认情况
button = main_game.green_bar.duplicate()
var crop = main_game.can_planted_crop[crop_name]
# 确保按钮可见并可点击
button.visible = true
button.disabled = false
button.focus_mode = Control.FOCUS_ALL
# 设置按钮文本,显示价格
button.text = str(crop_quality + "-" + crop_name + "\n价格: ¥" + str(crop["花费"]))
# 将成熟时间从秒转换为天时分秒格式
var total_seconds = int(crop["生长时间"])
# 定义时间单位换算
var SECONDS_PER_MINUTE = 60
var SECONDS_PER_HOUR = 3600
var SECONDS_PER_DAY = 86400
# 计算各时间单位
var days = total_seconds / SECONDS_PER_DAY
total_seconds %= SECONDS_PER_DAY
var hours = total_seconds / SECONDS_PER_HOUR
total_seconds %= SECONDS_PER_HOUR
var minutes = total_seconds / SECONDS_PER_MINUTE
var seconds = total_seconds % SECONDS_PER_MINUTE
# 构建时间字符串(只显示有值的单位)
var time_str = ""
if days > 0:
time_str += str(days) + ""
if hours > 0:
time_str += str(hours) + "小时"
if minutes > 0:
time_str += str(minutes) + "分钟"
if seconds > 0:
time_str += str(seconds) + ""
button.tooltip_text = str(
"作物: " + crop_name + "\n" +
"品质: " + crop_quality + "\n" +
"价格: " + str(crop["花费"]) + "\n" +
"成熟时间: " + time_str + "\n" +
"收获收益: " + str(crop["收益"]) + "\n" +
"需求等级: " + str(crop["等级"]) + "\n" +
"耐候性: " + str(crop["耐候性"]) + "\n" +
"经验: " + str(crop["经验"]) + "\n" +
"描述: " + str(crop["描述"])
)
# 添加按钮事件
button.pressed.connect(func(): _on_store_buy_pressed(crop_name))
# 更新按钮的作物图片
_update_button_crop_image(button, crop_name)
# 如果按钮有标题标签,设置标题
if button.has_node("Title"):
match crop_quality:
"普通":
button.get_node("Title").modulate = Color.HONEYDEW#白色
"优良":
button.get_node("Title").modulate =Color.DODGER_BLUE#深蓝色
"稀有":
button.get_node("Title").modulate =Color.HOT_PINK#品红色
"史诗":
button.get_node("Title").modulate =Color.YELLOW#黄色
"传奇":
button.get_node("Title").modulate =Color.ORANGE_RED#红色
return button
# 购买种子事件处理
func _on_store_buy_pressed(crop_name: String):
print("购买种子: " + crop_name)
var crop = main_game.can_planted_crop[crop_name]
# 检查等级要求
if main_game.level < crop["等级"]:
Toast.show("等级不足,无法购买此种子", Color.RED)
return
# 检查金钱是否足够
if main_game.money < crop["花费"]:
Toast.show("金钱不足,无法购买种子", Color.RED)
return
# 发送购买请求到服务器
if network_manager and network_manager.sendBuySeed(crop_name):
# 购买请求已发送,等待服务器响应
Toast.show("正在购买种子...", Color.YELLOW, 2.0, 1.0)
# 将种子添加到背包
var found = false
for seed_item in main_game.player_bag:
if seed_item["name"] == crop_name:
seed_item["count"] += 1
found = true
break
if not found:
main_game.player_bag.append({
"name": crop_name,
"quality": crop["品质"],
"count": 1
})
# 显示购买成功消息
Toast.show("购买了" + crop["品质"] + "-" + crop_name + "种子", Color.GREEN)
# 更新背包UI
crop_store_panel.update_player_bag_ui()
# 更新金钱显示
_update_money_display()
# 关闭面板
func _on_quit_button_pressed():
print("关闭商店面板")
self.hide()
# 按品质过滤作物
func _filter_by_quality(quality: String):
current_filter_quality = quality
print("过滤作物,品质: " + (quality if quality != "" else "全部"))
_apply_filter_and_sort()
# 按指定键排序
func _sort_by(sort_key: String):
# 切换排序方向或设置新排序键
if current_sort_key == sort_key:
current_sort_ascending = !current_sort_ascending
else:
current_sort_key = sort_key
current_sort_ascending = true
print("排序作物,键: " + sort_key + ",升序: " + str(current_sort_ascending))
_apply_filter_and_sort()
# 应用过滤和排序
func _apply_filter_and_sort():
# 清空现有按钮
for child in crop_grid_container.get_children():
child.queue_free()
# 收集符合条件的作物
var filtered_crops = []
for crop_name in main_game.can_planted_crop:
var crop = main_game.can_planted_crop[crop_name]
# 检查等级和品质过滤
if crop["等级"] > main_game.level:
continue
if current_filter_quality != "" and crop["品质"] != current_filter_quality:
continue
# 添加到过滤后的列表
filtered_crops.append({
"name": crop_name,
"data": crop
})
# 如果有排序条件,进行排序
if current_sort_key != "":
filtered_crops.sort_custom(Callable(self, "_sort_crop_items"))
# 添加所有过滤和排序后的作物
for crop in filtered_crops:
var store_btn = _create_store_button(crop["name"], crop["data"]["品质"])
crop_grid_container.add_child(store_btn)
# 更新金钱显示
_update_money_display()
# 自定义排序函数
func _sort_crop_items(a, b):
if current_sort_ascending:
return a["data"][current_sort_key] < b["data"][current_sort_key]
else:
return a["data"][current_sort_key] > b["data"][current_sort_key]
# 更新金钱显示
func _update_money_display():
var money_label = get_node_or_null("MoneyLabel")
if money_label == null:
# 创建金钱显示标签
money_label = Label.new()
money_label.name = "MoneyLabel"
money_label.position = Vector2(10, 10)
money_label.size = Vector2(300, 45)
# 设置标签样式
money_label.add_theme_color_override("font_color", Color(1, 0.647, 0, 1)) # 橙色
money_label.add_theme_font_size_override("font_size", 24)
add_child(money_label)
# 更新金钱显示
money_label.text = "当前金钱:" + str(main_game.money) + ""
print("更新商店金钱显示:" + str(main_game.money))
# 刷新商店内容,可以在金钱变化或等级提升后调用
func refresh_store():
# 清空并重新创建商店按钮
init_store()
# 尝试创建过滤按钮(如果商店面板中没有这些按钮)
_create_filter_buttons_if_needed()
# 如果需要,动态创建过滤按钮
func _create_filter_buttons_if_needed():
# 检查是否已存在过滤器容器
var filter_container = get_node_or_null("FilterContainer")
if filter_container == null:
# 创建过滤器容器
filter_container = HBoxContainer.new()
filter_container.name = "FilterContainer"
# 设置容器位置和大小
filter_container.position = Vector2(320, 10)
filter_container.size = Vector2(770, 45)
add_child(filter_container)
# 添加过滤按钮
_add_filter_button(filter_container, "全部", func(): _filter_by_quality(""))
_add_filter_button(filter_container, "普通", func(): _filter_by_quality("普通"))
_add_filter_button(filter_container, "优良", func(): _filter_by_quality("优良"))
_add_filter_button(filter_container, "稀有", func(): _filter_by_quality("稀有"))
_add_filter_button(filter_container, "史诗", func(): _filter_by_quality("史诗"))
_add_filter_button(filter_container, "传奇", func(): _filter_by_quality("传奇"))
# 检查是否已存在排序容器
var sort_container = get_node_or_null("SortContainer")
if sort_container == null:
# 创建排序容器
sort_container = HBoxContainer.new()
sort_container.name = "SortContainer"
# 设置容器位置和大小
sort_container.position = Vector2(320, 55)
sort_container.size = Vector2(770, 30)
add_child(sort_container)
# 添加排序按钮
_add_filter_button(sort_container, "按价格", func(): _sort_by("花费"))
_add_filter_button(sort_container, "按生长时间", func(): _sort_by("生长时间"))
_add_filter_button(sort_container, "按收益", func(): _sort_by("收益"))
_add_filter_button(sort_container, "按等级", func(): _sort_by("等级"))
# 添加过滤按钮
func _add_filter_button(container, text, callback):
var button = Button.new()
button.text = text
button.custom_minimum_size = Vector2(100, 0)
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
container.add_child(button)
button.pressed.connect(callback)
# 获取作物的最后一帧图片(用于商店显示)
func _get_crop_final_texture(crop_name: String) -> Texture2D:
"""
获取作物的最后一帧图片,用于商店和背包显示
如果作物图片不存在,使用默认图片的最后一帧
"""
# 先尝试从主游戏的缓存中获取
if main_game and main_game.crop_textures_cache.has(crop_name):
var textures = main_game.crop_textures_cache[crop_name]
if textures.size() > 0:
return textures[textures.size() - 1] # 返回最后一帧
# 如果主游戏缓存中没有,自己加载
var textures = _load_crop_textures(crop_name)
if textures.size() > 0:
return textures[textures.size() - 1] # 返回最后一帧
return null
# 加载作物图片序列帧(复用主游戏的逻辑)
func _load_crop_textures(crop_name: String) -> Array:
"""
加载指定作物的所有序列帧图片
"""
if crop_textures_cache.has(crop_name):
return crop_textures_cache[crop_name]
var textures = []
var crop_path = "res://assets/作物/" + crop_name + "/"
var default_path = "res://assets/作物/默认/"
# 检查作物文件夹是否存在
if DirAccess.dir_exists_absolute(crop_path):
# 尝试加载作物的序列帧从0开始
var frame_index = 0
while true:
var texture_path = crop_path + str(frame_index) + ".png"
if ResourceLoader.exists(texture_path):
var texture = load(texture_path)
if texture:
textures.append(texture)
frame_index += 1
else:
break
else:
break
if textures.size() > 0:
print("商店加载作物 ", crop_name, "", textures.size(), " 帧图片")
else:
print("商店:作物 ", crop_name, " 文件夹存在但没有找到有效图片,使用默认图片")
textures = _load_default_textures()
else:
print("商店:作物 ", crop_name, " 的文件夹不存在,使用默认图片")
textures = _load_default_textures()
# 缓存结果
crop_textures_cache[crop_name] = textures
crop_frame_counts[crop_name] = textures.size()
return textures
# 加载默认图片
func _load_default_textures() -> Array:
"""
加载默认作物图片
"""
if crop_textures_cache.has("默认"):
return crop_textures_cache["默认"]
var textures = []
var default_path = "res://assets/作物/默认/"
# 尝试加载默认图片序列帧
var frame_index = 0
while true:
var texture_path = default_path + str(frame_index) + ".png"
if ResourceLoader.exists(texture_path):
var texture = load(texture_path)
if texture:
textures.append(texture)
frame_index += 1
else:
break
else:
break
# 如果没有找到序列帧,尝试加载单个默认图片
if textures.size() == 0:
var single_texture_path = default_path + "0.png"
if ResourceLoader.exists(single_texture_path):
var texture = load(single_texture_path)
if texture:
textures.append(texture)
# 缓存默认图片
crop_textures_cache["默认"] = textures
crop_frame_counts["默认"] = textures.size()
print("商店加载了 ", textures.size(), " 个默认作物图片")
return textures
# 更新按钮的作物图片
func _update_button_crop_image(button: Button, crop_name: String):
"""
更新按钮中的作物图片
"""
# 检查按钮是否有CropImage节点
var crop_image = button.get_node_or_null("CropImage")
if not crop_image:
print("商店按钮没有找到CropImage节点", button.name)
return
# 获取作物的最后一帧图片
var texture = _get_crop_final_texture(crop_name)
if texture:
# CropImage是Sprite2D直接设置texture属性
crop_image.texture = texture
crop_image.visible = true
print("商店更新作物图片:", crop_name)
else:
crop_image.visible = false
print("商店无法获取作物图片:", crop_name)
# 兼容MainGame.gd中的调用转发到_on_store_buy_pressed
func _on_crop_selected(crop_name: String):
_on_store_buy_pressed(crop_name)

View File

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

126
GUI/land_panel.gd Normal file
View File

@@ -0,0 +1,126 @@
extends Panel
#获取玩家要操作的地块序号
var selected_lot_index = 0
#预添加常用的面板
@onready var main_game = get_node("/root/main")
@onready var land_panel = get_node("/root/main/UI/LandPanel")
@onready var crop_store_panel = get_node("/root/main/UI/PlayerBagPanel")
@onready var player_ranking_panel = get_node("/root/main/UI/PlayerRankingPanel")
@onready var player_bag_panel = get_node("/root/main/UI/PlayerBagPanel")
@onready var network_manager = get_node("/root/main/UI/TCPNetworkManager")
@onready var quit_button :Button = $Quit_Button
@onready var dig_button: Button = $Grid/Dig_Button
@onready var water_button: Button = $Grid/Water_Button
@onready var fertilize_button: Button = $Grid/Fertilize_Button
@onready var upgrade_button: Button = $Grid/Upgrade_Button
@onready var plant_button: Button = $Grid/Plant_Button
@onready var remove_button: Button = $Grid/Remove_Button
@onready var harvest_button: Button = $Grid/Harvest_Button
func _ready():
self.hide()
quit_button.pressed.connect(self._on_quit_button_pressed)
dig_button.pressed.connect(self._on_dig_button_pressed)
water_button.pressed.connect(self._on_water_button_pressed)
fertilize_button.pressed.connect(self._on_fertilize_button_pressed)
upgrade_button.pressed.connect(self._on_upgrade_button_pressed)
plant_button.pressed.connect(self._on_plant_button_pressed)
remove_button.pressed.connect(self._on_remove_button_pressed)
harvest_button.pressed.connect(self._on_harvest_button_pressed)
dig_button.text = "开垦"+"\n花费:"+str(main_game.dig_money)
#开垦
func _on_dig_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法开垦土地", Color.ORANGE, 2.0, 1.0)
self.hide()
return
dig_button.text = "开垦"+"\n花费:"+str(main_game.dig_money)
if network_manager and network_manager.is_connected_to_server():
# 使用服务器API来开垦土地
if network_manager.sendDigGround(selected_lot_index):
self.hide()
#浇水
func _on_water_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法浇水", Color.ORANGE, 2.0, 1.0)
self.hide()
return
self.hide()
pass
#施肥
func _on_fertilize_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法施肥", Color.ORANGE, 2.0, 1.0)
self.hide()
return
self.hide()
pass
#升级
func _on_upgrade_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法升级", Color.ORANGE, 2.0, 1.0)
self.hide()
return
self.hide()
pass
#种植
func _on_plant_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法种植", Color.ORANGE, 2.0, 1.0)
self.hide()
return
player_bag_panel.show()
self.hide()
pass
#铲除
func _on_remove_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法铲除作物", Color.ORANGE, 2.0, 1.0)
self.hide()
return
main_game.root_out_crop(selected_lot_index)
self.hide()
pass
#收获
func _on_harvest_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法收获作物", Color.ORANGE, 2.0, 1.0)
self.hide()
return
main_game._harvest_crop(selected_lot_index)
self.hide()
pass
#退出
func _on_quit_button_pressed():
self.hide()
pass

1
GUI/land_panel.gd.uid Normal file
View File

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

View File

@@ -1,87 +0,0 @@
extends Node
var http_request: HTTPRequest
var farm_lots = []
@onready var harvest = $harvest
@onready var label1 = $Label
@onready var username_input = $Panel/username_input
@onready var password_input = $Panel/password_input
@onready var login_button = $Panel/login_button
@onready var panel = $Panel
@onready var item_list = $item_list #ItemList
func _ready():
# 创建 HTTPRequest 节点
http_request = HTTPRequest.new()
add_child(http_request)
# 连接信号
http_request.connect("request_completed", Callable(self, "_on_request_completed"))
# 连接登录按钮点击事件
login_button.connect("pressed", Callable(self, "_on_login_button_pressed"))
# 登录按钮按下事件
func _on_login_button_pressed():
# 隐藏面板(只有在输入后才进行隐藏)
panel.hide()
# 获取用户名和密码输入
var username = username_input.text # 直接获取输入
var password = password_input.text # 直接获取输入
# 打印调试信息
print("Username entered: ", username)
print("Password entered: ", password)
# 检查用户名和密码是否为空
if username == "" or password == "":
print("用户名和密码不能为空")
panel.show() # 如果输入为空,显示面板
return
# 构建登录请求的 URL 和参数
var url = "https://api.shumengya.top/smyfarm/login.php"
var body = {
"username": username,
"password": password
}
# 发送 POST 请求进行登录
var err = http_request.request(url, [], HTTPClient.METHOD_POST, JSON.stringify(body))
if err != OK:
print("Error making HTTP POST request: ", err)
# 请求完成后的回调函数
func _on_request_completed(result, response_code, headers, body):
if response_code == 200:
var json = JSON.new()
var parse_result = json.parse(body.get_string_from_utf8())
if parse_result != OK:
print("Error parsing JSON: ", json.get_error_message())
return
var json_data = json.data
if json_data.has("error"):
print("Error: " + str(json_data["error"]))
panel.show() # 如果登录失败,显示面板,允许重新输入
elif json_data.has("message"):
print(json_data["message"])
# 处理登录成功
if json_data.has("data"):
var player_data = json_data["data"]
print("欢迎, " + player_data["username"])
# 加载玩家数据,进入游戏逻辑
_load_player_data(player_data)
else:
print("HTTP Request failed with response code: " + str(response_code))
panel.show() # 请求失败,重新显示面板
# 加载玩家数据
func _load_player_data(player_data):
# 根据返回的 player_data 初始化玩家的农场状态等
pass

433
GUI/login_panel.gd Normal file
View File

@@ -0,0 +1,433 @@
#玩家登录注册面板
extends PanelContainer
#玩家登录账号用QQ号代替
@onready var username_input : LineEdit = $VBox/UserName/username_input
#用户登录密码
@onready var password_input : LineEdit = $VBox/Password1/password_input
#登录按钮
@onready var login_button : Button = $VBox/LoginRegister/login_button
#下面是注册相关的
#注册按钮
@onready var register_button : Button = $VBox/LoginRegister/register_button
#注册账号时二次确认密码
@onready var password_input_2 : LineEdit = $VBox/Password2/password_input2
#农场名称
@onready var farmname_input : LineEdit = $VBox/FarmName/farmname_input
#玩家昵称
@onready var playername_input :LineEdit = $VBox/PlayerName/playername_input
#邮箱验证码
@onready var verificationcode_input :LineEdit = $VBox/VerificationCode/verificationcode_input
#发送验证码按钮
@onready var send_button :Button = $VBox/VerificationCode/SendButton
#状态提示标签
@onready var status_label : Label = $VBox/status_label
# 记住密码选项如果UI中有CheckBox的话
var remember_password : bool = true # 默认记住密码
# 引用主场景和全局函数
@onready var main_game = get_node("/root/main")
@onready var land_panel = get_node("/root/main/UI/LandPanel")
@onready var crop_store_panel = get_node("/root/main/UI/PlayerBagPanel")
@onready var player_ranking_panel = get_node("/root/main/UI/PlayerRankingPanel")
@onready var player_bag_panel = get_node("/root/main/UI/PlayerBagPanel")
@onready var tcp_network_manager = get_node("/root/main/UI/TCPNetworkManager")
# 准备函数
func _ready():
# 连接按钮信号
login_button.pressed.connect(self._on_login_button_pressed)
register_button.pressed.connect(self._on_register_button_pressed)
send_button.pressed.connect(self._on_send_button_pressed)
# 加载保存的登录信息
_load_login_info()
# 处理登录按钮点击
func _on_login_button_pressed():
var user_name = username_input.text.strip_edges() # 修剪前后的空格
var user_password = password_input.text.strip_edges()
var farmname = farmname_input.text.strip_edges()
if user_name == "" or user_password == "":
status_label.text = "用户名或密码不能为空!"
status_label.modulate = Color.RED
return
# 检查网络连接状态
if !tcp_network_manager.client.is_client_connected():
status_label.text = "未连接到服务器,正在尝试连接..."
status_label.modulate = Color.YELLOW
# 尝试自动连接到服务器
tcp_network_manager._on_connection_button_pressed()
await get_tree().create_timer(1.0).timeout
# 再次检查连接状态
if !tcp_network_manager.client.is_client_connected():
status_label.text = "连接服务器失败,请检查网络设置!"
status_label.modulate = Color.RED
return
# 禁用按钮,防止重复点击
login_button.disabled = true
status_label.text = "正在登录,请稍候..."
status_label.modulate = Color.YELLOW
# 如果启用了记住密码,保存登录信息
if remember_password:
_save_login_info(user_name, user_password)
tcp_network_manager.sendLoginInfo(user_name, user_password)
# 更新主游戏数据
main_game.user_name = user_name
main_game.user_password = user_password
main_game.farmname = farmname
# 5秒后重新启用按钮如果没有收到响应
await get_tree().create_timer(5.0).timeout
if login_button.disabled:
login_button.disabled = false
status_label.text = "登录超时,请重试!"
status_label.modulate = Color.RED
# 处理验证码发送按钮点击
func _on_send_button_pressed():
var user_name = username_input.text.strip_edges()
if user_name == "":
status_label.text = "请输入QQ号以接收验证码"
status_label.modulate = Color.RED
return
if !is_valid_qq_number(user_name):
status_label.text = "请输入正确的QQ号码5-12位数字"
status_label.modulate = Color.RED
return
# 检查网络连接状态
if !tcp_network_manager.client.is_client_connected():
status_label.text = "未连接到服务器,正在尝试连接..."
status_label.modulate = Color.YELLOW
# 尝试自动连接到服务器
tcp_network_manager._on_connection_button_pressed()
await get_tree().create_timer(1.0).timeout
# 再次检查连接状态
if !tcp_network_manager.client.is_client_connected():
status_label.text = "连接服务器失败,请检查网络设置!"
status_label.modulate = Color.RED
return
# 禁用按钮,防止重复点击
send_button.disabled = true
status_label.text = "正在发送验证码,请稍候..."
status_label.modulate = Color.YELLOW
# 发送验证码请求
tcp_network_manager.sendVerificationCodeRequest(user_name)
# 60秒后重新启用按钮或收到响应后提前启用
var timer = 60
while timer > 0 and send_button.disabled:
send_button.text = "重新发送(%d)" % timer
await get_tree().create_timer(1.0).timeout
timer -= 1
if send_button.disabled:
send_button.disabled = false
send_button.text = "发送验证码"
if status_label.text == "正在发送验证码,请稍候...":
status_label.text = "验证码发送超时,请重试!"
status_label.modulate = Color.RED
# 处理注册按钮点击
func _on_register_button_pressed():
var user_name = username_input.text.strip_edges()
var user_password = password_input.text.strip_edges()
var user_password_2 = password_input_2.text.strip_edges()
var farmname = farmname_input.text.strip_edges()
var player_name = playername_input.text.strip_edges()
var verification_code = verificationcode_input.text.strip_edges()
if user_name == "" or user_password == "":
status_label.text = "用户名或密码不能为空!"
status_label.modulate = Color.RED
return
if farmname == "":
status_label.text = "农场名称不能为空!"
status_label.modulate = Color.RED
return
if user_password != user_password_2:
status_label.text = "两次输入的密码不一致!"
status_label.modulate = Color.RED
return
if !is_valid_qq_number(user_name):
status_label.text = "请输入正确的QQ号码5-12位数字"
status_label.modulate = Color.RED
return
if verification_code == "":
status_label.text = "请输入验证码!"
status_label.modulate = Color.RED
return
# 检查网络连接状态
if !tcp_network_manager.client.is_client_connected():
status_label.text = "未连接到服务器,正在尝试连接..."
status_label.modulate = Color.YELLOW
# 尝试自动连接到服务器
tcp_network_manager._on_connection_button_pressed()
await get_tree().create_timer(1.0).timeout
# 再次检查连接状态
if !tcp_network_manager.client.is_client_connected():
status_label.text = "连接服务器失败,请检查网络设置!"
status_label.modulate = Color.RED
return
# 禁用按钮,防止重复点击
register_button.disabled = true
status_label.text = "正在注册,请稍候..."
status_label.modulate = Color.YELLOW
# 发送注册请求
tcp_network_manager.sendRegisterInfo(user_name, user_password, farmname, player_name, verification_code)
# 更新主游戏数据
main_game.user_name = user_name
main_game.user_password = user_password
main_game.farmname = farmname
# 5秒后重新启用按钮如果没有收到响应
await get_tree().create_timer(5.0).timeout
if register_button.disabled:
register_button.disabled = false
status_label.text = "注册超时,请重试!"
status_label.modulate = Color.RED
# 处理验证码发送响应
func _on_verification_code_response(success: bool, message: String):
if success:
status_label.text = message
status_label.modulate = Color.GREEN
else:
status_label.text = message
status_label.modulate = Color.RED
send_button.disabled = false
send_button.text = "发送验证码"
# 处理验证码验证响应
func _on_verify_code_response(success: bool, message: String):
if success:
status_label.text = message
status_label.modulate = Color.GREEN
else:
status_label.text = message
status_label.modulate = Color.RED
# 验证QQ号是否有效
func is_valid_qq_number(qq_number: String) -> bool:
# QQ号的标准格式是5到12位的数字
var qq_regex = RegEx.new()
var pattern = r"^\d{5,12}$"
var error = qq_regex.compile(pattern)
if error != OK:
status_label.text = "QQ号验证失败部错误"
status_label.modulate = Color.RED
return false
return qq_regex.search(qq_number) != null
# 处理登录响应
func _on_login_response_received(success: bool, message: String, user_data: Dictionary):
# 启用按钮
login_button.disabled = false
if success:
status_label.text = "登录成功!正在加载游戏..."
status_label.modulate = Color.GREEN
# 更新主游戏数据
main_game.experience = user_data.get("experience", 0)
main_game.farm_lots = user_data.get("farm_lots", [])
main_game.level = user_data.get("level", 1)
main_game.money = user_data.get("money", 0)
main_game.farmname = user_data.get("farm_name", "")
farmname_input.text = user_data.get("farm_name", "")
# 加载玩家背包数据
if user_data.has("player_bag"):
main_game.player_bag = user_data.get("player_bag", [])
else:
main_game.player_bag = []
main_game.start_game = true
self.hide()
# 确保在更新数据后调用主游戏的 UI 更新函数
main_game._update_ui()
main_game._refresh_farm_lots()
player_bag_panel.update_player_bag_ui()
else:
status_label.text = "登录失败:" + message
status_label.modulate = Color.RED
# 如果登录失败且是密码错误,可以选择清除保存的信息
if "密码" in message or "password" in message.to_lower():
print("登录失败可能是密码错误。如需清除保存的登录信息请调用_clear_login_info()")
# 处理注册响应
func _on_register_response_received(success: bool, message: String):
# 启用按钮
register_button.disabled = false
if success:
status_label.text = "注册成功!请登录游戏"
status_label.modulate = Color.GREEN
# 注册成功后,如果启用了记住密码,保存登录信息
if remember_password:
var user_name = username_input.text.strip_edges()
var user_password = password_input.text.strip_edges()
_save_login_info(user_name, user_password)
# 清除注册相关的输入框
password_input_2.text = ""
verificationcode_input.text = ""
else:
status_label.text = "注册失败:" + message
status_label.modulate = Color.RED
# 保存登录信息到JSON文件
func _save_login_info(user_name: String, password: String):
var login_data = {
"user_name": user_name,
"password": password
}
var file = FileAccess.open("user://login.json", FileAccess.WRITE)
if file:
var json_string = JSON.stringify(login_data, "\t")
file.store_string(json_string)
file.close()
print("登录信息已保存")
else:
print("无法保存登录信息")
# 从JSON文件加载登录信息
func _load_login_info():
var file = FileAccess.open("user://login.json", FileAccess.READ)
if file:
var json_text = file.get_as_text()
file.close()
var json = JSON.new()
var parse_result = json.parse(json_text)
if parse_result == OK:
var login_data = json.get_data()
if login_data.has("user_name") and login_data.has("password"):
var saved_username = login_data.get("user_name", "")
var saved_password = login_data.get("password", "")
if saved_username != "" and saved_password != "":
username_input.text = saved_username
password_input.text = saved_password
status_label.text = "已加载保存的登录信息"
status_label.modulate = Color.CYAN
print("登录信息已加载:用户名 =", saved_username)
else:
status_label.text = "欢迎使用萌芽农场"
status_label.modulate = Color.WHITE
print("没有有效的保存登录信息")
else:
print("登录信息格式错误")
else:
print("登录信息JSON解析错误", json.get_error_message())
else:
# 创建默认的登录信息文件
_save_login_info("", "")
status_label.text = "欢迎使用萌芽农场"
status_label.modulate = Color.WHITE
print("没有找到保存的登录信息,已创建默认文件")
# 清除保存的登录信息
func _clear_login_info():
var file = FileAccess.open("user://login.json", FileAccess.WRITE)
if file:
var empty_data = {
"user_name": "",
"password": ""
}
var json_string = JSON.stringify(empty_data, "\t")
file.store_string(json_string)
file.close()
print("登录信息已清除")
else:
print("无法清除登录信息")
# 切换记住密码选项
func toggle_remember_password():
remember_password = !remember_password
print("记住密码选项:", "开启" if remember_password else "关闭")
# 如果关闭了记住密码,清除已保存的信息
if not remember_password:
_clear_login_info()
# 检查是否有保存的登录信息
func has_saved_login_info() -> bool:
var file = FileAccess.open("user://login.json", FileAccess.READ)
if file:
var json_text = file.get_as_text()
file.close()
var json = JSON.new()
var parse_result = json.parse(json_text)
if parse_result == OK:
var login_data = json.get_data()
var user_name = login_data.get("user_name", "")
var password = login_data.get("password", "")
return user_name != "" and password != ""
return false
# 快捷登录(使用保存的登录信息)
func quick_login():
if has_saved_login_info():
var user_name = username_input.text.strip_edges()
var user_password = password_input.text.strip_edges()
if user_name != "" and user_password != "":
print("执行快捷登录...")
_on_login_button_pressed()
else:
status_label.text = "保存的登录信息不完整"
status_label.modulate = Color.ORANGE
else:
status_label.text = "没有保存的登录信息"
status_label.modulate = Color.ORANGE
# 获取保存的用户名(用于调试或显示)
func get_saved_username() -> String:
var file = FileAccess.open("user://login.json", FileAccess.READ)
if file:
var json_text = file.get_as_text()
file.close()
var json = JSON.new()
var parse_result = json.parse(json_text)
if parse_result == OK:
var login_data = json.get_data()
return login_data.get("user_name", "")
return ""

1
GUI/login_panel.gd.uid Normal file
View File

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

479
GUI/player_bag_panel.gd Normal file
View File

@@ -0,0 +1,479 @@
extends Panel
# 背包格子容器
@onready var player_bag_grid_container : GridContainer = $ScrollContainer/Bag_Grid
@onready var quit_button : Button = $QuitButton
#各种排序过滤按钮
@onready var sort_all_button : Button = $SortContainer/Sort_All#全部
@onready var sort_common_button : Button = $SortContainer/Sort_Common#普通
@onready var sort_superior_button : Button = $SortContainer/Sort_Superior#优良
@onready var sort_rare_button : Button = $SortContainer/Sort_Rare#稀有
@onready var sort_epic_button : Button = $SortContainer/Sort_Epic#史诗
@onready var sort_legendary_button : Button = $SortContainer/Sort_Legendary#传奇
@onready var sort_price_button : Button = $SortContainer/Sort_Price#价格
@onready var sort_growtime_button : Button = $SortContainer/Sort_GrowTime#生长时间
@onready var sort_profit_button : Button = $SortContainer/Sort_Profit#收益
@onready var sort_level_button : Button = $SortContainer/Sort_Level#等级
#预添加常用的面板
@onready var main_game = get_node("/root/main")
@onready var land_panel = get_node("/root/main/UI/LandPanel")
@onready var crop_store_panel = get_node("/root/main/UI/PlayerBagPanel")
@onready var player_ranking_panel = get_node("/root/main/UI/PlayerRankingPanel")
@onready var player_bag_panel = get_node("/root/main/UI/PlayerBagPanel")
@onready var network_manager = get_node("/root/main/UI/TCPNetworkManager")
# 作物图片缓存(复用主游戏的缓存系统)
var crop_textures_cache : Dictionary = {}
var crop_frame_counts : Dictionary = {}
# 当前选择的地块索引从MainGame获取
var selected_lot_index : int = -1
# 当前过滤和排序设置
var current_filter_quality = ""
var current_sort_key = ""
var current_sort_ascending = true
# 准备函数
func _ready():
# 连接按钮信号
_connect_buttons()
# 隐藏面板(初始默认隐藏)
self.hide()
# 连接所有按钮信号
func _connect_buttons():
# 关闭按钮
quit_button.pressed.connect(self._on_quit_button_pressed)
# 过滤按钮
sort_all_button.pressed.connect(func(): _filter_by_quality(""))
sort_common_button.pressed.connect(func(): _filter_by_quality("普通"))
sort_superior_button.pressed.connect(func(): _filter_by_quality("优良"))
sort_rare_button.pressed.connect(func(): _filter_by_quality("稀有"))
sort_epic_button.pressed.connect(func(): _filter_by_quality("史诗"))
sort_legendary_button.pressed.connect(func(): _filter_by_quality("传奇"))
# 排序按钮
sort_price_button.pressed.connect(func(): _sort_by("花费"))
sort_growtime_button.pressed.connect(func(): _sort_by("生长时间"))
sort_profit_button.pressed.connect(func(): _sort_by("收益"))
sort_level_button.pressed.connect(func(): _sort_by("等级"))
# 初始化玩家背包
func init_player_bag():
# 清空玩家背包格子
for child in player_bag_grid_container.get_children():
child.queue_free()
# 显示背包中的种子
update_player_bag_ui()
# 更新玩家背包UI
func update_player_bag_ui():
# 清空玩家背包格子
for child in player_bag_grid_container.get_children():
child.queue_free()
#print("更新背包UI背包中物品数量", main_game.player_bag.size())
# 应用过滤和排序
var filtered_seeds = _get_filtered_and_sorted_seeds()
# 为背包中的每个过滤后的种子创建按钮
for seed_item in filtered_seeds:
var crop_name = seed_item["name"]
var crop_quality = seed_item["quality"]
var crop_count = seed_item["count"]
#print("背包物品:", crop_name, " 数量:", crop_count)
# 创建种子按钮
var button = _create_crop_button(crop_name, crop_quality)
# 更新按钮文本显示数量
button.text = str(crop_quality + "-" + crop_name + "\n数量:" + str(crop_count))
# 根据是否处于访问模式连接不同的事件
if main_game.is_visiting_mode:
# 访问模式下,点击种子只显示信息,不能种植
button.pressed.connect(func(): _on_visit_seed_selected(crop_name, crop_count))
else:
# 正常模式下,连接种植事件
button.pressed.connect(func(): _on_bag_seed_selected(crop_name))
player_bag_grid_container.add_child(button)
# 获取过滤和排序后的种子列表
func _get_filtered_and_sorted_seeds():
var filtered_seeds = []
# 收集符合条件的种子
for seed_item in main_game.player_bag:
# 品质过滤
if current_filter_quality != "" and seed_item["quality"] != current_filter_quality:
continue
# 获取种子对应的作物数据
var crop_data = null
if main_game.can_planted_crop.has(seed_item["name"]):
crop_data = main_game.can_planted_crop[seed_item["name"]]
# 添加到过滤后的列表
filtered_seeds.append({
"name": seed_item["name"],
"quality": seed_item["quality"],
"count": seed_item["count"],
"data": crop_data
})
# 如果有排序条件且数据可用,进行排序
if current_sort_key != "":
filtered_seeds.sort_custom(Callable(self, "_sort_seed_items"))
return filtered_seeds
# 自定义排序函数
func _sort_seed_items(a, b):
# 检查是否有有效数据用于排序
if a["data"] == null or b["data"] == null:
# 如果某一项没有数据,将其排在后面
if a["data"] == null and b["data"] != null:
return false
if a["data"] != null and b["data"] == null:
return true
# 如果都没有数据,按名称排序
return a["name"] < b["name"]
# 确保排序键存在于数据中
if !a["data"].has(current_sort_key) or !b["data"].has(current_sort_key):
print("警告: 排序键 ", current_sort_key, " 在某些种子数据中不存在")
return false
# 执行排序
if current_sort_ascending:
return a["data"][current_sort_key] < b["data"][current_sort_key]
else:
return a["data"][current_sort_key] > b["data"][current_sort_key]
# 按品质过滤种子
func _filter_by_quality(quality: String):
current_filter_quality = quality
print("过滤种子,品质: " + (quality if quality != "" else "全部"))
update_player_bag_ui()
# 按指定键排序
func _sort_by(sort_key: String):
# 切换排序方向或设置新排序键
if current_sort_key == sort_key:
current_sort_ascending = !current_sort_ascending
else:
current_sort_key = sort_key
current_sort_ascending = true
print("排序种子,键: " + sort_key + ",升序: " + str(current_sort_ascending))
update_player_bag_ui()
# 创建作物按钮
func _create_crop_button(crop_name: String, crop_quality: String) -> Button:
# 根据品质选择相应的进度条
var button = null
#普通 Color.HONEYDEW#白色
#优良 Color.DODGER_BLUE#深蓝色
#稀有 Color.HOT_PINK#品红色
#史诗 Color.YELLOW#黄色
#传奇 Color.ORANGE_RED#红色
#空地 Color.GREEN#绿色
#未开垦 Color.WEB_GRAY#深褐色
match crop_quality:
"普通":
button = main_game.green_bar.duplicate()
"优良":
button = main_game.orange_bar.duplicate()
"稀有":
button = main_game.white_blue_bar.duplicate()
"史诗":
button = main_game.pink_bar.duplicate()
"传奇":
button = main_game.black_blue_bar.duplicate()
_: # 默认情况
button = main_game.green_bar.duplicate()
# 确保按钮可见并可点击
button.visible = true
button.disabled = false
button.focus_mode = Control.FOCUS_ALL
# 设置按钮文本
button.text = str(crop_quality + "-" + crop_name)
# 添加工具提示 (tooltip)
if main_game.can_planted_crop.has(crop_name):
var crop = main_game.can_planted_crop[crop_name]
# 将成熟时间从秒转换为天时分秒格式
var total_seconds = int(crop["生长时间"])
# 定义时间单位换算
var SECONDS_PER_MINUTE = 60
var SECONDS_PER_HOUR = 3600
var SECONDS_PER_DAY = 86400
# 计算各时间单位
var days = total_seconds / SECONDS_PER_DAY
total_seconds %= SECONDS_PER_DAY
var hours = total_seconds / SECONDS_PER_HOUR
total_seconds %= SECONDS_PER_HOUR
var minutes = total_seconds / SECONDS_PER_MINUTE
var seconds = total_seconds % SECONDS_PER_MINUTE
# 构建时间字符串(只显示有值的单位)
var time_str = ""
if days > 0:
time_str += str(days) + ""
if hours > 0:
time_str += str(hours) + "小时"
if minutes > 0:
time_str += str(minutes) + "分钟"
if seconds > 0:
time_str += str(seconds) + ""
button.tooltip_text = str(
"作物: " + crop_name + "\n" +
"品质: " + crop_quality + "\n" +
"价格: " + str(crop["花费"]) + "\n" +
"成熟时间: " + time_str + "\n" +
"收获收益: " + str(crop["收益"]) + "\n" +
"需求等级: " + str(crop["等级"]) + "\n" +
"耐候性: " + str(crop["耐候性"]) + "\n" +
"经验: " + str(crop["经验"]) + "\n" +
"描述: " + str(crop["描述"])
)
# 如果按钮有标题标签,设置标题
if button.has_node("Title"):
button.get_node("Title").text = crop_quality
match crop_quality:
"普通":
button.get_node("Title").modulate = Color.HONEYDEW#白色
"优良":
button.get_node("Title").modulate =Color.DODGER_BLUE#深蓝色
"稀有":
button.get_node("Title").modulate =Color.HOT_PINK#品红色
"史诗":
button.get_node("Title").modulate =Color.YELLOW#黄色
"传奇":
button.get_node("Title").modulate =Color.ORANGE_RED#红色
# 更新按钮的作物图片
_update_button_crop_image(button, crop_name)
return button
# 从背包中选择种子并种植
func _on_bag_seed_selected(crop_name):
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法种植", Color.ORANGE, 2.0, 1.0)
return
# 从主场景获取当前选择的地块索引
selected_lot_index = main_game.selected_lot_index
if selected_lot_index != -1:
# 检查背包中是否有这个种子
var seed_index = -1
for i in range(len(main_game.player_bag)):
if main_game.player_bag[i]["name"] == crop_name:
seed_index = i
break
#print("选择种子:", crop_name, ",背包索引:", seed_index)
if seed_index != -1 and main_game.player_bag[seed_index]["count"] > 0:
# 种植种子并从背包中减少数量
_plant_crop_from_bag(selected_lot_index, crop_name, seed_index)
main_game.selected_lot_index = -1
self.hide()
# 访问模式下的种子点击处理
func _on_visit_seed_selected(crop_name, crop_count):
# 显示种子信息
var info_text = ""
if main_game.can_planted_crop.has(crop_name):
var crop = main_game.can_planted_crop[crop_name]
var quality = crop.get("品质", "未知")
var price = crop.get("花费", 0)
var grow_time = crop.get("生长时间", 0)
var profit = crop.get("收益", 0)
var level_req = crop.get("等级", 1)
# 将成熟时间转换为可读格式
var time_str = ""
var total_seconds = int(grow_time)
var hours = total_seconds / 3600
var minutes = (total_seconds % 3600) / 60
var seconds = total_seconds % 60
if hours > 0:
time_str += str(hours) + "小时"
if minutes > 0:
time_str += str(minutes) + "分钟"
if seconds > 0:
time_str += str(seconds) + ""
info_text = quality + "-" + crop_name + " (数量: " + str(crop_count) + ")\n"
info_text += "价格: " + str(price) + "元, 收益: " + str(profit) + "\n"
info_text += "成熟时间: " + time_str + ", 需求等级: " + str(level_req)
else:
info_text = crop_name + " (数量: " + str(crop_count) + ")"
Toast.show(info_text, Color.CYAN, 3.0, 1.0)
print("查看种子信息: ", info_text)
# 从背包种植作物
func _plant_crop_from_bag(index, crop_name, seed_index):
var crop = main_game.can_planted_crop[crop_name]
# 检查是否有效的种子索引,防止越界访问
if seed_index < 0 or seed_index >= main_game.player_bag.size():
#print("错误:无效的种子索引 ", seed_index)
return
# 发送种植请求到服务器
if network_manager and network_manager.sendPlantCrop(index, crop_name):
# 种植请求已发送,等待服务器响应
Toast.show("正在发送种植请求", Color.YELLOW, 2.0, 1.0)
# 关闭背包面板
hide()
# 关闭面板
func _on_quit_button_pressed():
self.hide()
# 获取作物的最后一帧图片(用于背包显示)
func _get_crop_final_texture(crop_name: String) -> Texture2D:
"""
获取作物的最后一帧图片,用于背包显示
如果作物图片不存在,使用默认图片的最后一帧
"""
# 先尝试从主游戏的缓存中获取
if main_game and main_game.crop_textures_cache.has(crop_name):
var textures = main_game.crop_textures_cache[crop_name]
if textures.size() > 0:
return textures[textures.size() - 1] # 返回最后一帧
# 如果主游戏缓存中没有,自己加载
var textures = _load_crop_textures(crop_name)
if textures.size() > 0:
return textures[textures.size() - 1] # 返回最后一帧
return null
# 加载作物图片序列帧(复用主游戏的逻辑)
func _load_crop_textures(crop_name: String) -> Array:
"""
加载指定作物的所有序列帧图片
"""
if crop_textures_cache.has(crop_name):
return crop_textures_cache[crop_name]
var textures = []
var crop_path = "res://assets/作物/" + crop_name + "/"
var default_path = "res://assets/作物/默认/"
# 检查作物文件夹是否存在
if DirAccess.dir_exists_absolute(crop_path):
# 尝试加载作物的序列帧从0开始
var frame_index = 0
while true:
var texture_path = crop_path + str(frame_index) + ".png"
if ResourceLoader.exists(texture_path):
var texture = load(texture_path)
if texture:
textures.append(texture)
frame_index += 1
else:
break
else:
break
if textures.size() > 0:
print("背包加载作物 ", crop_name, "", textures.size(), " 帧图片")
else:
print("背包:作物 ", crop_name, " 文件夹存在但没有找到有效图片,使用默认图片")
textures = _load_default_textures()
else:
print("背包:作物 ", crop_name, " 的文件夹不存在,使用默认图片")
textures = _load_default_textures()
# 缓存结果
crop_textures_cache[crop_name] = textures
crop_frame_counts[crop_name] = textures.size()
return textures
# 加载默认图片
func _load_default_textures() -> Array:
"""
加载默认作物图片
"""
if crop_textures_cache.has("默认"):
return crop_textures_cache["默认"]
var textures = []
var default_path = "res://assets/作物/默认/"
# 尝试加载默认图片序列帧
var frame_index = 0
while true:
var texture_path = default_path + str(frame_index) + ".png"
if ResourceLoader.exists(texture_path):
var texture = load(texture_path)
if texture:
textures.append(texture)
frame_index += 1
else:
break
else:
break
# 如果没有找到序列帧,尝试加载单个默认图片
if textures.size() == 0:
var single_texture_path = default_path + "0.png"
if ResourceLoader.exists(single_texture_path):
var texture = load(single_texture_path)
if texture:
textures.append(texture)
# 缓存默认图片
crop_textures_cache["默认"] = textures
crop_frame_counts["默认"] = textures.size()
print("背包加载了 ", textures.size(), " 个默认作物图片")
return textures
# 更新按钮的作物图片
func _update_button_crop_image(button: Button, crop_name: String):
"""
更新按钮中的作物图片
"""
# 检查按钮是否有CropImage节点
var crop_image = button.get_node_or_null("CropImage")
if not crop_image:
print("背包按钮没有找到CropImage节点", button.name)
return
# 获取作物的最后一帧图片
var texture = _get_crop_final_texture(crop_name)
if texture:
# CropImage是Sprite2D直接设置texture属性
crop_image.texture = texture
crop_image.visible = true
print("背包更新作物图片:", crop_name)
else:
crop_image.visible = false
print("背包无法获取作物图片:", crop_name)

View File

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

View File

@@ -0,0 +1,71 @@
[gd_scene load_steps=3 format=3 uid="uid://crd28qnymob7"]
[ext_resource type="Texture2D" uid="uid://c3vng0nal1wr8" path="res://assets/Test/g.png" id="1_sgoxp"]
[ext_resource type="Script" uid="uid://0d2j5m6j2ema" path="res://Components/HTTPTextureRect.gd" id="2_ky0k8"]
[node name="player_ranking_item" type="VBoxContainer"]
offset_right = 1152.0
offset_bottom = 82.0
[node name="HBox" type="HBoxContainer" parent="."]
layout_mode = 2
[node name="SerialNumber" type="Label" parent="HBox"]
layout_mode = 2
theme_override_font_sizes/font_size = 30
text = "1."
[node name="PlayerAvatar" type="TextureRect" parent="HBox"]
layout_mode = 2
texture = ExtResource("1_sgoxp")
expand_mode = 3
script = ExtResource("2_ky0k8")
metadata/_custom_type_script = "uid://0d2j5m6j2ema"
[node name="PlayerName" type="Label" parent="HBox"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
text = "树萌芽"
[node name="PlayerMoney" type="Label" parent="HBox"]
modulate = Color(1, 1, 0, 1)
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
text = "钱币999"
[node name="SeedNum" type="Label" parent="HBox"]
modulate = Color(0, 1, 0, 1)
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
text = "种子数999"
[node name="PlayerLevel" type="Label" parent="HBox"]
modulate = Color(0, 1, 1, 1)
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
text = "等级999"
[node name="VisitButton" type="Button" parent="HBox"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 30
text = "访问"
[node name="HBox2" type="HBoxContainer" parent="."]
layout_mode = 2
[node name="LastLoginTime" type="Label" parent="HBox2"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 20
text = "最后在线2025年12时09分35秒"
[node name="OnlineTime" type="Label" parent="HBox2"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_font_sizes/font_size = 20
text = "累计在线时长99时60分60秒"

110
GUI/player_ranking_panel.gd Normal file
View File

@@ -0,0 +1,110 @@
extends Panel
@onready var player_ranking_list : VBoxContainer = $Scroll/PlayerList
@onready var refresh_button : Button = $RefreshButton
@onready var quit_button : Button = $QuitButton
#预添加常用的面板
@onready var main_game = get_node("/root/main")
@onready var land_panel = get_node("/root/main/UI/LandPanel")
@onready var crop_store_panel = get_node("/root/main/UI/PlayerBagPanel")
@onready var player_ranking_panel = get_node("/root/main/UI/PlayerRankingPanel")
@onready var player_bag_panel = get_node("/root/main/UI/PlayerBagPanel")
@onready var network_manager = get_node("/root/main/UI/TCPNetworkManager")
#下面这是每个玩家要展示的信息直接获取服务器玩家数据json文件来实现
#模板用于复制创建新的玩家条目
@onready var player_info_template : VBoxContainer = $Scroll/PlayerList/player_ranking_item
func _ready() -> void:
# 隐藏模板
player_info_template.visible = false
# 连接按钮信号
refresh_button.pressed.connect(_on_refresh_button_pressed)
quit_button.pressed.connect(_on_quit_button_pressed)
# 初始加载排行榜
request_player_rankings()
# 请求玩家排行榜数据
func request_player_rankings():
if network_manager:
network_manager.sendGetPlayerRankings()
# 处理玩家排行榜响应
func handle_player_rankings_response(data):
# 检查响应是否成功
if not data.get("success", false):
print("获取玩家排行榜失败:", data.get("message", "未知错误"))
return
# 清除现有的玩家条目(除了模板)
for child in player_ranking_list.get_children():
if child != player_info_template:
child.queue_free()
# 添加玩家条目
var players = data.get("players", [])
for player_data in players:
add_player_entry(player_data)
# 添加单个玩家条目
func add_player_entry(player_data):
# 复制模板
var player_entry = player_info_template.duplicate()
player_entry.visible = true
player_ranking_list.add_child(player_entry)
# 设置玩家信息
var player_name = player_entry.get_node("HBox/PlayerName")
var player_level = player_entry.get_node("HBox/PlayerLevel")
var player_money = player_entry.get_node("HBox/PlayerMoney")
var player_seed_num = player_entry.get_node("HBox/SeedNum")
var player_online_time = player_entry.get_node("HBox2/OnlineTime")
var player_last_login_time = player_entry.get_node("HBox2/LastLoginTime")
var player_avatar = player_entry.get_node("HBox/PlayerAvatar")
var visit_button = player_entry.get_node("HBox/VisitButton")
# 填充数据
var username = player_data.get("user_name", "未知")
var display_name = player_data.get("player_name", username)
player_name.text = display_name
player_level.text = "等级: " + str(player_data.get("level", 0))
player_money.text = "金币: " + str(player_data.get("money", 0))
player_seed_num.text = "种子: " + str(player_data.get("seed_count", 0))
player_online_time.text = "游玩时间: " + player_data.get("total_login_time", "0时0分0秒")
player_last_login_time.text = "最后登录: " + player_data.get("last_login_time", "未知")
# 尝试加载玩家头像(使用用户名/QQ号加载头像而不是显示名
if username.is_valid_int():
player_avatar.load_from_url("http://q1.qlogo.cn/g?b=qq&nk=" + username + "&s=100")
# 设置访问按钮
visit_button.pressed.connect(func(): _on_visit_player_pressed(username))
# 访问玩家按钮点击
func _on_visit_player_pressed(username):
print("访问玩家:", username)
# 发送访问玩家请求
if network_manager and network_manager.has_method("sendVisitPlayer"):
var success = network_manager.sendVisitPlayer(username)
if success:
print("已发送访问玩家请求:", username)
else:
print("发送访问玩家请求失败,网络未连接")
else:
print("网络管理器不可用")
# 刷新按钮点击
func _on_refresh_button_pressed():
request_player_rankings()
# 退出按钮点击
func _on_quit_button_pressed():
self.hide()
# 添加到main.gd中调用
func _handle_player_rankings_response(data):
handle_player_rankings_response(data)

View File

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