diff --git a/excel/cha.xlsx b/excel/cha.xlsx index 5f61c45..aa490c1 100644 Binary files a/excel/cha.xlsx and b/excel/cha.xlsx differ diff --git a/excel/enemy.xlsx b/excel/enemy.xlsx index 6332a8c..32f8ea2 100644 Binary files a/excel/enemy.xlsx and b/excel/enemy.xlsx differ diff --git a/excel/equipment.xlsx b/excel/equipment.xlsx index 8488c3a..4b91c8e 100644 Binary files a/excel/equipment.xlsx and b/excel/equipment.xlsx differ diff --git a/excel/level.xlsx b/excel/level.xlsx index ab519cb..e9f07bc 100644 Binary files a/excel/level.xlsx and b/excel/level.xlsx differ diff --git a/src/ReplicatedStorage/Base/UIList.luau b/src/ReplicatedStorage/Base/UIList.luau index d0d2719..bac759e 100644 --- a/src/ReplicatedStorage/Base/UIList.luau +++ b/src/ReplicatedStorage/Base/UIList.luau @@ -41,6 +41,7 @@ function UIList:Init(Prefab: Instance) self.Instances = {} self.Connections = {} self.LayoutOrderKey = nil + self.reverse = false self.Component = nil self.UIRoot = Prefab self.Org = Utils:FindInDescendantsUI(Prefab, "__org") @@ -89,10 +90,23 @@ function UIList:RemoveData(key) end end -function UIList:SetLayoutOrder(keyName: string) - self.LayoutOrderKey = keyName +function UIList:FindSameDataInstance(data) for _, ui in pairs(self.Instances) do - ui.UIRoot.LayoutOrder = tonumber(ui.Data[keyName]) + if ui.Data == data then + return ui + end + end +end + +function UIList:SetLayoutOrder(keyName: string, reverse: boolean?) + self.LayoutOrderKey = keyName + if reverse then self.reverse = true else self.reverse = false end + for _, ui in pairs(self.Instances) do + if self.reverse then + ui.UIRoot.LayoutOrder = 1000 - tonumber(ui.Data[keyName]) + else + ui.UIRoot.LayoutOrder = tonumber(ui.Data[keyName]) + end end end @@ -106,7 +120,11 @@ function UIList:SetSingleInstance(index: number, data: table) uiInstance.Name = index uiInstance.Parent = self.Org.Parent if self.LayoutOrderKey then - uiInstance.LayoutOrder = tonumber(child.Data[self.LayoutOrderKey]) + if self.reverse then + uiInstance.LayoutOrder = 1000 - tonumber(child.Data[self.LayoutOrderKey]) + else + uiInstance.LayoutOrder = tonumber(child.Data[self.LayoutOrderKey]) + end end self.Instances[index] = child @@ -129,7 +147,10 @@ function UIList:GetMinLayoutOrderInstance() end function UIList:Refresh() - for _, ui in pairs(self.Instances) do ui:Destroy() end + for _, ui in pairs(self.Instances) do + if ui.UIRoot then ui.UIRoot:Destroy() end + ui:Destroy() + end self.Instances = {} if not self.Component then warn("UIList:Refresh() Component未设置") return end diff --git a/src/ReplicatedStorage/Json/AttributesUpgrade.json b/src/ReplicatedStorage/Json/AttributesUpgrade.json index 6510e37..c238de5 100644 --- a/src/ReplicatedStorage/Json/AttributesUpgrade.json +++ b/src/ReplicatedStorage/Json/AttributesUpgrade.json @@ -1,6 +1,6 @@ [ -{"id":1,"type":1,"effectAttribute":"attack","cost":[1,10,20],"lvAdd":[10,20],"battleValueLimit":[5,20],"maxLv":null}, -{"id":2,"type":1,"effectAttribute":"hp","cost":[1,10,20],"lvAdd":[10,20],"battleValueLimit":[5,20],"maxLv":null}, +{"id":1,"type":1,"effectAttribute":"attack","cost":[1,10,20],"lvAdd":[100,845],"battleValueLimit":[5,20],"maxLv":null}, +{"id":2,"type":1,"effectAttribute":"hp","cost":[1,10,20],"lvAdd":[2000,845],"battleValueLimit":[5,20],"maxLv":null}, {"id":3,"type":1,"effectAttribute":"swordAtk","cost":[1,10,20],"lvAdd":[10,20],"battleValueLimit":[5,20],"maxLv":null}, {"id":4,"type":1,"effectAttribute":"swordWearBase","cost":[1,10,20],"lvAdd":[10,20],"battleValueLimit":[5,20],"maxLv":null}, {"id":5,"type":1,"effectAttribute":"swordWearSpe","cost":[1,10,20],"lvAdd":[10,20],"battleValueLimit":[5,20],"maxLv":null}, diff --git a/src/ReplicatedStorage/Json/Character.json b/src/ReplicatedStorage/Json/Character.json index 92d553a..dfbc59d 100644 --- a/src/ReplicatedStorage/Json/Character.json +++ b/src/ReplicatedStorage/Json/Character.json @@ -1,3 +1,3 @@ [ -{"id":1,"name":1,"attack":10,"hp":100,"walkSpeed":10,"atkSpeed":1} +{"id":1,"name":1,"attack":100,"hp":2000,"walkSpeed":10,"atkSpeed":1} ] \ No newline at end of file diff --git a/src/ReplicatedStorage/Json/Enemy.json b/src/ReplicatedStorage/Json/Enemy.json index 05a2143..e29a0d2 100644 --- a/src/ReplicatedStorage/Json/Enemy.json +++ b/src/ReplicatedStorage/Json/Enemy.json @@ -1,5 +1,5 @@ [ -{"id":1,"type":1,"name":1,"attack":10,"hp":100,"walkSpeed":10,"attackSpeed":2,"model":"Thief"}, +{"id":1,"type":1,"name":1,"attack":83,"hp":400,"walkSpeed":10,"attackSpeed":1,"model":"Thief"}, {"id":2,"type":1,"name":2,"attack":30,"hp":300,"walkSpeed":10,"attackSpeed":1,"model":"Thief"}, -{"id":1000,"type":2,"name":1000,"attack":50,"hp":1000,"walkSpeed":20,"attackSpeed":1,"model":"Thief"} +{"id":1000,"type":2,"name":1000,"attack":240,"hp":2000,"walkSpeed":20,"attackSpeed":1,"model":"Thief"} ] \ No newline at end of file diff --git a/src/ReplicatedStorage/Json/Forge.json b/src/ReplicatedStorage/Json/Forge.json index 1a4963c..e3cc33b 100644 --- a/src/ReplicatedStorage/Json/Forge.json +++ b/src/ReplicatedStorage/Json/Forge.json @@ -1,17 +1,17 @@ [ -{"id":1,"cost":[2,20]}, -{"id":2,"cost":[2,30]}, -{"id":3,"cost":[2,40]}, -{"id":4,"cost":[2,50]}, -{"id":5,"cost":[2,60]}, -{"id":6,"cost":[2,70]}, -{"id":7,"cost":[2,80]}, -{"id":8,"cost":[2,90]}, -{"id":9,"cost":[2,100]}, -{"id":10,"cost":[2,110]}, -{"id":11,"cost":[2,120]}, -{"id":12,"cost":[2,130]}, -{"id":13,"cost":[2,140]}, -{"id":14,"cost":[2,150]}, -{"id":15,"cost":[2,160]} +{"id":1,"cost":[1,500]}, +{"id":2,"cost":[1,500]}, +{"id":3,"cost":[1,500]}, +{"id":4,"cost":[1,500]}, +{"id":5,"cost":[1,500]}, +{"id":6,"cost":[1,500]}, +{"id":7,"cost":[1,500]}, +{"id":8,"cost":[1,500]}, +{"id":9,"cost":[1,500]}, +{"id":10,"cost":[1,500]}, +{"id":11,"cost":[1,500]}, +{"id":12,"cost":[1,500]}, +{"id":13,"cost":[1,500]}, +{"id":14,"cost":[1,500]}, +{"id":15,"cost":[1,500]} ] \ No newline at end of file diff --git a/src/ReplicatedStorage/Json/Level.json b/src/ReplicatedStorage/Json/Level.json index bc036d9..5dc7665 100644 --- a/src/ReplicatedStorage/Json/Level.json +++ b/src/ReplicatedStorage/Json/Level.json @@ -1,22 +1,52 @@ [ -{"id":1,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1]]}, -{"id":2,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":3,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":4,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":5,"type":2,"timeLimit":60,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1000,1]]}, -{"id":6,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":7,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":8,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":9,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":10,"type":2,"timeLimit":60,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1000,1]]}, -{"id":11,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":12,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":13,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":14,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":15,"type":2,"timeLimit":60,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1000,1]]}, -{"id":16,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":17,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":18,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":19,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1],[10,1,1,10,2,1]]}, -{"id":20,"type":2,"timeLimit":60,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1000,1]]} +{"id":1,"type":1,"timeLimit":null,"atkBonus":500,"hpBonus":500,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":2,"type":1,"timeLimit":null,"atkBonus":520,"hpBonus":520,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":3,"type":1,"timeLimit":null,"atkBonus":540,"hpBonus":540,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":4,"type":1,"timeLimit":null,"atkBonus":560,"hpBonus":560,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":5,"type":2,"timeLimit":60,"atkBonus":1050,"hpBonus":1050,"wave":[[10,1000,1]]}, +{"id":6,"type":1,"timeLimit":null,"atkBonus":600,"hpBonus":600,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":7,"type":1,"timeLimit":null,"atkBonus":620,"hpBonus":620,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":8,"type":1,"timeLimit":null,"atkBonus":640,"hpBonus":640,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":9,"type":1,"timeLimit":null,"atkBonus":660,"hpBonus":660,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":10,"type":2,"timeLimit":60,"atkBonus":1100,"hpBonus":1100,"wave":[[10,1000,1]]}, +{"id":11,"type":1,"timeLimit":null,"atkBonus":700,"hpBonus":700,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":12,"type":1,"timeLimit":null,"atkBonus":720,"hpBonus":720,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":13,"type":1,"timeLimit":null,"atkBonus":740,"hpBonus":740,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":14,"type":1,"timeLimit":null,"atkBonus":760,"hpBonus":760,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":15,"type":2,"timeLimit":60,"atkBonus":1150,"hpBonus":1150,"wave":[[10,1000,1]]}, +{"id":16,"type":1,"timeLimit":null,"atkBonus":800,"hpBonus":800,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":17,"type":1,"timeLimit":null,"atkBonus":820,"hpBonus":820,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":18,"type":1,"timeLimit":null,"atkBonus":840,"hpBonus":840,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":19,"type":1,"timeLimit":null,"atkBonus":860,"hpBonus":860,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":20,"type":2,"timeLimit":60,"atkBonus":1250,"hpBonus":1250,"wave":[[10,1000,1]]}, +{"id":21,"type":1,"timeLimit":null,"atkBonus":900,"hpBonus":900,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":22,"type":1,"timeLimit":null,"atkBonus":920,"hpBonus":920,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":23,"type":1,"timeLimit":null,"atkBonus":940,"hpBonus":940,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":24,"type":1,"timeLimit":null,"atkBonus":960,"hpBonus":960,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":25,"type":2,"timeLimit":60,"atkBonus":1350,"hpBonus":1350,"wave":[[10,1000,1]]}, +{"id":26,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":27,"type":1,"timeLimit":null,"atkBonus":1020,"hpBonus":1020,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":28,"type":1,"timeLimit":null,"atkBonus":1040,"hpBonus":1040,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":29,"type":1,"timeLimit":null,"atkBonus":1060,"hpBonus":1060,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":30,"type":2,"timeLimit":60,"atkBonus":1500,"hpBonus":1500,"wave":[[10,1000,1]]}, +{"id":31,"type":1,"timeLimit":null,"atkBonus":1100,"hpBonus":1100,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":32,"type":1,"timeLimit":null,"atkBonus":1120,"hpBonus":1120,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":33,"type":1,"timeLimit":null,"atkBonus":1140,"hpBonus":1140,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":34,"type":1,"timeLimit":null,"atkBonus":1160,"hpBonus":1160,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":35,"type":2,"timeLimit":60,"atkBonus":2000,"hpBonus":2000,"wave":[[10,1000,1]]}, +{"id":36,"type":1,"timeLimit":null,"atkBonus":1200,"hpBonus":1200,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":37,"type":1,"timeLimit":null,"atkBonus":1220,"hpBonus":1220,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":38,"type":1,"timeLimit":null,"atkBonus":1240,"hpBonus":1240,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":39,"type":1,"timeLimit":null,"atkBonus":1260,"hpBonus":1260,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":40,"type":2,"timeLimit":60,"atkBonus":2500,"hpBonus":2500,"wave":[[10,1000,1]]}, +{"id":41,"type":1,"timeLimit":null,"atkBonus":1300,"hpBonus":1300,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":42,"type":1,"timeLimit":null,"atkBonus":1320,"hpBonus":1320,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":43,"type":1,"timeLimit":null,"atkBonus":1340,"hpBonus":1340,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":44,"type":1,"timeLimit":null,"atkBonus":1360,"hpBonus":1360,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":45,"type":2,"timeLimit":60,"atkBonus":3000,"hpBonus":3000,"wave":[[10,1000,1]]}, +{"id":46,"type":1,"timeLimit":null,"atkBonus":1400,"hpBonus":1400,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":47,"type":1,"timeLimit":null,"atkBonus":1420,"hpBonus":1420,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":48,"type":1,"timeLimit":null,"atkBonus":1440,"hpBonus":1440,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":49,"type":1,"timeLimit":null,"atkBonus":1460,"hpBonus":1460,"wave":[[10,1,1,50,1,1,100,1,1,150,1,1,200,1,1,250,1,1]]}, +{"id":50,"type":2,"timeLimit":60,"atkBonus":3500,"hpBonus":3500,"wave":[[10,1000,1]]} ] \ No newline at end of file diff --git a/src/ServerStorage/Proxy/BookProxy.luau b/src/ServerStorage/Proxy/BookProxy.luau index 0befcbc..6d7a335 100644 --- a/src/ServerStorage/Proxy/BookProxy.luau +++ b/src/ServerStorage/Proxy/BookProxy.luau @@ -64,7 +64,11 @@ function BookProxy:AddBook(Player: Player, BookId: number, UniqueEquipmentId: nu local EquipmentData = EquipmentProxy:GetEquipmentData(Player, UniqueEquipmentId) if not EquipmentData then return end + + -- 变成字符串,因为在次读取后,是字典 + local BookId = tostring(BookId) local orgBookData = ArchiveProxy.pData[Player.UserId][STORE_NAME].Books[BookId] + -- 检查是否已经存在 if orgBookData then -- 图鉴没原先品质高就返回 @@ -86,6 +90,7 @@ end -- 解锁图鉴 function BookProxy:UnlockBook(Player: Player, BookId: number) + local BookId = tostring(BookId) local pData = Utils:GetPlayerDataFolder(Player) if not pData then return end @@ -102,7 +107,7 @@ end -- 检查是否解锁对应图鉴 function BookProxy:IsBookUnlocked(Player: Player, BookId: number) - return ArchiveProxy.pData[Player.UserId][STORE_NAME].Books[BookId] ~= nil + return ArchiveProxy.pData[Player.UserId][STORE_NAME].Books[tostring(BookId)] end -------------------------------------------------------------------------------- diff --git a/src/ServerStorage/Proxy/EquipmentProxy.luau b/src/ServerStorage/Proxy/EquipmentProxy.luau index a0b63c4..a0696cc 100644 --- a/src/ServerStorage/Proxy/EquipmentProxy.luau +++ b/src/ServerStorage/Proxy/EquipmentProxy.luau @@ -21,7 +21,6 @@ local JsonParam = require(ReplicatedStorage.Json.Param) local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip local RE_WearEquipment = ReplicatedStorage.Events.RE_WearEquipment - --> Constants local STORE_NAME = "Equipment" @@ -219,12 +218,12 @@ function EquipmentProxy:AddEquipment(Player: Player, EquipmentId: number) ------------------------------------------------------------ ArchiveProxy.pData[Player.UserId][STORE_NAME][UniqueId] = ResultData - print(ArchiveProxy.pData[Player.UserId][STORE_NAME]) - Utils:CreateDataInstance(Player, UniqueId, ResultData, GetPlayerEquipmentFolder(Player)) + local equipmentInstance = Utils:CreateDataInstance(Player, UniqueId, ResultData, GetPlayerEquipmentFolder(Player)) -- 添加图鉴记录 local BookProxy = require(ServerStorage.Proxy.BookProxy) BookProxy:AddBook(Player, EquipmentId, UniqueId) + return equipmentInstance end -- 回收装备 diff --git a/src/ServerStorage/Proxy/PlayerInfoProxy.luau b/src/ServerStorage/Proxy/PlayerInfoProxy.luau index 3d2a261..4959fdc 100644 --- a/src/ServerStorage/Proxy/PlayerInfoProxy.luau +++ b/src/ServerStorage/Proxy/PlayerInfoProxy.luau @@ -20,6 +20,7 @@ local JsonForge = require(ReplicatedStorage.Json.Forge) local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip local RE_Forge = ReplicatedStorage.Events.RE_Forge local RE_UpgradeAttributes = ReplicatedStorage.Events.RE_UpgradeAttributes +local RE_ShowGetEquipments = ReplicatedStorage.Events.RE_ShowGetEquipments --> Constants local STORE_NAME = "PlayerInfo" @@ -67,6 +68,7 @@ local STATS_DATA = { name = {type = ENUM_STATE_TYPE.String, value = "PlayerName"}, level = {type = ENUM_STATE_TYPE.Number, value = 1}, exp = {type = ENUM_STATE_TYPE.Number, value = 0}, + forge = {type = ENUM_STATE_TYPE.Number, value = 1}, } -- 初始化玩家状态信息(采用额外添加的模式,如果没有写值,就覆盖写入) @@ -75,7 +77,7 @@ local function ExtraAddPlayerStats(Player: Player, StatsData: table) -- 如果列表中不包含信息就添加到表中 for StateKey, StateValue in STATS_DATA do if not StatsData[StateKey] then - StatsData[StateKey] = StateValue + StatsData[StateKey] = StateValue.value end end end @@ -97,7 +99,6 @@ function PlayerInfoProxy:InitPlayer(Player: Player) ArchiveProxy.pData[Player.UserId][STORE_NAME].Stats = {} ArchiveProxy.pData[Player.UserId][STORE_NAME].Items = {} ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade = {} - ArchiveProxy.pData[Player.UserId][STORE_NAME].Forge = 1 end -- 放在外面是为了以后系统新增内容方便(同时不用在初始化数据是做写入了) @@ -108,7 +109,7 @@ function PlayerInfoProxy:InitPlayer(Player: Player) CreateInfoInstance(Player, ItemsFolder, ItemId, ENUM_STATE_TYPE.Number, ItemValue) end for StateKey, StateData in ArchiveProxy.pData[Player.UserId][STORE_NAME].Stats do - CreateInfoInstance(Player, StatsFolder, StateKey, StateData.type, StateData.value) + CreateInfoInstance(Player, StatsFolder, StateKey, STATS_DATA[StateKey].type, StateData) end for AttributeId, AttributeLv in ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade do CreateInfoInstance(Player, AttributesUpgradeFolder, AttributeId, "NumberValue", AttributeLv) @@ -127,7 +128,7 @@ end function PlayerInfoProxy:GetPlayerLevel(Player: Player) if not Player then warn('获取玩家等级失败: ', Player.Name) return end local playerInfoData = ArchiveProxy.pData[Player.UserId][STORE_NAME] - return playerInfoData.Stats.level.value + return playerInfoData.Stats.level end function PlayerInfoProxy:GetPlayerAttributesUpgrade(Player: Player, AttributeName: string) @@ -153,7 +154,7 @@ function PlayerInfoProxy:UpgradeAttribute(Player: Player, AttributeId: number) requireMoney = attributeData["cost"][2] requireBattleValue = attributeData["battleValueLimit"][1] else - requireMoney = attributeData["cost"][2] + (nowLv - 1) * attributeData["cost"][3] + requireMoney = math.floor(attributeData["cost"][2] ^ (nowLv - 1) * attributeData["cost"][3] / 100) requireBattleValue = attributeData["battleValueLimit"][1] + (nowLv - 1) * attributeData["battleValueLimit"][2] end @@ -255,6 +256,7 @@ end -- 打造装备 function PlayerInfoProxy:MakeForge(Player: Player, EquipmentId: number, Count: number) if not Player or not EquipmentId then warn('打造装备失败: ', Player.Name,EquipmentId) return end + local playerInfoData = ArchiveProxy.pData[Player.UserId][STORE_NAME] local PlayerInfoFolder = GetPlayerInfoFolder(Player) if not PlayerInfoFolder then return end @@ -266,18 +268,23 @@ function PlayerInfoProxy:MakeForge(Player: Player, EquipmentId: number, Count: n return end - -- 锻造数量>1,判断是否到达最高锻造等级 - local ForgeLv = PlayerInfoProxy:GetPlayerInfo(Player).Forge - if Count > 1 then - local MaxForgeLv = Utils:GetMaxIdFromJson(JsonForge, ForgeLv) - if ForgeLv < MaxForgeLv then - RE_PlayerTip:FireClient(Player, "锻造等级已到达最高等级") - return + -- 判断金钱是否足够 + local MaxForgeLv = Utils:GetMaxIdFromJson(JsonForge) + local ShouldCostMoney = 0 + for i = 1, Count do + -- 读取等级并且做最大值限制 + local ForgeLv = ArchiveProxy.pData[Player.UserId][STORE_NAME]["Stats"].forge + ForgeLv = ForgeLv > MaxForgeLv and MaxForgeLv or ForgeLv + + local ForgeData = Utils:GetIdDataFromJson(JsonForge, ForgeLv) + ShouldCostMoney = ShouldCostMoney + ForgeData["cost"][2] + + if ForgeLv > MaxForgeLv then + ForgeLv = MaxForgeLv + else + ForgeLv = ForgeLv + 1 end end - - -- 判断金钱是否足够 - local ShouldCostMoney = Utils:GetIdDataFromJson(JsonForge, ForgeLv)["cost"][2] * Count if not self:HasEnoughItem(Player, 1, ShouldCostMoney) then RE_PlayerTip:FireClient(Player, "金钱不足") return @@ -286,16 +293,19 @@ function PlayerInfoProxy:MakeForge(Player: Player, EquipmentId: number, Count: n self:ChangeItemCount(Player, 1, -ShouldCostMoney) -- 生成对应装备 + local ResultData = {} local EquipmentProxy = require(ServerStorage.Proxy.EquipmentProxy) for i = 1, Count do - EquipmentProxy:AddEquipment(Player, EquipmentId) + local EquipmentInstance = EquipmentProxy:AddEquipment(Player, EquipmentId) + table.insert(ResultData, EquipmentInstance) end -- 锻造升级 - ForgeLv = ForgeLv + Count - ChangeInfoInstance(Player, PlayerInfoFolder, "Forge", ForgeLv) + ArchiveProxy.pData[Player.UserId][STORE_NAME]["Stats"].forge = ArchiveProxy.pData[Player.UserId][STORE_NAME]["Stats"].forge + Count + ChangeInfoInstance(Player, PlayerInfoFolder:FindFirstChild("Stats"), "forge", ArchiveProxy.pData[Player.UserId][STORE_NAME]["Stats"].forge) - -- TODO: 添加对应奖励弹窗 + -- 装备奖励弹窗 + RE_ShowGetEquipments:FireClient(Player, ResultData) end -------------------------------------------------------------------------------- @@ -307,7 +317,8 @@ function PlayerInfoProxy:GetPlayerUpgradeAttributes(Player: Player) local attributes = {} for AttributeId, AttributeLv in playerInfoData.AttributesUpgrade do local attributeData = Utils:GetIdDataFromJson(JsonAttributesUpgrade, AttributeId) - attributes[attributeData["effectAttribute"]] = attributeData["lvAdd"][1] + (AttributeLv - 1) * attributeData["lvAdd"][2] + -- attributes[attributeData["effectAttribute"]] = attributeData["lvAdd"][1] + (AttributeLv - 1) * attributeData["lvAdd"][2] + attributes[attributeData["effectAttribute"]] = math.floor(attributeData["lvAdd"][1] ^ (AttributeLv - 1) * attributeData["lvAdd"][2] / 10000) end return attributes end diff --git a/src/StarterPlayerScripts/ClientMain/HealthBar.luau b/src/StarterPlayerScripts/ClientMain/HealthBar.luau new file mode 100644 index 0000000..3fab74c --- /dev/null +++ b/src/StarterPlayerScripts/ClientMain/HealthBar.luau @@ -0,0 +1,69 @@ +local HealthBar = {} + +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local Workspace = game:GetService("Workspace") +local Players = game:GetService("Players") + +local BoardFolder = ReplicatedStorage:WaitForChild("UI"):WaitForChild("Board") +local HeadBar = BoardFolder:WaitForChild("HeadBar") + +local LocalPlayer = Players.LocalPlayer +local MobsFolder = Workspace:WaitForChild("Mobs"):WaitForChild(LocalPlayer.UserId) +local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait() + +local Connections = {} + +local function SetHp(child, hpFill, Attributes) + local hpValue = Attributes:GetAttribute("hp") + local maxHpValue = Attributes:GetAttribute("maxhp") + hpFill.Size = UDim2.new(hpValue / maxHpValue, 0, 1, 0) +end + +local function SetHealthBar(child, prefab) + local HealthBarInstance = prefab:Clone() + + local CoordinateFrame: CFrame, Size: Vector3 = child:GetBoundingBox() + HealthBarInstance.Adornee = child.HumanoidRootPart + HealthBarInstance.StudsOffsetWorldSpace = Vector3.new(0, (CoordinateFrame.Position.Y+Size.Y/2) - child.HumanoidRootPart.Position.Y+2, 0) + HealthBarInstance.Enabled = true + local hpFill = HealthBarInstance:WaitForChild("Canvas"):WaitForChild("HealthBar"):WaitForChild("Fill") + HealthBarInstance.Parent = child + + local Attributes = child:WaitForChild("Attributes") + local attributeCon = Attributes.AttributeChanged:Connect(function(attribute) + if attribute == "hp" then + SetHp(child, hpFill, Attributes) + end + end) + Connections[child] = attributeCon + + -- 初始化设置血量 + SetHp(child, hpFill, Attributes) +end + +-- 玩家自己特殊监听 +SetHealthBar(Character, HeadBar) + +-- 监听玩家角色重新生成(暂时没放在Connections中) +LocalPlayer.CharacterAdded:Connect(function(newCharacter) + Character = newCharacter + SetHealthBar(Character, HeadBar) +end) + + + +-- TODO: 监听玩家怪物目录下的怪物增减,处理对应血条 +MobsFolder.ChildAdded:Connect(function(child) + if child:IsA("Model") then + SetHealthBar(child, HeadBar) + end +end) + +MobsFolder.ChildRemoved:Connect(function(child) + if Connections[child] then + Connections[child]:Disconnect() + Connections[child] = nil + end +end) + +return HealthBar \ No newline at end of file diff --git a/src/StarterPlayerScripts/ClientMain/Helper.luau b/src/StarterPlayerScripts/ClientMain/Helper.luau index 1168257..9350299 100644 --- a/src/StarterPlayerScripts/ClientMain/Helper.luau +++ b/src/StarterPlayerScripts/ClientMain/Helper.luau @@ -15,7 +15,7 @@ UserInputService.InputBegan:Connect(function(input, gameProcessed) if input.KeyCode == Enum.KeyCode.H then RE_PlayerHelper:FireServer("CleanPlayerData") elseif input.KeyCode == Enum.KeyCode.J then - RE_PlayerHelper:FireServer("AddItem", {1, 100}) + RE_PlayerHelper:FireServer("AddItem", {1, 1000}) elseif input.KeyCode == Enum.KeyCode.K then RE_UpgradeAttributes:FireServer(1) elseif input.KeyCode == Enum.KeyCode.L then diff --git a/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau b/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau index a526288..7ddccf5 100644 --- a/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau +++ b/src/StarterPlayerScripts/ClientMain/PerformanceClient/init.luau @@ -12,6 +12,7 @@ local RE_PerformanceEvent = EventsFolder:FindFirstChild("RE_PerformanceEvent") local RE_CleanPlayerPerformance = EventsFolder:FindFirstChild("RE_CleanPlayerPerformance") local RE_DamagePerformance = EventsFolder:FindFirstChild("RE_DamagePerformance") local RE_AbilityPerformance = EventsFolder:FindFirstChild("RE_AbilityPerformance") +local RE_ShowGetEquipments = EventsFolder:FindFirstChild("RE_ShowGetEquipments") --> Dependencies local UIManager = require(script.Parent.Parent.UI.UIManager) @@ -113,6 +114,13 @@ RE_CleanPlayerPerformance.OnClientEvent:Connect(function(CleanedPlayer: Player) PerformanceClient.pData[UserId] = nil end) +-- 监听获取装备事件调用 +RE_ShowGetEquipments.OnClientEvent:Connect(function(EquipmentDetail: table) + if not UIManager:IsOpened("GetEquipmentsWindow") then + UIManager:OpenWindow("GetEquipmentsWindow", EquipmentDetail) + end +end) + -- 打开默认界面 UIManager:OpenWindow("MainWindow") UIManager:OpenWindow("TipsWindow") diff --git a/src/StarterPlayerScripts/UI/UIManager.luau b/src/StarterPlayerScripts/UI/UIManager.luau index 4f513d5..0fb6a88 100644 --- a/src/StarterPlayerScripts/UI/UIManager.luau +++ b/src/StarterPlayerScripts/UI/UIManager.luau @@ -4,10 +4,98 @@ local FolderWindows = script.Parent.Windows UIManager.Instances = {} UIManager.Windows = {} +UIManager.WindowStack = {} -- 窗口堆栈 +UIManager.ExcludeFromStack = { -- 不受堆栈影响的窗口列表 + "TipsWindow", -- 主窗口 + "AbilityStateWindow", + -- 可以继续添加其他窗口名称 +} + for _, child in FolderWindows:GetChildren() do UIManager.Windows[child.Name] = require(child) end +-- 获取窗口的ZIndex +local function getWindowZIndex(windowInstance) + if not windowInstance or not windowInstance.UIRoot then + return 0 + end + return windowInstance.UIRoot.ZIndex or 0 +end + +-- 设置窗口的Interactable +local function setWindowInteractable(windowInstance, interactable) + if not windowInstance or not windowInstance.UIRoot then + return + end + + -- 根窗口本身就是CanvasGroup + if windowInstance.UIRoot:IsA("CanvasGroup") then + windowInstance.UIRoot.Interactable = interactable + end +end + +-- 检查窗口是否在排除列表中 +local function isExcludedFromStack(windowName) + for _, excludedName in ipairs(UIManager.ExcludeFromStack) do + if windowName == excludedName then + return true + end + end + return false +end + +-- 管理窗口堆栈 +local function manageWindowStack(newWindowName, newWindowInstance) + -- 检查是否在排除列表中 + if isExcludedFromStack(newWindowName) then + return + end + + local newZIndex = getWindowZIndex(newWindowInstance) + + -- 检查堆栈中所有窗口,设置ZIndex较低的窗口为false + for i = #UIManager.WindowStack, 1, -1 do + local stackWindow = UIManager.WindowStack[i] + local stackZIndex = getWindowZIndex(stackWindow.instance) + + -- 如果堆栈中窗口的ZIndex小于等于新窗口,设置为false + if stackZIndex <= newZIndex then + -- 设置之前窗口的Interactable为false + setWindowInteractable(stackWindow.instance, false) + end + end + + -- 将新窗口添加到堆栈顶部 + table.insert(UIManager.WindowStack, { + name = newWindowName, + instance = newWindowInstance, + zIndex = newZIndex + }) +end + +-- 移除窗口堆栈中的窗口 +local function removeFromWindowStack(windowName) + -- 检查是否在排除列表中 + if isExcludedFromStack(windowName) then + return + end + + for i = #UIManager.WindowStack, 1, -1 do + if UIManager.WindowStack[i].name == windowName then + table.remove(UIManager.WindowStack, i) + break + end + end + + -- 如果堆栈不为空,设置顶部窗口的Interactable为true + if #UIManager.WindowStack > 0 then + local topWindow = UIManager.WindowStack[#UIManager.WindowStack] + setWindowInteractable(topWindow.instance, true) + end +end + +-- 打开窗口 function UIManager:OpenWindow(WindowName: string, Data: table?) if not UIManager.Windows[WindowName] then warn("UIManager:OpenWindow() 窗口不存在:" .. WindowName) @@ -16,22 +104,21 @@ function UIManager:OpenWindow(WindowName: string, Data: table?) UIManager.Instances[WindowName] = UIManager.Windows[WindowName]:Init(self, Data) UIManager.Instances[WindowName]:OnOpenWindow() + + -- 管理窗口堆栈 + manageWindowStack(WindowName, UIManager.Instances[WindowName]) end -function UIManager:SetData(WindowName: string, Data: table) - if not UIManager.Instances[WindowName] then - warn("UIManager:SetData() 窗口不存在:" .. WindowName) - return - end - UIManager.Instances[WindowName]:SetData(Data) -end - +-- 关闭窗口 function UIManager:CloseWindow(WindowName: string) if not UIManager.Instances[WindowName] then warn("UIManager:CloseWindow() 窗口不存在:" .. WindowName) return end + -- 从堆栈中移除窗口 + removeFromWindowStack(WindowName) + UIManager.Instances[WindowName]:OnCloseWindow() UIManager.Instances[WindowName]:Destroy() UIManager.Instances[WindowName] = nil @@ -41,5 +128,51 @@ function UIManager:IsOpened(WindowName: string) return UIManager.Instances[WindowName] ~= nil end +-- 获取当前窗口堆栈信息(用于调试) +function UIManager:GetWindowStackInfo() + local info = {} + for i, window in ipairs(UIManager.WindowStack) do + table.insert(info, { + name = window.name, + zIndex = window.zIndex, + index = i + }) + end + return info +end + +-- 打印窗口堆栈(用于调试) +function UIManager:PrintWindowStack() + print("=== 窗口堆栈信息 ===") + for i, window in ipairs(UIManager.WindowStack) do + print(string.format("[%d] %s (ZIndex: %d)", i, window.name, window.zIndex)) + end + print("==================") +end + +-- 添加窗口到排除列表 +function UIManager:AddToExcludeList(windowName) + for _, excludedName in ipairs(UIManager.ExcludeFromStack) do + if windowName == excludedName then + return + end + end + table.insert(UIManager.ExcludeFromStack, windowName) +end + +-- 从排除列表中移除窗口 +function UIManager:RemoveFromExcludeList(windowName) + for i, excludedName in ipairs(UIManager.ExcludeFromStack) do + if windowName == excludedName then + table.remove(UIManager.ExcludeFromStack, i) + return + end + end +end + +-- 获取排除列表 +function UIManager:GetExcludeList() + return UIManager.ExcludeFromStack +end return UIManager \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/CreateWindow/init.luau b/src/StarterPlayerScripts/UI/Windows/CreateWindow/init.luau index d3036b6..c901c2e 100644 --- a/src/StarterPlayerScripts/UI/Windows/CreateWindow/init.luau +++ b/src/StarterPlayerScripts/UI/Windows/CreateWindow/init.luau @@ -44,6 +44,7 @@ function CreateWindow:Init(UIManager: table, Data: table?) ["_tmpQuality"] = 0, ["_toggleAutoRecycle"] = 0, ["_imgAutoRecycleActive"] = 0, + ["__moneyCoin"] = 0, } self.MultNumber = 1 self.AutoRecycle = false @@ -107,7 +108,7 @@ function CreateWindow:OnOpenWindow() Quality = child:GetAttribute("quality"), Timestamp = child:GetAttribute("timestamp"), } - self.Variables["__listWeaponPackage"]:AddData(self.Data[child.Name]) + self.Variables["__listWeaponPackage"]:AddData(child.Name, self.Data[child.Name]) end) table.insert(self.Connections, childAddCon) @@ -140,10 +141,12 @@ function CreateWindow:OnOpenWindow() if self.Data then local minInstance = self.Variables["__listWeaponPackage"]:GetMinLayoutOrderInstance() - self:ShowDetailInfo(minInstance.Data) + if minInstance then + self:ShowDetailInfo(minInstance.Data) - self.LastActiveItem = minInstance - minInstance:SetSelected(true) + self.LastActiveItem = minInstance + minInstance:SetSelected(true) + end else self:ShowDetailInfo() end diff --git a/src/StarterPlayerScripts/UI/Windows/GetEquipmentsWindow/AttributeShow.luau b/src/StarterPlayerScripts/UI/Windows/GetEquipmentsWindow/AttributeShow.luau new file mode 100644 index 0000000..4f41d03 --- /dev/null +++ b/src/StarterPlayerScripts/UI/Windows/GetEquipmentsWindow/AttributeShow.luau @@ -0,0 +1,43 @@ +local AttributeShow = {} +AttributeShow.__index = AttributeShow + +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +local Utils = require(ReplicatedStorage.Tools.Utils) +local Localization = require(ReplicatedStorage.Tools.Localization) +local JsonEquipment = require(ReplicatedStorage.Json.Equipment) +local JsonItemProp = require(ReplicatedStorage.Json.ItemProp) +local JsonAttributes = require(ReplicatedStorage.Json.Attributes) + +function AttributeShow:Init(data: table) + local self = {} + self.Data = data + self.Variables = { + ["_tmpAttributeName"] = 0, + ["_tmpValue"] = 0, + } + + setmetatable(self, AttributeShow) + return self +end + +function AttributeShow:Refresh() + local attributeData = Utils:GetSpecialKeyDataFromJson(JsonAttributes, "effectAttribute", self.Data.attribute) + self.Variables._tmpAttributeName.Text = self.Data.attribute + self.UIRoot.LayoutOrder = 1000 - attributeData.id + + if attributeData.type == 2 then + self.Variables._tmpValue.Text = string.format("%.2f%%", self.Data.value / 100) + else + self.Variables._tmpValue.Text = self.Data.value + end +end + +function AttributeShow:Destroy() + for k, v in pairs(self) do + self[k] = nil + end + self = nil +end + +return AttributeShow \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/GetEquipmentsWindow/EquipmentShow.luau b/src/StarterPlayerScripts/UI/Windows/GetEquipmentsWindow/EquipmentShow.luau new file mode 100644 index 0000000..511dd7a --- /dev/null +++ b/src/StarterPlayerScripts/UI/Windows/GetEquipmentsWindow/EquipmentShow.luau @@ -0,0 +1,77 @@ +local EquipmentShow = {} +EquipmentShow.__index = EquipmentShow + +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +local Utils = require(ReplicatedStorage.Tools.Utils) +local Localization = require(ReplicatedStorage.Tools.Localization) +local JsonEquipment = require(ReplicatedStorage.Json.Equipment) +local JsonItemProp = require(ReplicatedStorage.Json.ItemProp) +local JsonAttributes = require(ReplicatedStorage.Json.Attributes) + +local FolderEquipment = ReplicatedStorage:WaitForChild("Prefabs"):WaitForChild("Equipments") + +function EquipmentShow:Init(data: table) + local self = {} + self.Data = data + self.Variables = { + ["_imgView"] = 0, + ["_btnSelect"] = 0, + } + self.Connections = {} + + setmetatable(self, EquipmentShow) + return self +end + +function EquipmentShow:Refresh() + local equipmentData = Utils:GetIdDataFromJson(JsonEquipment, self.Data["orgId"]) + + -- 模型 + local part = FolderEquipment:FindFirstChild(equipmentData.modelName):Clone() + part.Handle.Position = Vector3.new(0, 0, 0) + part.Handle.CFrame = CFrame.new(0, 0, 0) * CFrame.Angles(math.rad(90), 0, 0) + part.Parent = self.Variables["_imgView"] + self.Prefab = part + + -- 相机 + local viewportCamera = Instance.new("Camera") + self.Variables["_imgView"].CurrentCamera = viewportCamera + viewportCamera.Parent = self.Variables["_imgView"] + viewportCamera.CFrame = CFrame.new(Vector3.new(0, 0, 6), part.Handle.Position) + self.ViewCamera = viewportCamera + + -- 旋转 + self.taskRotation = task.spawn(function() + while true do + self.Prefab.Handle.CFrame = self.Prefab.Handle.CFrame * CFrame.Angles(0, 0, 0.01) + task.wait(0.01) + end + end) +end + +function EquipmentShow:OnInitFinish() + -- 点击事件 + local con = self.Variables["_btnSelect"].Activated:Connect(function() + self.TopUI:ReShowDetail(self.Data) + end) + table.insert(self.Connections, con) +end + +function EquipmentShow:Destroy() + if self.Connections then + for k, v in pairs(self.Connections) do + v:Disconnect() + end + end + if self.taskRotation then + task.cancel(self.taskRotation) + self.taskRotation = nil + end + for k, v in pairs(self) do + self[k] = nil + end + self = nil +end + +return EquipmentShow \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/GetEquipmentsWindow/init.luau b/src/StarterPlayerScripts/UI/Windows/GetEquipmentsWindow/init.luau new file mode 100644 index 0000000..09a9b93 --- /dev/null +++ b/src/StarterPlayerScripts/UI/Windows/GetEquipmentsWindow/init.luau @@ -0,0 +1,252 @@ +--> Services +local ReplicatedStorage = game:GetService("ReplicatedStorage") + +--> Dependencies +local UIWindow = require(ReplicatedStorage.Base.UIWindow) +local UIEnums = require(ReplicatedStorage.Base.UIEnums) + +--> Json +local JsonItemProp = require(ReplicatedStorage.Json.ItemProp) +local JsonAttributes = require(ReplicatedStorage.Json.Attributes) + +--> Modules +local Utils = require(ReplicatedStorage.Tools.Utils) +local Localization = require(ReplicatedStorage.Tools.Localization) +local AttributeShow = require(script.AttributeShow) +local EquipmentShow = require(script.EquipmentShow) + +local LocalPlayer = game:GetService("Players").LocalPlayer + +-------------------------------------------------------------------------------- + +local function centerSpecificListItem(scrollingFrame, targetItem) + -- 检查参数是否有效 + if not scrollingFrame or not targetItem then + warn("centerSpecificListItem: 参数无效") + return + end + + -- 等待UI完全加载 + task.wait() + + local canvasSize = scrollingFrame.CanvasSize + local absoluteSize = scrollingFrame.AbsoluteSize + + -- 检查尺寸是否有效 + if not canvasSize or not absoluteSize then + warn("centerSpecificListItem: 尺寸无效", scrollingFrame.Name) + return + end + + -- 获取目标项的位置和尺寸 + local itemPosition = targetItem.Position + local itemSize = targetItem.AbsoluteSize + + -- 检查位置和尺寸是否有效 + if not itemPosition or not itemSize then + warn("centerSpecificListItem: 目标项位置或尺寸无效", targetItem.Name) + return + end + + -- 计算目标项在ScrollingFrame中的绝对位置 + local itemAbsolutePosition = targetItem.AbsolutePosition + + -- 计算目标项的中心位置(相对于ScrollingFrame) + local itemCenterX = itemAbsolutePosition.X + (itemSize.X / 2) + + -- 计算容器中心位置 + local containerCenterX = absoluteSize.X / 2 + + -- 计算目标项在ScrollingFrame内容中的位置 + local currentCanvasPosition = scrollingFrame.CanvasPosition + + -- 计算需要的偏移量,使目标项居中 + -- 目标项中心位置 - 容器中心位置 = 需要的偏移量 + local offsetX = itemCenterX - containerCenterX + + -- 计算新的CanvasPosition(当前位置 + 需要的偏移量) + local newCanvasPositionX = currentCanvasPosition.X + offsetX + + -- 确保不超出边界 + -- CanvasSize是UDim2,需要计算实际的像素宽度 + local contentWidth = canvasSize.X.Offset + (canvasSize.X.Scale * absoluteSize.X) + local maxOffset = contentWidth - absoluteSize.X + + newCanvasPositionX = math.clamp(newCanvasPositionX, 0, math.max(0, maxOffset)) + + -- 设置canvasPosition + scrollingFrame.CanvasPosition = Vector2.new(newCanvasPositionX, 0) +end + +-------------------------------------------------------------------------------- + +local GetEquipmentsWindow = {} +GetEquipmentsWindow.__index = GetEquipmentsWindow +setmetatable(GetEquipmentsWindow, {__index = UIWindow}) + +function GetEquipmentsWindow:Init(UIManager: table, Data: table?) + local self = UIWindow:Init(UIManager, Data) + setmetatable(self, GetEquipmentsWindow) + self.Variables = { + ["_goRewardsPanel"] = 0, + ["_goDetailPanel"] = 0, + + ["_goBase"] = 0, + ["_goExAttributesPanel"] = 0, + ["_goElementPanel"] = 0, + ["_goElementDefPanel"] = 0, + + ["__listBaseAttributes"] = 0, + ["__listExAttributes"] = 0, + ["__listElement"] = 0, + ["__listElementDef"] = 0, + + ["_tmpName"] = 0, + ["_tmpQuality"] = 0, + + ["__listEquipments"] = 0, + ["_btnLeft"] = 0, + ["_btnRight"] = 0, + + ["_btnClose"] = 0, + } + self.UIRootName = "ui_w_get_equipments" + self.UIParentName = UIEnums.UIParent.UIRoot + + return self +end + +function GetEquipmentsWindow:TransformKeyTable(data: table) + local newData = {} + local index = 1 + for k, v in pairs(data) do + newData[index] = {} + newData[index]["attribute"] = k + newData[index]["value"] = v + index = index + 1 + end + return newData +end + +function GetEquipmentsWindow:ShowDetail(equipmentInstance: Instance) + local equipmentData = Utils:GetIdDataFromJson(JsonItemProp, equipmentInstance:GetAttribute("orgId")) + self.Variables["_tmpName"].Text = Localization:GetLanguageData(equipmentData.textId) + self.Variables["_tmpQuality"].Text = equipmentInstance:GetAttribute("quality") + + local baseAttributes = equipmentInstance:FindFirstChild("attributes"):GetAttributes() + local exAttributes = equipmentInstance:FindFirstChild("exAttributes"):GetAttributes() + local elements = equipmentInstance:FindFirstChild("elements"):GetAttributes() + local elementDef = equipmentInstance:FindFirstChild("elementDef"):GetAttributes() + + self.Variables["__listBaseAttributes"]:SetData(self:TransformKeyTable(baseAttributes)) + self.Variables["__listExAttributes"]:SetData(self:TransformKeyTable(exAttributes)) + self.Variables["__listElement"]:SetData(self:TransformKeyTable(elements)) + self.Variables["__listElementDef"]:SetData(self:TransformKeyTable(elementDef)) + + -- 额外属性 + if #exAttributes > 0 then + self.Variables["_goExAttributesPanel"].Visible = true + self.Variables["__listExAttributes"]:SetData(self:TransformKeyTable(exAttributes)) + else + self.Variables["_goExAttributesPanel"].Visible = false + end + + -- 元素属性 + if #elements > 0 then + self.Variables["_goElementPanel"].Visible = true + self.Variables["__listElement"]:SetData(self:TransformKeyTable(elements)) + else + self.Variables["_goElementPanel"].Visible = false + end + + -- 元素定义属性 + if #elementDef > 0 then + self.Variables["_goElementDefPanel"].Visible = true + self.Variables["__listElementDef"]:SetData(self:TransformKeyTable(elementDef)) + else + self.Variables["_goElementDefPanel"].Visible = false + end +end + +function GetEquipmentsWindow:SetCenter(listName, equipmentData) + -- 等待一帧确保UI已加载,然后设置居中 + task.spawn(function() + task.wait() -- 等待一帧 + local targetInstance = self.Variables[listName]:FindSameDataInstance(equipmentData) + if targetInstance and targetInstance.UIRoot then + -- 查找ScrollingFrame + local scrollingFrame = self.Variables[listName].UIRoot + if scrollingFrame:IsA("ScrollingFrame") then + centerSpecificListItem(scrollingFrame, targetInstance.UIRoot) + else + -- 如果不是ScrollingFrame,查找子级中的ScrollingFrame + local scroller = scrollingFrame:FindFirstChildWhichIsA("ScrollingFrame") + if scroller then + centerSpecificListItem(scroller, targetInstance.UIRoot) + end + end + end + end) +end + +function GetEquipmentsWindow:ReShowDetail(equipmentData) + local equipmentInstance + for _, instance in self.Data do + if instance.Name == tostring(equipmentData.id) then + equipmentInstance = instance + break + end + end + self:ShowDetail(equipmentInstance) + self:SetCenter("__listEquipments", equipmentData) +end + +function GetEquipmentsWindow:OnOpenWindow() + UIWindow.OnOpenWindow(self) + + local equipmentsData = {} + local maxQuality = 0 + local showDetailData = nil + + for _, equipmentInstance in self.Data do + local attributes = equipmentInstance:GetAttributes() + equipmentsData[equipmentInstance.Name] = attributes + + -- 同时找到最高品质的装备 + if attributes.quality and attributes.quality > maxQuality then + maxQuality = attributes.quality + showDetailData = attributes + end + end + + self.Variables["__listEquipments"]:AddComponent(EquipmentShow) + self.Variables["__listEquipments"]:SetData(equipmentsData) + self.Variables["__listEquipments"]:SetLayoutOrder("quality", true) + + if not showDetailData then warn("ShowDetail Is Null") return end + + self:SetCenter("__listEquipments", showDetailData) + + -- 基础属性 + self.Variables["__listBaseAttributes"]:AddComponent(AttributeShow) + self.Variables["__listExAttributes"]:AddComponent(AttributeShow) + self.Variables["__listElement"]:AddComponent(AttributeShow) + self.Variables["__listElementDef"]:AddComponent(AttributeShow) + + -- 找到对应的原始equipmentInstance来显示详情 + for _, equipmentInstance in self.Data do + if equipmentInstance:GetAttribute("quality") == showDetailData.quality then + self:ShowDetail(equipmentInstance) + break + end + end + + local closeCon = self.Variables["_btnClose"].Activated:Connect(function() + self.UIManager:CloseWindow(script.Name) + end) + table.insert(self.Connections, closeCon) +end + + + +return GetEquipmentsWindow \ No newline at end of file diff --git a/src/StarterPlayerScripts/UI/Windows/MainWindow/init.luau b/src/StarterPlayerScripts/UI/Windows/MainWindow/init.luau index 0e1b309..050451d 100644 --- a/src/StarterPlayerScripts/UI/Windows/MainWindow/init.luau +++ b/src/StarterPlayerScripts/UI/Windows/MainWindow/init.luau @@ -5,6 +5,13 @@ local ReplicatedStorage = game:GetService("ReplicatedStorage") local UIWindow = require(ReplicatedStorage.Base.UIWindow) local UIEnums = require(ReplicatedStorage.Base.UIEnums) +--> Json +local JsonLevel = require(ReplicatedStorage.Json.Level) + +local Utils = require(ReplicatedStorage.Tools.Utils) + +local LocalPlayer = game:GetService("Players").LocalPlayer + -------------------------------------------------------------------------------- local MainWindow = {} @@ -18,6 +25,9 @@ function MainWindow:Init(UIManager: table, Data: table?) ["_btnMainCreate"] = 0, ["_btnMainCha"] = 0, ["_btnMainAttributeUpgrade"] = 0, + + ["_tmpNowLevel"] = 0, + ["_imgBoss"] = 0, } self.UIRootName = "ui_w_main" self.UIParentName = UIEnums.UIParent.UIRoot @@ -25,6 +35,16 @@ function MainWindow:Init(UIManager: table, Data: table?) return self end +function MainWindow:SetShowLevel(level: number) + self.Variables["_tmpNowLevel"].Text = string.format("第%d关", level) + local levelData = Utils:GetIdDataFromJson(JsonLevel, level) + if levelData.type == 2 then + self.Variables["_imgBoss"].Visible = true + else + self.Variables["_imgBoss"].Visible = false + end +end + function MainWindow:OnOpenWindow() UIWindow.OnOpenWindow(self) @@ -41,6 +61,16 @@ function MainWindow:OnOpenWindow() table.insert(self.Connections, createCon) table.insert(self.Connections, chaCon) table.insert(self.Connections, attributeUpgradeCon) + + local playerDataFolder = Utils:WaitPlayerDataFolder(LocalPlayer) + local StatsFolder = playerDataFolder:WaitForChild("PlayerInfo"):WaitForChild("Stats") + local levelCon = StatsFolder.level.Changed:Connect(function(newValue) + self:SetShowLevel(newValue) + end) + + -- 初始值设置 + self:SetShowLevel(StatsFolder.level.Value) + table.insert(self.Connections, levelCon) end