更新
This commit is contained in:
parent
fdc6ee6a6e
commit
2c43aba4bf
147
RUNE_STATE_WINDOW_README.md
Normal file
147
RUNE_STATE_WINDOW_README.md
Normal file
@ -0,0 +1,147 @@
|
||||
# RuneStateWindow 符文状态窗口
|
||||
|
||||
## 📋 功能概述
|
||||
|
||||
RuneStateWindow是一个用于显示当前穿戴符文状态的UI窗口,主要功能包括:
|
||||
|
||||
1. **符文栏显示** - 根据当前穿戴装备显示符文列表
|
||||
2. **小丑牌动画** - 接收服务端符文执行记录后播放类似小丑牌的动画效果
|
||||
|
||||
## 🏗️ 文件结构
|
||||
|
||||
```
|
||||
src/StarterPlayerScripts/UI/Windows/RuneStateWindow/
|
||||
├── init.luau # 主窗口文件
|
||||
└── RuneShow.luau # 符文显示组件
|
||||
|
||||
src/StarterPlayerScripts/ClientMain/
|
||||
├── RuneExecutionClient.luau # 客户端接收符文执行记录
|
||||
└── TestRuneStateWindow.luau # 测试脚本
|
||||
```
|
||||
|
||||
## 🎮 使用方法
|
||||
|
||||
### 1. 打开符文状态窗口
|
||||
|
||||
```lua
|
||||
-- 通过UIManager打开窗口
|
||||
UIManager:OpenWindow("RuneStateWindow", {
|
||||
runeData = {
|
||||
{
|
||||
runeName = "RuneFireDamage",
|
||||
runeUniqueId = 1,
|
||||
level = 5,
|
||||
icon = "fire_icon"
|
||||
},
|
||||
{
|
||||
runeName = "RuneIceCoffin",
|
||||
runeUniqueId = 2,
|
||||
level = 3,
|
||||
icon = "ice_icon"
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 2. 接收符文执行记录
|
||||
|
||||
窗口会自动接收服务端发送的符文执行记录,并播放动画:
|
||||
|
||||
```lua
|
||||
-- 服务端发送的数据格式
|
||||
local executionRecords = {
|
||||
{
|
||||
runeName = "RuneFireDamage",
|
||||
runeUniqueId = 1,
|
||||
index = 1,
|
||||
timestamp = tick(),
|
||||
action = "Execute",
|
||||
attributesBefore = {attack = 100, hp = 1000},
|
||||
attributesAfter = {attack = 150, hp = 1000},
|
||||
behaviorListBefore = {"Attack"},
|
||||
behaviorListAfter = {"Attack", "FireDamage"},
|
||||
nextIndex = 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 测试功能
|
||||
|
||||
使用测试脚本可以快速验证功能:
|
||||
|
||||
- **按 R 键** - 打开符文状态窗口
|
||||
- **按 T 键** - 模拟接收符文执行记录
|
||||
- **按 C 键** - 关闭符文状态窗口
|
||||
|
||||
## 🎨 动画效果
|
||||
|
||||
### 小丑牌动画特点
|
||||
|
||||
1. **金色光效** - 符文激活时显示金色发光效果
|
||||
2. **缩放动画** - 符文图标会放大并旋转
|
||||
3. **粒子效果** - 中心产生黄色粒子扩散效果
|
||||
4. **顺序播放** - 多个符文按执行顺序依次播放动画
|
||||
|
||||
### 动画参数
|
||||
|
||||
- **动画时长**: 0.3秒
|
||||
- **缩放比例**: 1.5倍
|
||||
- **旋转角度**: 360度
|
||||
- **颜色**: 金色(#FFD700)和黄色(#FFFF00)
|
||||
|
||||
## 🔧 技术实现
|
||||
|
||||
### 核心组件
|
||||
|
||||
1. **RuneStateWindow** - 主窗口管理
|
||||
- 管理符文执行记录队列
|
||||
- 控制动画播放顺序
|
||||
- 处理窗口生命周期
|
||||
|
||||
2. **RuneShow** - 符文显示组件
|
||||
- 显示符文图标、名称、等级
|
||||
- 处理符文激活动画
|
||||
- 管理组件生命周期
|
||||
|
||||
3. **RuneExecutionClient** - 客户端接收器
|
||||
- 监听服务端符文执行记录
|
||||
- 转发数据到窗口组件
|
||||
|
||||
### 数据流程
|
||||
|
||||
```
|
||||
服务端符文执行 → RemoteEvent发送 → 客户端接收 → 窗口处理 → 动画播放
|
||||
```
|
||||
|
||||
## 🎯 扩展功能
|
||||
|
||||
### 可扩展的动画效果
|
||||
|
||||
1. **音效支持** - 添加符文激活音效
|
||||
2. **特效增强** - 添加更多视觉特效
|
||||
3. **交互功能** - 点击符文查看详情
|
||||
4. **状态显示** - 显示符文冷却时间
|
||||
|
||||
### 自定义动画
|
||||
|
||||
可以通过修改`CreateJokerCardEffect`方法来自定义动画效果:
|
||||
|
||||
```lua
|
||||
function RuneStateWindow:CreateJokerCardEffect(runeItem, record)
|
||||
-- 自定义动画逻辑
|
||||
-- 可以添加更多特效、音效等
|
||||
end
|
||||
```
|
||||
|
||||
## 🐛 注意事项
|
||||
|
||||
1. **UI预制体** - 需要创建对应的UI预制体`ui_w_rune_state`
|
||||
2. **符文数据** - 需要正确配置符文JSON数据
|
||||
3. **图标资源** - 需要上传对应的符文图标资源
|
||||
4. **性能优化** - 大量符文时注意动画性能
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
- **v1.0.0** - 初始版本,支持基础符文显示和小丑牌动画
|
||||
- 支持符文执行记录接收和播放
|
||||
- 支持测试脚本快速验证功能
|
BIN
excel/Rune.xlsx
BIN
excel/Rune.xlsx
Binary file not shown.
Binary file not shown.
@ -1,4 +1,5 @@
|
||||
[
|
||||
{"id":20000,"type":1,"icon":1,"nameId":20000,"behaviourName":"Attack","upgradeCost":[30000,5,0],"upgradeValue":[10,0],"recycle":[30000,0],"isInPool":null},
|
||||
{"id":20001,"type":1,"icon":1,"nameId":20001,"behaviourName":"SwordWave","upgradeCost":[30000,5,10],"upgradeValue":[10,200],"recycle":[30000,100],"isInPool":1}
|
||||
{"id":20001,"type":1,"icon":1,"nameId":20001,"behaviourName":"SwordWave","upgradeCost":[30000,5,10],"upgradeValue":[10,200],"recycle":[30000,100],"isInPool":1},
|
||||
{"id":61000,"type":1,"icon":1,"nameId":61000,"behaviourName":"IceCoffine","upgradeCost":[30000,5,0],"upgradeValue":[10,0],"recycle":[30000,0],"isInPool":null}
|
||||
]
|
@ -30,5 +30,5 @@
|
||||
{"id":53,"type":1,"specialType":null,"effectAttribute":"elementNumber","battleValue":[1,10],"iconId":29,"nameId":253},
|
||||
{"id":54,"type":1,"specialType":null,"effectAttribute":"elementDefNumber","battleValue":[1,10],"iconId":30,"nameId":254},
|
||||
{"id":55,"type":1,"specialType":null,"effectAttribute":"gemNumber","battleValue":[1,10],"iconId":31,"nameId":255},
|
||||
{"id":56,"type":1,"specialType":null,"effectAttribute":"runeNumber","battleValue":[1,10],"iconId":31,"nameId":256}
|
||||
{"id":56,"type":1,"specialType":null,"effectAttribute":"runeNumber","battleValue":[1,10],"iconId":32,"nameId":256}
|
||||
]
|
@ -1,5 +1,5 @@
|
||||
[
|
||||
{"id":60000,"quality":1,"type":1,"icon":1,"nameId":60000,"runeName":"RuneFireDamage","behaviorName":null,"recycle":[],"isInPool":1},
|
||||
{"id":61000,"quality":2,"type":1,"icon":1,"nameId":61000,"runeName":"RuneIceCoffin","behaviorName":"IceCoffin","recycle":[],"isInPool":1},
|
||||
{"id":61000,"quality":2,"type":1,"icon":1,"nameId":61000,"runeName":"RuneIceCoffin","behaviorName":"IceCoffine","recycle":[],"isInPool":1},
|
||||
{"id":62000,"quality":3,"type":1,"icon":1,"nameId":62000,"runeName":null,"behaviorName":null,"recycle":[],"isInPool":1}
|
||||
]
|
@ -60,6 +60,14 @@ local Temporary = CreateFolder("Temporary", workspace)
|
||||
local ProjectileCache = CreateFolder("ProjectileCache", Temporary)
|
||||
local Characters = CreateFolder("Characters", workspace)
|
||||
|
||||
-- 初始化ReplicatedStorage目录
|
||||
local EventsFolder = CreateFolder("Events", ReplicatedStorage)
|
||||
|
||||
-- 创建符文执行记录RemoteEvent
|
||||
local RE_RuneExecutionRecord = Instance.new("RemoteEvent")
|
||||
RE_RuneExecutionRecord.Name = "RE_RuneExecutionRecord"
|
||||
RE_RuneExecutionRecord.Parent = EventsFolder
|
||||
|
||||
-- Initially require all server-sided & shared modules
|
||||
-- 加载模块 ReplicatedStorage.Modules, ServerStorage.Modules
|
||||
for _, Location in {ReplicatedStorage.Modules, ServerStorage.Modules} do
|
||||
|
@ -7,20 +7,55 @@ local ServerStorage = game:GetService("ServerStorage")
|
||||
|
||||
--> Dependencies
|
||||
local TypeList = require(ServerStorage.Base.TypeList)
|
||||
local Communicate = require(ServerStorage.Modules.Tools.Communicate)
|
||||
local Utils = require(ReplicatedStorage.Tools.Utils)
|
||||
|
||||
|
||||
|
||||
function Rune:Init(PlayerAI: Player, Character: TypeList.Character, ScriptName: string)
|
||||
local self = {}
|
||||
setmetatable(self, Rune)
|
||||
self.PlayerAI = PlayerAI
|
||||
self.Character = Character
|
||||
self.ScriptName = ScriptName
|
||||
self.Player = self.Character.Player
|
||||
self.TriggerSlot = 0
|
||||
self.WearingSlot = 0
|
||||
self.TriggerTime = 0
|
||||
self.executionRecords = {}
|
||||
self.isRecording = false -- 记录开关
|
||||
return self
|
||||
end
|
||||
|
||||
-- 开始记录
|
||||
function Rune:StartRecording()
|
||||
self.isRecording = true
|
||||
self.executionRecords = {}
|
||||
end
|
||||
|
||||
-- 停止记录
|
||||
function Rune:StopRecording()
|
||||
self.isRecording = false
|
||||
end
|
||||
|
||||
-- 记录执行信息
|
||||
function Rune:RecordExecution(index: number, attributesBefore: table?, attributesAfter: table?, behaviorListBefore: table?, behaviorListAfter: table?, nextIndex: number?)
|
||||
if not self.isRecording then return end
|
||||
|
||||
table.insert(self.executionRecords, {
|
||||
runeName = self.ScriptName,
|
||||
runeUniqueId = self.TriggerSlot,
|
||||
index = index,
|
||||
timestamp = tick(),
|
||||
action = "Execute",
|
||||
attributesBefore = attributesBefore or {},
|
||||
attributesAfter = attributesAfter or {},
|
||||
behaviorListBefore = behaviorListBefore or {},
|
||||
behaviorListAfter = behaviorListAfter or {},
|
||||
nextIndex = nextIndex
|
||||
})
|
||||
end
|
||||
|
||||
-- 获取执行记录
|
||||
function Rune:GetExecutionRecords()
|
||||
return self.executionRecords
|
||||
end
|
||||
|
||||
-- 触发最开始事件
|
||||
@ -62,14 +97,25 @@ function Rune:Check(index: number, AttributesData: table?, BehaviorNameList: tab
|
||||
-- index: 当前符文在列表中的位置
|
||||
-- AttributesData: 属性数据,符文可以修改
|
||||
-- BehaviorNameList: 行为名称列表,符文可以修改
|
||||
return false -- 默认返回false,表示不可以执行
|
||||
-- 返回值: true表示可以执行,false表示跳过
|
||||
return false
|
||||
end
|
||||
|
||||
-- 执行事件
|
||||
function Rune:Execute(index: number, AttributesData: table?, BehaviorNameList: table?)
|
||||
-- 使用PlayerAI的专用方法,性能更好
|
||||
-- index: 当前符文在列表中的位置
|
||||
-- AttributesData: 属性数据,符文可以修改
|
||||
-- BehaviorNameList: 行为名称列表,符文可以修改
|
||||
-- 返回值: 下一个要执行的index,或者nil表示继续下一个
|
||||
|
||||
-- 记录执行前的状态
|
||||
local attributesBefore = Utils:DeepCopyTable(AttributesData or {})
|
||||
local behaviorListBefore = Utils:DeepCopyTable(BehaviorNameList or {})
|
||||
|
||||
-- 使用PlayerAI的专用方法
|
||||
local beginNextIndex = self.PlayerAI:TriggerAllRunesExcept(self, "OnTriggerBeginEvent", index, AttributesData, BehaviorNameList)
|
||||
if type(beginNextIndex) == "number" then
|
||||
self:RecordExecution(index, attributesBefore, AttributesData, behaviorListBefore, BehaviorNameList, beginNextIndex)
|
||||
return beginNextIndex
|
||||
end
|
||||
|
||||
@ -77,32 +123,35 @@ function Rune:Execute(index: number, AttributesData: table?, BehaviorNameList: t
|
||||
local nextIndex = self:OnExecute(index, AttributesData, BehaviorNameList)
|
||||
if type(nextIndex) == "number" then
|
||||
self.PlayerAI:TriggerAllRunesExcept(self, "OnTriggerEndEvent", index, AttributesData, BehaviorNameList)
|
||||
self:RecordExecution(index, attributesBefore, AttributesData, behaviorListBefore, BehaviorNameList, nextIndex)
|
||||
return nextIndex
|
||||
end
|
||||
|
||||
local endNextIndex = self.PlayerAI:TriggerAllRunesExcept(self, "OnTriggerEndEvent", index, AttributesData, BehaviorNameList)
|
||||
if type(endNextIndex) == "number" then
|
||||
self:RecordExecution(index, attributesBefore, AttributesData, behaviorListBefore, BehaviorNameList, endNextIndex)
|
||||
return endNextIndex
|
||||
end
|
||||
|
||||
self.TriggerTime = self.TriggerTime + 1
|
||||
return nextIndex -- 返回下一个要执行的index
|
||||
self:RecordExecution(index, attributesBefore, AttributesData, behaviorListBefore, BehaviorNameList, nextIndex)
|
||||
|
||||
return nextIndex
|
||||
end
|
||||
|
||||
-- 子类可以重写这个方法
|
||||
function Rune:OnExecute(index: number, AttributesData: table?, BehaviorNameList: table?)
|
||||
-- 默认实现,子类可以重写
|
||||
-- index: 当前符文在列表中的位置
|
||||
-- AttributesData: 属性数据,符文可以修改
|
||||
-- BehaviorNameList: 行为名称列表,符文可以修改
|
||||
-- 返回值: 下一个要执行的index,或者nil表示继续下一个
|
||||
return nil -- 默认继续下一个符文
|
||||
return nil
|
||||
end
|
||||
|
||||
-- 销毁
|
||||
function Rune:OnDestroy()
|
||||
self.executionRecords = nil
|
||||
self = nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
return Rune
|
@ -28,7 +28,7 @@ function IceCoffine:Init(PlayerAI, Character: TypeList.Character, Player: Player
|
||||
self.Mobs = nil
|
||||
setmetatable(self, IceCoffine)
|
||||
self.OrgCooldown = COOLDOWN
|
||||
self:StartCooldownTask()
|
||||
-- self:StartCooldownTask()
|
||||
|
||||
-- 客户端表现
|
||||
self:SendPerformanceEvent("Init", self.Player, script.Name, true, {})
|
||||
@ -40,8 +40,8 @@ function IceCoffine:Check(CheckInfo: table)
|
||||
self:CheckClean()
|
||||
|
||||
-- 当前血量<=20%时触发技能
|
||||
local maxHp = self.Character.Stats.MaxHp
|
||||
local currentHp = self.Character.Stats.Hp
|
||||
local maxHp = self.Character.Config.maxhp
|
||||
local currentHp = self.Character.Config.hp
|
||||
local recoverHp = maxHp * 0.2
|
||||
if currentHp <= recoverHp then
|
||||
self.CheckData = {}
|
||||
@ -58,7 +58,7 @@ function IceCoffine:Execute()
|
||||
-- cd放前面之后发送事件才能正常记录cd
|
||||
self:StartCooldownTask()
|
||||
|
||||
local maxHp = self.Character.Stats.MaxHp
|
||||
local maxHp = self.Character.Config.MaxHp
|
||||
local recoverHp = math.floor(maxHp * (self.PlayerAI:GetSharedData("IceCoffin_MaxRecover") / 100))
|
||||
DamageProxy:Heal(self.Character, self.Character, recoverHp)
|
||||
task.wait(0.5)
|
||||
|
@ -1,17 +1,19 @@
|
||||
--> Services
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
|
||||
--> Dependencies
|
||||
local Utils = require(ReplicatedStorage.Tools.Utils)
|
||||
local TypeList = require(ServerStorage.Base.TypeList)
|
||||
local Rune = require(ServerStorage.Base.Rune)
|
||||
|
||||
local RuneFireDamage = {}
|
||||
RuneFireDamage.__index = RuneFireDamage
|
||||
setmetatable(RuneFireDamage, {__index = Rune})
|
||||
|
||||
|
||||
function RuneFireDamage:Init(PlayerAI, Character: TypeList.Character, Player: Player)
|
||||
function RuneFireDamage:Init(PlayerAI, Character: TypeList.Character)
|
||||
local self = Rune:Init(PlayerAI, Character, script.Name)
|
||||
self.Player = Player
|
||||
setmetatable(self, RuneFireDamage)
|
||||
|
||||
return self
|
||||
|
@ -1,17 +1,19 @@
|
||||
--> Services
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
|
||||
--> Dependencies
|
||||
local Utils = require(ReplicatedStorage.Tools.Utils)
|
||||
local TypeList = require(ServerStorage.Base.TypeList)
|
||||
local Rune = require(ServerStorage.Base.Rune)
|
||||
|
||||
local RuneIceCoffin = {}
|
||||
RuneIceCoffin.__index = RuneIceCoffin
|
||||
setmetatable(RuneIceCoffin, {__index = Rune})
|
||||
|
||||
|
||||
function RuneIceCoffin:Init(PlayerAI, Character: TypeList.Character, Player: Player)
|
||||
function RuneIceCoffin:Init(PlayerAI, Character: TypeList.Character)
|
||||
local self = Rune:Init(PlayerAI, Character, script.Name)
|
||||
self.Player = Player
|
||||
setmetatable(self, RuneIceCoffin)
|
||||
|
||||
return self
|
||||
|
@ -95,7 +95,7 @@ end
|
||||
|
||||
-- 动态添加行为
|
||||
function PlayerAI:AddBehaviour(BehaviourName: string, WearingSlot: number?)
|
||||
if not Behaviours[BehaviourName] then warn("Behaviour not found") return end
|
||||
if not Behaviours[BehaviourName] then warn("Behaviour not found", BehaviourName) return end
|
||||
local newBehaviour = Behaviours[BehaviourName]:Init(self, self.Character, self.Player)
|
||||
newBehaviour.WearingSlot = WearingSlot or 4
|
||||
self.BehaviourList[BehaviourName] = newBehaviour
|
||||
|
@ -185,7 +185,6 @@ function PlayerFightProxy:UpdatePlayerFightData(Player: Player)
|
||||
end
|
||||
|
||||
-- 更新玩家属性
|
||||
-- print(AttributesData)
|
||||
for AttributeName, AttributeValue in AttributesData do
|
||||
-- TODO:这里可能涉及到战斗时更换装备的属性处理,还需要再函数内部再根据剩余百分比数值变化
|
||||
PlayerRole:ChangeAttributeValue(AttributeName, AttributeValue)
|
||||
@ -205,7 +204,6 @@ function PlayerFightProxy:UpdatePlayerFightData(Player: Player)
|
||||
playerAI:AddBehaviour(behaviorName)
|
||||
end
|
||||
playerAI:AddBehaviour("Move")
|
||||
-- playerAI:AddBehaviour("SwordWave")
|
||||
playerAI:AddBehaviour("Attack")
|
||||
|
||||
|
||||
|
@ -1,5 +1,11 @@
|
||||
local RuneCalculation = {}
|
||||
|
||||
--> Services
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
--> Events
|
||||
local RE_RuneExecutionRecord = ReplicatedStorage.Events:WaitForChild("RE_RuneExecutionRecord")
|
||||
|
||||
-- 处理符文机制主函数
|
||||
function RuneCalculation:GetRuneAttributes(Player: Player, PlayerAI: table, AttributesData: table, BehaviorNameList: table)
|
||||
if not Player and not PlayerAI then warn("Player or PlayerAI not found") return end
|
||||
@ -19,25 +25,52 @@ function RuneCalculation:GetRuneAttributes(Player: Player, PlayerAI: table, Attr
|
||||
PlayerAI:ClearSharedData()
|
||||
PlayerAI:ClearAllRune()
|
||||
for wearingSlot, runeName in wearingRuneName do PlayerAI:AddRune(runeName, wearingSlot) end
|
||||
|
||||
-- 开始记录
|
||||
for runeName, rune in pairs(PlayerAI.RuneList) do
|
||||
rune:StartRecording()
|
||||
end
|
||||
|
||||
-- 触发开始事件,并检查是否有符文要控制流程
|
||||
local startNextIndex = PlayerAI:ForEachRune(function(runeName, triggerSlot, rune)
|
||||
local result = rune:OnStartEvent(runeName, triggerSlot, AttributesData, BehaviorNameList)
|
||||
if type(result) == "number" then
|
||||
return result -- 返回要跳转的index
|
||||
return result
|
||||
end
|
||||
end)
|
||||
|
||||
local index = 1
|
||||
local maxSteps = 1000 -- 防止无限循环
|
||||
local maxSteps = 1000
|
||||
|
||||
-- 如果开始事件指定了起始位置,使用它
|
||||
if type(startNextIndex) == "number" then
|
||||
index = startNextIndex
|
||||
end
|
||||
|
||||
-- 执行符文循环
|
||||
self:ExecuteRuneLoop(PlayerAI, wearingRuneName, wearingRuneUniqueId, index, maxSteps)
|
||||
self:ExecuteRuneLoop(PlayerAI, wearingRuneName, wearingRuneUniqueId, index, maxSteps, AttributesData, BehaviorNameList)
|
||||
|
||||
-- 收集所有符文的执行记录
|
||||
local allExecutionRecords = {}
|
||||
for runeName, rune in pairs(PlayerAI.RuneList) do
|
||||
local records = rune:GetExecutionRecords()
|
||||
if records and #records > 0 then
|
||||
for _, record in ipairs(records) do
|
||||
table.insert(allExecutionRecords, record)
|
||||
end
|
||||
end
|
||||
rune:StopRecording()
|
||||
end
|
||||
|
||||
-- 统一发送执行记录到前端
|
||||
if #allExecutionRecords > 0 then
|
||||
local success, error = pcall(function()
|
||||
RE_RuneExecutionRecord:FireClient(Player, allExecutionRecords)
|
||||
end)
|
||||
|
||||
if not success then
|
||||
warn("RuneCalculation: 发送符文执行记录失败:", error)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 执行符文循环的辅助函数
|
||||
@ -49,31 +82,28 @@ function RuneCalculation:ExecuteRuneLoop(PlayerAI: table, wearingRuneName: table
|
||||
if result then
|
||||
local nextIndex = PlayerAI:TriggerRune(wearingRuneName[index], "Execute", index, AttributesData, BehaviorNameList)
|
||||
|
||||
-- 根据返回值决定下一个index
|
||||
if type(nextIndex) == "number" then
|
||||
index = nextIndex -- 符文指定了下一个位置
|
||||
index = nextIndex
|
||||
else
|
||||
index += 1 -- 默认继续下一个
|
||||
index += 1
|
||||
end
|
||||
else
|
||||
index += 1
|
||||
end
|
||||
maxSteps -= 1 -- 防止无限循环
|
||||
maxSteps -= 1
|
||||
end
|
||||
|
||||
-- 触发结束事件,并检查是否有符文要控制流程
|
||||
local endNextIndex = PlayerAI:ForEachRune(function(runeName, triggerSlot, rune)
|
||||
local result = rune:OnEndEvent(runeName, triggerSlot, AttributesData, BehaviorNameList)
|
||||
if type(result) == "number" then
|
||||
return result -- 返回要跳转的index
|
||||
return result
|
||||
end
|
||||
end)
|
||||
|
||||
-- 如果结束事件指定了要跳转的位置,重新开始循环
|
||||
if type(endNextIndex) == "number" and endNextIndex <= #wearingRuneUniqueId and maxSteps > 0 then
|
||||
self:ExecuteRuneLoop(PlayerAI, wearingRuneName, wearingRuneUniqueId, endNextIndex, maxSteps, AttributesData, BehaviorNameList)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return RuneCalculation
|
@ -258,16 +258,16 @@ function RuneProxy:GetPlayerWearingRuneData(Player: Player)
|
||||
for _, RuneData in ArchiveProxy.pData[Player.UserId][STORE_NAME] do
|
||||
if tonumber(RuneData.wearing) > 0 and table.find(wearingEquipments, RuneData.wearing) then
|
||||
table.insert(wearingRuneUniqueId, RuneData.id)
|
||||
local RuneData = Utils:GetIdDataFromJson(JsonRune, RuneData.orgId)
|
||||
if RuneData.runeName then
|
||||
wearingRuneName[RuneData.wearingSlot] = RuneData.runeName
|
||||
local JsonRuneData = Utils:GetIdDataFromJson(JsonRune, RuneData.orgId)
|
||||
if JsonRuneData and JsonRuneData.runeName then
|
||||
wearingRuneName[RuneData.wearingSlot] = JsonRuneData.runeName
|
||||
end
|
||||
if RuneData.behaviorName then
|
||||
table.insert(wearingRuneBehaviorName, RuneData.behaviorName)
|
||||
if JsonRuneData and JsonRuneData.behaviorName then
|
||||
table.insert(wearingRuneBehaviorName, JsonRuneData.behaviorName)
|
||||
end
|
||||
end
|
||||
end
|
||||
return wearingRuneUniqueId, wearingRuneName
|
||||
return wearingRuneUniqueId, wearingRuneName, wearingRuneBehaviorName
|
||||
end
|
||||
|
||||
-- 获取对应装备槽位上的技能
|
||||
|
@ -123,5 +123,6 @@ end)
|
||||
-- 打开默认界面
|
||||
UIManager:OpenWindow("MainWindow")
|
||||
UIManager:OpenWindow("TipsWindow")
|
||||
UIManager:OpenWindow("RuneStateWindow")
|
||||
|
||||
return PerformanceClient
|
70
src/StarterPlayerScripts/ClientMain/TestRuneStateWindow.luau
Normal file
70
src/StarterPlayerScripts/ClientMain/TestRuneStateWindow.luau
Normal file
@ -0,0 +1,70 @@
|
||||
--> Services
|
||||
local Players = game:GetService("Players")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
--> Dependencies
|
||||
local UIManager = require(script.Parent.Parent.UI.UIManager)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
|
||||
-- 测试执行记录
|
||||
local testExecutionRecords = {
|
||||
{
|
||||
runeName = "RuneFireDamage",
|
||||
runeUniqueId = 1,
|
||||
index = 1,
|
||||
timestamp = tick(),
|
||||
action = "Execute",
|
||||
attributesBefore = {attack = 100, hp = 1000, atkSpeed = 100},
|
||||
attributesAfter = {attack = 150, hp = 1000, atkSpeed = 120},
|
||||
behaviorListBefore = {"Attack"},
|
||||
behaviorListAfter = {"Attack", "FireDamage"},
|
||||
nextIndex = 2
|
||||
},
|
||||
{
|
||||
runeName = "RuneIceCoffin",
|
||||
runeUniqueId = 2,
|
||||
index = 2,
|
||||
timestamp = tick(),
|
||||
action = "Execute",
|
||||
attributesBefore = {attack = 150, hp = 1000, atkSpeed = 120},
|
||||
attributesAfter = {attack = 150, hp = 1200, atkSpeed = 120, fireAtk = 50},
|
||||
behaviorListBefore = {"Attack", "FireDamage"},
|
||||
behaviorListAfter = {"Attack", "FireDamage", "IceCoffin"},
|
||||
nextIndex = nil
|
||||
}
|
||||
}
|
||||
|
||||
-- 键盘输入测试
|
||||
UserInputService.InputBegan:Connect(function(input, gameProcessed)
|
||||
if gameProcessed then return end
|
||||
|
||||
if input.KeyCode == Enum.KeyCode.R then
|
||||
-- 打开符文状态窗口
|
||||
print("打开符文状态窗口")
|
||||
UIManager:OpenWindow("RuneStateWindow")
|
||||
|
||||
elseif input.KeyCode == Enum.KeyCode.T then
|
||||
-- 模拟接收符文执行记录
|
||||
print("模拟符文执行记录")
|
||||
local runeStateWindow = UIManager:GetWindow("RuneStateWindow")
|
||||
if runeStateWindow then
|
||||
runeStateWindow:OnRuneExecutionRecord(testExecutionRecords)
|
||||
end
|
||||
|
||||
elseif input.KeyCode == Enum.KeyCode.C then
|
||||
-- 关闭符文状态窗口
|
||||
print("关闭符文状态窗口")
|
||||
UIManager:CloseWindow("RuneStateWindow")
|
||||
end
|
||||
end)
|
||||
|
||||
print("符文状态窗口测试脚本已启动")
|
||||
print("按 R 键打开符文状态窗口")
|
||||
print("按 T 键模拟符文执行记录")
|
||||
print("按 C 键关闭符文状态窗口")
|
||||
|
||||
-- 返回一个空表作为模块返回值
|
||||
return {}
|
@ -9,6 +9,7 @@ UIManager.ExcludeFromStack = { -- 不受堆栈影响的窗口列表
|
||||
"TipsWindow", -- 主窗口
|
||||
"AbilityStateWindow",
|
||||
"LevelStageWindow",
|
||||
"RuneStateWindow", -- 符文状态窗口
|
||||
-- 可以继续添加其他窗口名称
|
||||
}
|
||||
|
||||
@ -129,6 +130,11 @@ function UIManager:IsOpened(WindowName: string)
|
||||
return UIManager.Instances[WindowName] ~= nil
|
||||
end
|
||||
|
||||
-- 获取窗口实例
|
||||
function UIManager:GetWindow(WindowName: string)
|
||||
return UIManager.Instances[WindowName]
|
||||
end
|
||||
|
||||
function UIManager:SetData(WindowName: string, Data: table)
|
||||
if not UIManager.Instances[WindowName] then
|
||||
warn("UIManager:SetData() 窗口不存在:" .. WindowName)
|
||||
|
@ -0,0 +1,151 @@
|
||||
local RuneShow = {}
|
||||
RuneShow.__index = RuneShow
|
||||
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local Utils = require(ReplicatedStorage.Tools.Utils)
|
||||
local Localization = require(ReplicatedStorage.Tools.Localization)
|
||||
local JsonRune = require(ReplicatedStorage.Json.Rune)
|
||||
local Signal = require(ReplicatedStorage.Tools.Signal)
|
||||
|
||||
local showRuneSignal = Signal.new(Signal.ENUM.SHOW_RUNE)
|
||||
|
||||
function RuneShow:Init(data: table)
|
||||
local self = {}
|
||||
self.Data = data
|
||||
self.Variables = {
|
||||
["_imgIcon"] = 0,
|
||||
["_imgMask"] = 0,
|
||||
["_tmpName"] = 0,
|
||||
["_tmpLevel"] = 0,
|
||||
}
|
||||
self.Task = nil
|
||||
self.SignalConnections = {}
|
||||
|
||||
local con = showRuneSignal:Connect(function(RuneName, RuneUniqueId)
|
||||
if RuneName == self.Data.runeName and RuneUniqueId == self.Data.runeUniqueId then
|
||||
self:Refresh()
|
||||
end
|
||||
end)
|
||||
table.insert(self.SignalConnections, con)
|
||||
|
||||
setmetatable(self, RuneShow)
|
||||
return self
|
||||
end
|
||||
|
||||
-- 初始化完成后的回调
|
||||
function RuneShow:OnInitFinish()
|
||||
end
|
||||
|
||||
function RuneShow:Refresh()
|
||||
if self.Task then
|
||||
task.cancel(self.Task)
|
||||
self.Task = nil
|
||||
end
|
||||
|
||||
if self.Data.runeName ~= nil then
|
||||
-- 获取符文数据
|
||||
local runeData = Utils:GetSpecialKeyDataFromJson(JsonRune, "runeName", self.Data.runeName)
|
||||
|
||||
-- 设置符文图标
|
||||
if runeData and runeData.icon then
|
||||
self.Variables._imgIcon.Image = Localization:GetImageData(runeData.icon)
|
||||
else
|
||||
-- 使用默认图标
|
||||
self.Variables._imgIcon.Image = "rbxassetid://0"
|
||||
end
|
||||
|
||||
-- 设置符文名称
|
||||
if runeData and runeData.nameId then
|
||||
-- 通过nameId获取本地化文本
|
||||
self.Variables._tmpName.Text = Localization:GetLanguageData(runeData.nameId) or "未知符文"
|
||||
else
|
||||
-- 使用符文名称作为显示文本
|
||||
self.Variables._tmpName.Text = self.Data.runeName or "未知符文"
|
||||
end
|
||||
|
||||
-- 设置符文等级
|
||||
if self.Data.level then
|
||||
self.Variables._tmpLevel.Text = "Lv." .. tostring(self.Data.level)
|
||||
else
|
||||
self.Variables._tmpLevel.Text = "Lv.1"
|
||||
end
|
||||
|
||||
-- 设置符文背景颜色
|
||||
if runeData and runeData.quality then
|
||||
local bgColor = Localization:GetRuneQualityBgColor(runeData.quality)
|
||||
if bgColor and self.Variables._imgIcon then
|
||||
self.Variables._imgIcon.BackgroundColor3 = bgColor
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.Variables._imgIcon.Visible = true
|
||||
self.Variables._imgMask.Visible = false
|
||||
end
|
||||
|
||||
-- 播放激活动画
|
||||
function RuneShow:PlayActivateAnimation()
|
||||
-- 创建激活效果
|
||||
local effect = Instance.new("Frame")
|
||||
effect.Size = UDim2.new(1, 0, 1, 0)
|
||||
effect.Position = UDim2.new(0, 0, 0, 0)
|
||||
effect.BackgroundColor3 = Color3.fromRGB(255, 215, 0) -- 金色
|
||||
effect.BackgroundTransparency = 0.3
|
||||
effect.BorderSizePixel = 0
|
||||
effect.Parent = self.UIRoot
|
||||
|
||||
-- 创建粒子效果
|
||||
local particle = Instance.new("Frame")
|
||||
particle.Size = UDim2.new(0.1, 0, 0.1, 0)
|
||||
particle.Position = UDim2.new(0.45, 0, 0.45, 0)
|
||||
particle.BackgroundColor3 = Color3.fromRGB(255, 255, 0) -- 黄色
|
||||
particle.BackgroundTransparency = 0
|
||||
particle.BorderSizePixel = 0
|
||||
particle.Parent = effect
|
||||
|
||||
-- 动画效果
|
||||
local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
|
||||
|
||||
-- 主效果动画
|
||||
local mainTween = game:GetService("TweenService"):Create(effect, tweenInfo, {
|
||||
Size = UDim2.new(1.5, 0, 1.5, 0),
|
||||
BackgroundTransparency = 1
|
||||
})
|
||||
|
||||
-- 粒子动画
|
||||
local particleTween = game:GetService("TweenService"):Create(particle, tweenInfo, {
|
||||
Size = UDim2.new(0.5, 0, 0.5, 0),
|
||||
BackgroundTransparency = 1
|
||||
})
|
||||
|
||||
-- 播放动画
|
||||
mainTween:Play()
|
||||
particleTween:Play()
|
||||
|
||||
-- 动画结束后清理
|
||||
mainTween.Completed:Connect(function()
|
||||
effect:Destroy()
|
||||
end)
|
||||
end
|
||||
|
||||
function RuneShow:Destroy()
|
||||
if self.Task then
|
||||
task.cancel(self.Task)
|
||||
self.Task = nil
|
||||
end
|
||||
|
||||
-- 清理信号连接
|
||||
for _, connection in pairs(self.SignalConnections) do
|
||||
if connection then
|
||||
connection:Disconnect()
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs(self) do
|
||||
self[k] = nil
|
||||
end
|
||||
self = nil
|
||||
end
|
||||
|
||||
return RuneShow
|
361
src/StarterPlayerScripts/UI/Windows/RuneStateWindow/init.luau
Normal file
361
src/StarterPlayerScripts/UI/Windows/RuneStateWindow/init.luau
Normal file
@ -0,0 +1,361 @@
|
||||
--> Services
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
--> Dependencies
|
||||
local UIWindow = require(ReplicatedStorage.Base.UIWindow)
|
||||
local UIEnums = require(ReplicatedStorage.Base.UIEnums)
|
||||
local Localization = require(ReplicatedStorage.Tools.Localization)
|
||||
local Utils = require(ReplicatedStorage.Tools.Utils)
|
||||
|
||||
--> Json
|
||||
local JsonAttributes = require(ReplicatedStorage.Json.Attributes)
|
||||
|
||||
--> Components
|
||||
local RuneShow = require(script.RuneShow)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local RuneStateWindow = {}
|
||||
RuneStateWindow.__index = RuneStateWindow
|
||||
setmetatable(RuneStateWindow, {__index = UIWindow})
|
||||
|
||||
function RuneStateWindow:Init(UIManager: table, Data: table?)
|
||||
local self = UIWindow:Init(UIManager, Data)
|
||||
setmetatable(self, RuneStateWindow)
|
||||
self.Variables = {
|
||||
["__listRune"] = 0,
|
||||
}
|
||||
self.UIRootName = "ui_w_rune_state"
|
||||
self.UIParentName = UIEnums.UIParent.UIRoot
|
||||
|
||||
-- 符文执行记录队列
|
||||
self.runeExecutionQueue = {}
|
||||
self.isPlayingAnimation = false
|
||||
|
||||
-- 事件连接
|
||||
self.runeExecutionConnection = nil
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function RuneStateWindow:OnOpenWindow()
|
||||
UIWindow.OnOpenWindow(self)
|
||||
|
||||
self.Variables["__listRune"]:AddComponent(RuneShow)
|
||||
|
||||
-- 连接符文执行记录事件
|
||||
self:ConnectRuneExecutionEvent()
|
||||
|
||||
-- 初始化符文列表
|
||||
self:RefreshRuneList()
|
||||
end
|
||||
|
||||
function RuneStateWindow:OnCloseWindow()
|
||||
UIWindow.OnCloseWindow(self)
|
||||
|
||||
self.Variables["__listRune"]:Clean()
|
||||
|
||||
-- 断开符文执行记录事件连接
|
||||
self:DisconnectRuneExecutionEvent()
|
||||
end
|
||||
|
||||
-- 刷新符文列表
|
||||
function RuneStateWindow:RefreshRuneList()
|
||||
-- 这里需要从服务端获取当前穿戴的符文数据
|
||||
-- 暂时使用模拟数据
|
||||
local runeData = self:GetWearingRuneData()
|
||||
self.Variables["__listRune"]:SetData(runeData)
|
||||
print("刷新符文列表", runeData)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- 获取穿戴的符文数据
|
||||
function RuneStateWindow:GetWearingRuneData()
|
||||
-- 从传入的数据中获取符文信息
|
||||
if self.Data and self.Data.runeData then
|
||||
return self.Data.runeData
|
||||
end
|
||||
|
||||
-- 从ReplicatedStorage获取当前穿戴的符文
|
||||
local runeData = {}
|
||||
local Players = game:GetService("Players")
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
|
||||
-- 获取玩家数据文件夹
|
||||
local PlayerDataFolder = ReplicatedStorage:WaitForChild("PlayerData")
|
||||
local PlayerFolder = PlayerDataFolder:FindFirstChild(LocalPlayer.UserId)
|
||||
if not PlayerFolder then return runeData end
|
||||
|
||||
-- 获取符文文件夹
|
||||
local RuneFolder = PlayerFolder:FindFirstChild("Rune")
|
||||
if not RuneFolder then return runeData end
|
||||
|
||||
-- 遍历所有符文,找到穿戴中的
|
||||
for _, runeInstance in pairs(RuneFolder:GetChildren()) do
|
||||
local wearing = runeInstance:GetAttribute("wearing")
|
||||
if wearing and tonumber(wearing) > 0 then
|
||||
local runeInfo = {
|
||||
runeName = runeInstance:GetAttribute("runeName"),
|
||||
runeUniqueId = tonumber(runeInstance.Name),
|
||||
level = runeInstance:GetAttribute("level") or 1,
|
||||
wearingSlot = runeInstance:GetAttribute("wearingSlot") or 1
|
||||
}
|
||||
table.insert(runeData, runeInfo)
|
||||
end
|
||||
end
|
||||
|
||||
-- 按穿戴槽位排序
|
||||
table.sort(runeData, function(a, b)
|
||||
return a.wearingSlot < b.wearingSlot
|
||||
end)
|
||||
|
||||
return runeData
|
||||
end
|
||||
|
||||
-- 接收符文执行记录
|
||||
function RuneStateWindow:OnRuneExecutionRecord(executionRecords: table)
|
||||
-- 自动刷新符文列表(获取最新的穿戴符文数据)
|
||||
self:RefreshRuneList()
|
||||
|
||||
-- 将执行记录添加到队列
|
||||
for _, record in ipairs(executionRecords) do
|
||||
table.insert(self.runeExecutionQueue, record)
|
||||
end
|
||||
|
||||
-- 开始播放动画
|
||||
if not self.isPlayingAnimation then
|
||||
self:PlayRuneAnimation()
|
||||
end
|
||||
end
|
||||
|
||||
-- 播放符文动画
|
||||
function RuneStateWindow:PlayRuneAnimation()
|
||||
if #self.runeExecutionQueue == 0 then
|
||||
self.isPlayingAnimation = false
|
||||
return
|
||||
end
|
||||
|
||||
self.isPlayingAnimation = true
|
||||
local record = table.remove(self.runeExecutionQueue, 1)
|
||||
|
||||
-- 播放小丑牌动画
|
||||
self:PlayJokerCardAnimation(record)
|
||||
end
|
||||
|
||||
-- 播放小丑牌动画
|
||||
function RuneStateWindow:PlayJokerCardAnimation(record: table)
|
||||
-- 找到对应的符文UI元素
|
||||
local runeItem = self:FindRuneItem(record.runeName, record.runeUniqueId)
|
||||
if not runeItem then
|
||||
-- 如果找不到符文,直接播放下一个
|
||||
task.wait(0.5) -- 短暂延迟
|
||||
self:PlayRuneAnimation()
|
||||
return
|
||||
end
|
||||
|
||||
-- 创建动画效果
|
||||
self:CreateJokerCardEffect(runeItem, record)
|
||||
end
|
||||
|
||||
-- 查找符文UI元素
|
||||
function RuneStateWindow:FindRuneItem(runeName: string, runeUniqueId: number)
|
||||
-- 在符文列表中查找对应的符文
|
||||
local runeList = self.Variables["__listRune"]
|
||||
if runeList and runeList.Instances then
|
||||
for _, component in pairs(runeList.Instances) do
|
||||
if component.Data and component.Data.runeName == runeName and component.Data.runeUniqueId == runeUniqueId then
|
||||
return component
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- 创建小丑牌动画效果
|
||||
function RuneStateWindow:CreateJokerCardEffect(runeItem: table, record: table)
|
||||
-- 获取符文UI根节点
|
||||
local runeUI = runeItem.UIRoot
|
||||
if not runeUI then
|
||||
return
|
||||
end
|
||||
|
||||
-- 创建动画效果
|
||||
local effect = Instance.new("Frame")
|
||||
effect.Size = UDim2.new(1, 0, 1, 0)
|
||||
effect.Position = UDim2.new(0, 0, 0, 0)
|
||||
effect.BackgroundColor3 = Color3.fromRGB(255, 215, 0) -- 金色
|
||||
effect.BackgroundTransparency = 0.5
|
||||
effect.BorderSizePixel = 0
|
||||
effect.Parent = runeUI
|
||||
|
||||
-- 创建发光效果
|
||||
local glow = Instance.new("Frame")
|
||||
glow.Size = UDim2.new(1.2, 0, 1.2, 0)
|
||||
glow.Position = UDim2.new(-0.1, 0, -0.1, 0)
|
||||
glow.BackgroundColor3 = Color3.fromRGB(255, 255, 0) -- 黄色
|
||||
glow.BackgroundTransparency = 0.8
|
||||
glow.BorderSizePixel = 0
|
||||
glow.Parent = effect
|
||||
|
||||
-- 创建属性变化显示
|
||||
self:CreateAttributeChangeDisplay(runeUI, record)
|
||||
|
||||
-- 动画效果
|
||||
local tweenInfo = TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
|
||||
|
||||
-- 缩放动画
|
||||
local scaleTween = game:GetService("TweenService"):Create(effect, tweenInfo, {
|
||||
Size = UDim2.new(1.5, 0, 1.5, 0),
|
||||
BackgroundTransparency = 0.9
|
||||
})
|
||||
|
||||
-- 旋转动画
|
||||
local rotationTween = game:GetService("TweenService"):Create(effect, tweenInfo, {
|
||||
Rotation = 360
|
||||
})
|
||||
|
||||
-- 播放动画
|
||||
scaleTween:Play()
|
||||
rotationTween:Play()
|
||||
|
||||
-- 动画结束后清理
|
||||
scaleTween.Completed:Connect(function()
|
||||
effect:Destroy()
|
||||
-- 播放下一个动画
|
||||
task.wait(0.2)
|
||||
self:PlayRuneAnimation()
|
||||
end)
|
||||
end
|
||||
|
||||
-- 创建属性变化显示
|
||||
function RuneStateWindow:CreateAttributeChangeDisplay(runeUI: Instance, record: table)
|
||||
-- 收集所有属性变化
|
||||
local attributeChanges = {}
|
||||
|
||||
-- 检查属性变化
|
||||
if record.attributesBefore and record.attributesAfter then
|
||||
for attrName, afterValue in pairs(record.attributesAfter) do
|
||||
local beforeValue = record.attributesBefore[attrName] or 0
|
||||
local change = afterValue - beforeValue
|
||||
if change ~= 0 then
|
||||
-- 通过effectAttribute查找对应的nameId
|
||||
local attributeData = Utils:GetSpecialKeyDataFromJson(JsonAttributes, "effectAttribute", attrName)
|
||||
local attributeName = attrName -- 默认使用原始名称
|
||||
|
||||
if attributeData and attributeData.nameId then
|
||||
-- 通过nameId获取本地化文本
|
||||
attributeName = Localization:GetLanguageData(attributeData.nameId) or attrName
|
||||
end
|
||||
|
||||
table.insert(attributeChanges, {
|
||||
name = attributeName,
|
||||
change = change
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 如果没有属性变化,直接返回
|
||||
if #attributeChanges == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
-- 创建统一的属性变化显示
|
||||
self:CreateAttributeChangeContainer(runeUI, attributeChanges)
|
||||
end
|
||||
|
||||
-- 创建属性变化容器
|
||||
function RuneStateWindow:CreateAttributeChangeContainer(runeUI: Instance, attributeChanges: table)
|
||||
-- 计算容器高度
|
||||
local containerHeight = #attributeChanges * 25 + 10
|
||||
|
||||
-- 创建属性变化显示容器
|
||||
local changeContainer = Instance.new("Frame")
|
||||
changeContainer.Size = UDim2.new(0, 160, 0, containerHeight)
|
||||
changeContainer.Position = UDim2.new(0.5, -80, 0, -30)
|
||||
changeContainer.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
|
||||
changeContainer.BackgroundTransparency = 0.2
|
||||
changeContainer.BorderSizePixel = 0
|
||||
changeContainer.Parent = runeUI
|
||||
|
||||
-- 创建圆角
|
||||
local corner = Instance.new("UICorner")
|
||||
corner.CornerRadius = UDim.new(0, 8)
|
||||
corner.Parent = changeContainer
|
||||
|
||||
-- 创建边框
|
||||
local stroke = Instance.new("UIStroke")
|
||||
stroke.Color = Color3.fromRGB(255, 215, 0)
|
||||
stroke.Thickness = 1.5
|
||||
stroke.Parent = changeContainer
|
||||
|
||||
-- 创建属性变化文本
|
||||
for i, change in ipairs(attributeChanges) do
|
||||
local changeText = Instance.new("TextLabel")
|
||||
changeText.Size = UDim2.new(1, -10, 0, 20)
|
||||
changeText.Position = UDim2.new(0, 5, 0, 5 + (i-1) * 25)
|
||||
changeText.Text = string.format("%s +%d", change.name, change.change)
|
||||
changeText.TextColor3 = change.change > 0 and Color3.fromRGB(0, 255, 100) or Color3.fromRGB(255, 100, 100)
|
||||
changeText.TextScaled = true
|
||||
changeText.Font = Enum.Font.SourceSansBold
|
||||
changeText.BackgroundTransparency = 1
|
||||
changeText.Parent = changeContainer
|
||||
end
|
||||
|
||||
-- 创建向上移动动画
|
||||
local moveTween = game:GetService("TweenService"):Create(changeContainer, TweenInfo.new(2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {
|
||||
Position = UDim2.new(0.5, -80, 0, -150),
|
||||
BackgroundTransparency = 1
|
||||
})
|
||||
|
||||
-- 播放动画
|
||||
moveTween:Play()
|
||||
|
||||
-- 动画结束后清理
|
||||
moveTween.Completed:Connect(function()
|
||||
changeContainer:Destroy()
|
||||
end)
|
||||
end
|
||||
|
||||
-- 连接符文执行记录事件
|
||||
function RuneStateWindow:ConnectRuneExecutionEvent()
|
||||
-- 确保只连接一次
|
||||
if self.runeExecutionConnection then
|
||||
return
|
||||
end
|
||||
|
||||
-- 等待RemoteEvent
|
||||
local RE_RuneExecutionRecord = ReplicatedStorage.Events:WaitForChild("RE_RuneExecutionRecord")
|
||||
|
||||
-- 连接事件
|
||||
self.runeExecutionConnection = RE_RuneExecutionRecord.OnClientEvent:Connect(function(executionRecords: table)
|
||||
print("收到符文执行记录:", executionRecords)
|
||||
|
||||
-- 发送执行记录到窗口
|
||||
self:OnRuneExecutionRecord(executionRecords)
|
||||
end)
|
||||
end
|
||||
|
||||
-- 断开符文执行记录事件
|
||||
function RuneStateWindow:DisconnectRuneExecutionEvent()
|
||||
if self.runeExecutionConnection then
|
||||
self.runeExecutionConnection:Disconnect()
|
||||
self.runeExecutionConnection = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- 销毁窗口
|
||||
function RuneStateWindow:Destroy()
|
||||
-- 清理动画队列
|
||||
self.runeExecutionQueue = {}
|
||||
self.isPlayingAnimation = false
|
||||
|
||||
-- 断开事件连接
|
||||
self:DisconnectRuneExecutionEvent()
|
||||
|
||||
-- 调用父类销毁方法
|
||||
UIWindow.Destroy(self)
|
||||
end
|
||||
|
||||
return RuneStateWindow
|
Loading…
x
Reference in New Issue
Block a user