更新
This commit is contained in:
parent
678c6035a9
commit
11ddf9fe1f
Binary file not shown.
BIN
excel/anim.xlsx
BIN
excel/anim.xlsx
Binary file not shown.
Binary file not shown.
BIN
excel/enemy.xlsx
BIN
excel/enemy.xlsx
Binary file not shown.
BIN
excel/level.xlsx
BIN
excel/level.xlsx
Binary file not shown.
@ -1,3 +1,4 @@
|
|||||||
[
|
[
|
||||||
{"id":20000,"type":1,"icon":1,"behaviourName":"SwordWave","upgradeCost":[30000,5,10],"upgradeValue":[10,200],"recycle":[30000,100]}
|
{"id":20000,"type":1,"icon":1,"behaviourName":"Attack","upgradeCost":[30000,5,0],"upgradeValue":[10,0],"recycle":[30000,0]},
|
||||||
|
{"id":20001,"type":1,"icon":1,"behaviourName":"SwordWave","upgradeCost":[30000,5,10],"upgradeValue":[10,200],"recycle":[30000,100]}
|
||||||
]
|
]
|
@ -1,3 +1,4 @@
|
|||||||
[
|
[
|
||||||
{"id":1,"name":"SwordWave","rbxId":"133335766636767","priority":"Action"}
|
{"id":1,"name":"SwordWave","rbxId":"133335766636767","priority":"Action"},
|
||||||
|
{"id":2,"name":"Attack","rbxId":"17283773476","priority":"Action"}
|
||||||
]
|
]
|
@ -14,7 +14,7 @@
|
|||||||
{"id":13,"type":1,"effectAttribute":"shadowDef","battleValue":[1,10],"iconId":13},
|
{"id":13,"type":1,"effectAttribute":"shadowDef","battleValue":[1,10],"iconId":13},
|
||||||
{"id":14,"type":2,"effectAttribute":"attackRate","battleValue":[1,10],"iconId":14},
|
{"id":14,"type":2,"effectAttribute":"attackRate","battleValue":[1,10],"iconId":14},
|
||||||
{"id":15,"type":2,"effectAttribute":"hpRate","battleValue":[1,10],"iconId":15},
|
{"id":15,"type":2,"effectAttribute":"hpRate","battleValue":[1,10],"iconId":15},
|
||||||
{"id":16,"type":2,"effectAttribute":"atkSpeed","battleValue":[1,10],"iconId":16},
|
{"id":16,"type":1,"effectAttribute":"atkSpeed","battleValue":[1,10],"iconId":16},
|
||||||
{"id":20,"type":2,"effectAttribute":"critRate","battleValue":[1,10],"iconId":17},
|
{"id":20,"type":2,"effectAttribute":"critRate","battleValue":[1,10],"iconId":17},
|
||||||
{"id":21,"type":2,"effectAttribute":"critDamageRate","battleValue":[1,10],"iconId":18},
|
{"id":21,"type":2,"effectAttribute":"critDamageRate","battleValue":[1,10],"iconId":18},
|
||||||
{"id":22,"type":2,"effectAttribute":"atkSpeedRate","battleValue":[1,10],"iconId":19},
|
{"id":22,"type":2,"effectAttribute":"atkSpeedRate","battleValue":[1,10],"iconId":19},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[
|
[
|
||||||
{"id":1,"type":1,"name":1,"attack":83,"hp":400,"walkSpeed":10,"attackSpeed":1,"model":"Thief"},
|
{"id":1,"type":1,"name":1,"attack":83,"hp":400,"walkSpeed":8,"attackSpeed":1,"model":"Thief"},
|
||||||
{"id":2,"type":1,"name":2,"attack":30,"hp":300,"walkSpeed":10,"attackSpeed":1,"model":"Thief"},
|
{"id":2,"type":1,"name":2,"attack":30,"hp":300,"walkSpeed":8,"attackSpeed":1,"model":"Thief"},
|
||||||
{"id":1000,"type":2,"name":1000,"attack":240,"hp":2000,"walkSpeed":20,"attackSpeed":1,"model":"Thief"}
|
{"id":1000,"type":2,"name":1000,"attack":240,"hp":2000,"walkSpeed":4,"attackSpeed":1,"model":"Thief"}
|
||||||
]
|
]
|
@ -1,52 +1,52 @@
|
|||||||
[
|
[
|
||||||
{"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":1,"type":1,"timeLimit":null,"atkBonus":500,"hpBonus":500,"wave":[[10,1,1,50,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":2,"type":1,"timeLimit":null,"atkBonus":520,"hpBonus":520,"wave":[[10,1,1,50,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":3,"type":1,"timeLimit":null,"atkBonus":540,"hpBonus":540,"wave":[[10,1,1,50,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":4,"type":1,"timeLimit":null,"atkBonus":560,"hpBonus":560,"wave":[[10,1,1,50,1,1]]},
|
||||||
{"id":5,"type":2,"timeLimit":60,"atkBonus":1050,"hpBonus":1050,"wave":[[10,1000,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":6,"type":1,"timeLimit":null,"atkBonus":600,"hpBonus":600,"wave":[[10,1,1,50,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":7,"type":1,"timeLimit":null,"atkBonus":620,"hpBonus":620,"wave":[[10,1,1,50,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":8,"type":1,"timeLimit":null,"atkBonus":640,"hpBonus":640,"wave":[[10,1,1,50,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":9,"type":1,"timeLimit":null,"atkBonus":660,"hpBonus":660,"wave":[[10,1,1,50,1,1]]},
|
||||||
{"id":10,"type":2,"timeLimit":60,"atkBonus":1100,"hpBonus":1100,"wave":[[10,1000,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":11,"type":1,"timeLimit":null,"atkBonus":700,"hpBonus":700,"wave":[[10,1,1,50,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":12,"type":1,"timeLimit":null,"atkBonus":720,"hpBonus":720,"wave":[[10,1,1,50,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":13,"type":1,"timeLimit":null,"atkBonus":740,"hpBonus":740,"wave":[[10,1,1,50,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":14,"type":1,"timeLimit":null,"atkBonus":760,"hpBonus":760,"wave":[[10,1,1,50,1,1]]},
|
||||||
{"id":15,"type":2,"timeLimit":60,"atkBonus":1150,"hpBonus":1150,"wave":[[10,1000,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":16,"type":1,"timeLimit":null,"atkBonus":800,"hpBonus":800,"wave":[[10,1,1,50,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":17,"type":1,"timeLimit":null,"atkBonus":820,"hpBonus":820,"wave":[[10,1,1,50,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":18,"type":1,"timeLimit":null,"atkBonus":840,"hpBonus":840,"wave":[[10,1,1,50,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":19,"type":1,"timeLimit":null,"atkBonus":860,"hpBonus":860,"wave":[[10,1,1,50,1,1]]},
|
||||||
{"id":20,"type":2,"timeLimit":60,"atkBonus":1250,"hpBonus":1250,"wave":[[10,1000,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":21,"type":1,"timeLimit":null,"atkBonus":900,"hpBonus":900,"wave":[[10,1,1,50,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":22,"type":1,"timeLimit":null,"atkBonus":920,"hpBonus":920,"wave":[[10,1,1,50,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":23,"type":1,"timeLimit":null,"atkBonus":940,"hpBonus":940,"wave":[[10,1,1,50,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":24,"type":1,"timeLimit":null,"atkBonus":960,"hpBonus":960,"wave":[[10,1,1,50,1,1]]},
|
||||||
{"id":25,"type":2,"timeLimit":60,"atkBonus":1350,"hpBonus":1350,"wave":[[10,1000,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":26,"type":1,"timeLimit":null,"atkBonus":1000,"hpBonus":1000,"wave":[[10,1,1,50,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":27,"type":1,"timeLimit":null,"atkBonus":1020,"hpBonus":1020,"wave":[[10,1,1,50,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":28,"type":1,"timeLimit":null,"atkBonus":1040,"hpBonus":1040,"wave":[[10,1,1,50,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":29,"type":1,"timeLimit":null,"atkBonus":1060,"hpBonus":1060,"wave":[[10,1,1,50,1,1]]},
|
||||||
{"id":30,"type":2,"timeLimit":60,"atkBonus":1500,"hpBonus":1500,"wave":[[10,1000,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":31,"type":1,"timeLimit":null,"atkBonus":1100,"hpBonus":1100,"wave":[[10,1,1,50,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":32,"type":1,"timeLimit":null,"atkBonus":1120,"hpBonus":1120,"wave":[[10,1,1,50,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":33,"type":1,"timeLimit":null,"atkBonus":1140,"hpBonus":1140,"wave":[[10,1,1,50,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":34,"type":1,"timeLimit":null,"atkBonus":1160,"hpBonus":1160,"wave":[[10,1,1,50,1,1]]},
|
||||||
{"id":35,"type":2,"timeLimit":60,"atkBonus":2000,"hpBonus":2000,"wave":[[10,1000,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":36,"type":1,"timeLimit":null,"atkBonus":1200,"hpBonus":1200,"wave":[[10,1,1,50,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":37,"type":1,"timeLimit":null,"atkBonus":1220,"hpBonus":1220,"wave":[[10,1,1,50,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":38,"type":1,"timeLimit":null,"atkBonus":1240,"hpBonus":1240,"wave":[[10,1,1,50,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":39,"type":1,"timeLimit":null,"atkBonus":1260,"hpBonus":1260,"wave":[[10,1,1,50,1,1]]},
|
||||||
{"id":40,"type":2,"timeLimit":60,"atkBonus":2500,"hpBonus":2500,"wave":[[10,1000,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":41,"type":1,"timeLimit":null,"atkBonus":1300,"hpBonus":1300,"wave":[[10,1,1,50,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":42,"type":1,"timeLimit":null,"atkBonus":1320,"hpBonus":1320,"wave":[[10,1,1,50,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":43,"type":1,"timeLimit":null,"atkBonus":1340,"hpBonus":1340,"wave":[[10,1,1,50,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":44,"type":1,"timeLimit":null,"atkBonus":1360,"hpBonus":1360,"wave":[[10,1,1,50,1,1]]},
|
||||||
{"id":45,"type":2,"timeLimit":60,"atkBonus":3000,"hpBonus":3000,"wave":[[10,1000,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":46,"type":1,"timeLimit":null,"atkBonus":1400,"hpBonus":1400,"wave":[[10,1,1,50,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":47,"type":1,"timeLimit":null,"atkBonus":1420,"hpBonus":1420,"wave":[[10,1,1,50,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":48,"type":1,"timeLimit":null,"atkBonus":1440,"hpBonus":1440,"wave":[[10,1,1,50,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":49,"type":1,"timeLimit":null,"atkBonus":1460,"hpBonus":1460,"wave":[[10,1,1,50,1,1]]},
|
||||||
{"id":50,"type":2,"timeLimit":60,"atkBonus":3500,"hpBonus":3500,"wave":[[10,1000,1]]}
|
{"id":50,"type":2,"timeLimit":60,"atkBonus":3500,"hpBonus":3500,"wave":[[10,1000,1]]}
|
||||||
]
|
]
|
48
src/ReplicatedStorage/Modules/BehavioursClient/Attack.luau
Normal file
48
src/ReplicatedStorage/Modules/BehavioursClient/Attack.luau
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
-- 剑气
|
||||||
|
|
||||||
|
--> Services
|
||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
|
||||||
|
--> Dependencies
|
||||||
|
local BehaviourClient = require(ReplicatedStorage.Base.BehaviourClient)
|
||||||
|
|
||||||
|
--> Variables
|
||||||
|
local PrefabFolder = ReplicatedStorage:WaitForChild("Prefabs")
|
||||||
|
-- local Prefab_Attack = PrefabFolder:WaitForChild("Projectiles"):WaitForChild("Attack")
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local Attack = {}
|
||||||
|
Attack.__index = Attack
|
||||||
|
setmetatable(Attack, {__index = BehaviourClient})
|
||||||
|
|
||||||
|
function Attack:Init(CasterPlayer: Player, CastInfo: table, DelayTime: number, CastState: boolean)
|
||||||
|
local self = BehaviourClient:Init(CasterPlayer, CastInfo, DelayTime, CastState)
|
||||||
|
setmetatable(self, Attack)
|
||||||
|
|
||||||
|
-- 加载动画
|
||||||
|
self:LoadAnimationByName("Attack")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function Attack:Show(CasterPlayer: Player, CastInfo: table, DelayTime: number, CastState: boolean)
|
||||||
|
self.EffectDispatcher:ShowAnimation(self.Player, DelayTime, self:GetAnimationByName("Attack"))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Attack:Destroy()
|
||||||
|
if self.ShowTask then
|
||||||
|
task.cancel(self.ShowTask)
|
||||||
|
self.ShowTask = nil
|
||||||
|
end
|
||||||
|
if self.Tween then
|
||||||
|
self.Tween:Cancel()
|
||||||
|
self.Tween = nil
|
||||||
|
end
|
||||||
|
if self.Projectile then
|
||||||
|
self.Projectile:Destroy()
|
||||||
|
self.Projectile = nil
|
||||||
|
end
|
||||||
|
BehaviourClient.Destroy(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
return Attack
|
@ -12,6 +12,16 @@ local RE_CleanPlayerPerformance = ReplicatedStorage:FindFirstChild("Events"):Fin
|
|||||||
--> Dependencies
|
--> Dependencies
|
||||||
local TypeList = require(ServerStorage.Base.TypeList)
|
local TypeList = require(ServerStorage.Base.TypeList)
|
||||||
local Communicate = require(ServerStorage.Modules.Tools.Communicate)
|
local Communicate = require(ServerStorage.Modules.Tools.Communicate)
|
||||||
|
local Utils = require(ReplicatedStorage.Tools.Utils)
|
||||||
|
|
||||||
|
--> Json
|
||||||
|
local JsonAttributes = require(ReplicatedStorage.Json.Attributes)
|
||||||
|
|
||||||
|
--> 临时维护一个属性数据表,用于记录属性类型
|
||||||
|
local AttributesNameData = {}
|
||||||
|
for _, Attribute in JsonAttributes do
|
||||||
|
AttributesNameData[Attribute.effectAttribute] = Utils:DeepCopyTable(Attribute)
|
||||||
|
end
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -54,7 +64,6 @@ end
|
|||||||
|
|
||||||
-- 检查行为前先清理之前遗留的引用数据
|
-- 检查行为前先清理之前遗留的引用数据
|
||||||
function Behaviour:CheckClean()
|
function Behaviour:CheckClean()
|
||||||
|
|
||||||
if self.Mobs then
|
if self.Mobs then
|
||||||
for _, Mob in self.Mobs do
|
for _, Mob in self.Mobs do
|
||||||
self.Mobs[Mob] = nil
|
self.Mobs[Mob] = nil
|
||||||
@ -69,6 +78,21 @@ function Behaviour:CheckClean()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Behaviour:GetAttributeValue(AttributeName: string)
|
||||||
|
local AttributeValue = self.Character.Instance:FindFirstChild("Attributes"):GetAttribute(AttributeName)
|
||||||
|
if not AttributeValue then return nil end
|
||||||
|
-- 处理对应的值
|
||||||
|
local AttributeData = AttributesNameData[AttributeName]
|
||||||
|
if not AttributeData then return nil end
|
||||||
|
|
||||||
|
local typeValue = AttributeData.type
|
||||||
|
if typeValue == 1 then
|
||||||
|
return AttributeValue
|
||||||
|
elseif typeValue == 2 then
|
||||||
|
return AttributeValue / 100
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- 启动冷却时间清除计时
|
-- 启动冷却时间清除计时
|
||||||
function Behaviour:StartCooldownTask()
|
function Behaviour:StartCooldownTask()
|
||||||
self.Cooldown = self.OrgCooldown
|
self.Cooldown = self.OrgCooldown
|
||||||
|
121
src/ServerStorage/Modules/Behaviours/Attack.luau
Normal file
121
src/ServerStorage/Modules/Behaviours/Attack.luau
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
-- 移动行为
|
||||||
|
|
||||||
|
--> Services
|
||||||
|
local ServerStorage = game:GetService("ServerStorage")
|
||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
|
||||||
|
--> Dependencies
|
||||||
|
local TypeList = require(ServerStorage.Base.TypeList)
|
||||||
|
local Behaviour = require(ServerStorage.Base.Behaviour)
|
||||||
|
local MobsProxy = require(ServerStorage.Proxy.MobsProxy)
|
||||||
|
local DamageProxy = require(ServerStorage.Proxy.DamageProxy)
|
||||||
|
local Utils = require(ReplicatedStorage.Tools.Utils)
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local Attack = {}
|
||||||
|
Attack.__index = Attack
|
||||||
|
setmetatable(Attack, {__index = Behaviour})
|
||||||
|
|
||||||
|
local CAST_DISTANCE = 8
|
||||||
|
local COOLDOWN = 1
|
||||||
|
local ATTRIBUTE_LIST = {
|
||||||
|
{Name = "attack", ElementType = DamageProxy.ElementType.NONE},
|
||||||
|
{Name = "fireAtk", ElementType = DamageProxy.ElementType.FIRE},
|
||||||
|
{Name = "iceAtk", ElementType = DamageProxy.ElementType.ICE},
|
||||||
|
{Name = "lightAtk", ElementType = DamageProxy.ElementType.LIGHT},
|
||||||
|
{Name = "shadowAtk", ElementType = DamageProxy.ElementType.SHADOW},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function Attack:Init(PlayerAI, Character: TypeList.Character, Player: Player)
|
||||||
|
local self = Behaviour:Init(PlayerAI, Character, script.Name)
|
||||||
|
self.Player = Player
|
||||||
|
self.Mobs = nil
|
||||||
|
setmetatable(self, Attack)
|
||||||
|
self.OrgCooldown = COOLDOWN
|
||||||
|
-- self:StartCooldownTask()
|
||||||
|
|
||||||
|
-- 客户端表现
|
||||||
|
self:SendPerformanceEvent("Init", self.Player, script.Name, true, {})
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function Attack:Check(CheckInfo: table)
|
||||||
|
if Behaviour.CheckStat(self) then return -1, self.CheckData end
|
||||||
|
self:CheckClean()
|
||||||
|
|
||||||
|
self.Mobs = MobsProxy:GetPlayerMobs(self.Player)
|
||||||
|
if not self.Mobs then return end
|
||||||
|
|
||||||
|
|
||||||
|
local closestMob, minDistance = nil, CAST_DISTANCE
|
||||||
|
for _, Mob in self.Mobs do
|
||||||
|
if Mob.Instance and Mob.Instance.PrimaryPart then
|
||||||
|
local dist = (Mob.Instance.PrimaryPart.Position - self.Character.Instance.PrimaryPart.Position).Magnitude
|
||||||
|
if dist < minDistance then
|
||||||
|
minDistance = dist
|
||||||
|
closestMob = Mob
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self.CheckData = {}
|
||||||
|
if closestMob then
|
||||||
|
self.CheckData["ClosestCharacter"] = closestMob
|
||||||
|
return 50, self.CheckData
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 返回优先级,执行数据
|
||||||
|
return -1, self.CheckData
|
||||||
|
end
|
||||||
|
|
||||||
|
function Attack:Execute()
|
||||||
|
self.ExeTask = task.spawn(function ()
|
||||||
|
self:ChangeExecutingState(true)
|
||||||
|
-- cd放前面之后发送事件才能正常记录cd
|
||||||
|
-- self:StartCooldownTask()
|
||||||
|
|
||||||
|
-- 停止移动
|
||||||
|
self.Character.Humanoid:MoveTo(self.Character.Root.Position)
|
||||||
|
-- 朝向目标
|
||||||
|
local HumanoidRootPart = self.Character.Root
|
||||||
|
local TargetPosition = self.CheckData["ClosestCharacter"].Instance.PrimaryPart.Position
|
||||||
|
|
||||||
|
if HumanoidRootPart then
|
||||||
|
HumanoidRootPart.CFrame = CFrame.lookAt(HumanoidRootPart.Position, TargetPosition)
|
||||||
|
end
|
||||||
|
|
||||||
|
local atkSpeed = self:GetAttributeValue("atkSpeed")
|
||||||
|
if not atkSpeed then warn("atkSpeed not found") return end
|
||||||
|
|
||||||
|
-- 表现部分
|
||||||
|
self:SendPerformanceEvent("Show", self.Player, self.ScriptName, true, {
|
||||||
|
{ UniqueId = self.PlayerAI:GetBehaviourUniqueId() }
|
||||||
|
})
|
||||||
|
-- 攻击前摇
|
||||||
|
task.wait(atkSpeed)
|
||||||
|
|
||||||
|
-- TODO: 之后这里可以提前做暴击判定
|
||||||
|
|
||||||
|
-- 伤害逻辑计算部分
|
||||||
|
local damageData = {}
|
||||||
|
for _, attribute in ATTRIBUTE_LIST do
|
||||||
|
local attributeValue = self:GetAttributeValue(attribute.Name)
|
||||||
|
if attributeValue then
|
||||||
|
table.insert(damageData, {
|
||||||
|
Damage = attributeValue,
|
||||||
|
Type = DamageProxy.DamageType.NORMAL,
|
||||||
|
Tag = DamageProxy.DamageTag.NORMAL,
|
||||||
|
ElementType = attribute.ElementType,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
DamageProxy:TakeDamage(self.Character, self.CheckData["ClosestCharacter"], damageData)
|
||||||
|
|
||||||
|
-- task.wait(atkSpeed / 2)
|
||||||
|
self:ChangeExecutingState(false)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return Attack
|
@ -14,6 +14,8 @@ local Move = {}
|
|||||||
Move.__index = Move
|
Move.__index = Move
|
||||||
setmetatable(Move, {__index = Behaviour})
|
setmetatable(Move, {__index = Behaviour})
|
||||||
|
|
||||||
|
local ATTACK_DISTANCE = 8
|
||||||
|
|
||||||
function Move:Init(PlayerAI, Character: TypeList.Character, Player: Player)
|
function Move:Init(PlayerAI, Character: TypeList.Character, Player: Player)
|
||||||
local self = Behaviour:Init(PlayerAI, Character, script.Name)
|
local self = Behaviour:Init(PlayerAI, Character, script.Name)
|
||||||
self.Player = Player
|
self.Player = Player
|
||||||
@ -41,8 +43,11 @@ function Move:Check(CheckInfo: table)
|
|||||||
|
|
||||||
self.CheckData = {}
|
self.CheckData = {}
|
||||||
if closestMob then
|
if closestMob then
|
||||||
self.CheckData["ClosestCharacter"] = closestMob
|
local distance = (closestMob.Instance.PrimaryPart.Position - self.Character.Instance.PrimaryPart.Position).Magnitude
|
||||||
return 10, self.CheckData
|
if distance > ATTACK_DISTANCE then
|
||||||
|
self.CheckData["ClosestCharacter"] = closestMob
|
||||||
|
return 10, self.CheckData
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- 返回优先级,执行数据
|
-- 返回优先级,执行数据
|
||||||
@ -50,10 +55,22 @@ function Move:Check(CheckInfo: table)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Move:Execute()
|
function Move:Execute()
|
||||||
|
if self.ExeTask then task.cancel(self.ExeTask) end
|
||||||
self.ExeTask = task.spawn(function ()
|
self.ExeTask = task.spawn(function ()
|
||||||
self:ChangeExecutingState(true)
|
self:ChangeExecutingState(true)
|
||||||
self.Character.Humanoid:MoveTo(self.CheckData["ClosestCharacter"].Instance:GetPivot().Position)
|
|
||||||
task.wait(0.5)
|
-- 新移动朝向
|
||||||
|
local TargetCharacter = self.CheckData["ClosestCharacter"].Instance
|
||||||
|
local TargetPosition = TargetCharacter:GetPivot().Position
|
||||||
|
local CharacterPosition = self.Character.Instance:GetPivot().Position
|
||||||
|
local Direction = (TargetPosition - CharacterPosition).Unit
|
||||||
|
local MoveToPosition = TargetPosition - (Direction * ATTACK_DISTANCE)
|
||||||
|
|
||||||
|
self.Character.Humanoid:MoveTo(MoveToPosition)
|
||||||
|
|
||||||
|
-- 旧内容
|
||||||
|
-- self.Character.Humanoid:MoveTo(self.CheckData["ClosestCharacter"].Instance:GetPivot().Position)
|
||||||
|
task.wait(0.2)
|
||||||
self:ChangeExecutingState(false)
|
self:ChangeExecutingState(false)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -86,7 +86,6 @@ local function LoadData(Player: Player): (boolean, any)
|
|||||||
|
|
||||||
if Success and Response then
|
if Success and Response then
|
||||||
print(("DataManager: User %s's data loaded into the game."):format(Player.Name))
|
print(("DataManager: User %s's data loaded into the game."):format(Player.Name))
|
||||||
print(Response)
|
|
||||||
else
|
else
|
||||||
print(("DataManager: User %s had no data to load from."):format(Player.Name))
|
print(("DataManager: User %s had no data to load from."):format(Player.Name))
|
||||||
end
|
end
|
||||||
|
@ -67,9 +67,7 @@ task.defer(function()
|
|||||||
local Enemy = Mob.Humanoid
|
local Enemy = Mob.Humanoid
|
||||||
|
|
||||||
-- Simulation
|
-- Simulation
|
||||||
if Mob.Root.Anchored then
|
if Mob.Root.Anchored then Mob.Root.Anchored = false end
|
||||||
Mob.Root.Anchored = false
|
|
||||||
end
|
|
||||||
if not Mob.Root:GetNetworkOwner() then
|
if not Mob.Root:GetNetworkOwner() then
|
||||||
Mob.Root:SetNetworkOwner(Player)
|
Mob.Root:SetNetworkOwner(Player)
|
||||||
task.wait(0.05) -- Give physics more time so it doesn't appear as choppy
|
task.wait(0.05) -- Give physics more time so it doesn't appear as choppy
|
||||||
@ -78,9 +76,12 @@ task.defer(function()
|
|||||||
-- Tracking
|
-- Tracking
|
||||||
if Player and Enemy and PlayerRole then
|
if Player and Enemy and PlayerRole then
|
||||||
if PlayerRole.Stats.Died then return end
|
if PlayerRole.Stats.Died then return end
|
||||||
if distance > 5 then
|
if distance > 8 then
|
||||||
|
Enemy:SetAttribute("AttackState", "Idle")
|
||||||
Enemy:MoveTo(Player.Character:GetPivot().Position, Player.Character.PrimaryPart)
|
Enemy:MoveTo(Player.Character:GetPivot().Position, Player.Character.PrimaryPart)
|
||||||
else
|
else
|
||||||
|
Enemy:SetAttribute("AttackState", "Hit")
|
||||||
|
Mob.Root.Anchored = true
|
||||||
Mob.ExecutingState = true
|
Mob.ExecutingState = true
|
||||||
-- 停止移动
|
-- 停止移动
|
||||||
Enemy:MoveTo(MobInstance:GetPivot().Position)
|
Enemy:MoveTo(MobInstance:GetPivot().Position)
|
||||||
@ -92,7 +93,7 @@ task.defer(function()
|
|||||||
if not Player then return end
|
if not Player then return end
|
||||||
if PlayerRole.Stats.Died then return end
|
if PlayerRole.Stats.Died then return end
|
||||||
|
|
||||||
if AI:GetModelDistance(MobInstance, Player.Character) <= 5 then
|
if AI:GetModelDistance(MobInstance, Player.Character) <= 8 then
|
||||||
-- 调用伤害模块
|
-- 调用伤害模块
|
||||||
DamageProxy:TakeDamage(Mob, Mob.PlayerRole, {
|
DamageProxy:TakeDamage(Mob, Mob.PlayerRole, {
|
||||||
{
|
{
|
||||||
@ -104,6 +105,7 @@ task.defer(function()
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
Mob.ExecutingState = false
|
Mob.ExecutingState = false
|
||||||
|
Enemy:SetAttribute("AttackState", "Idle")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -99,7 +99,10 @@ function MobsProxy:CreateMob(Player: Player, MobId: number, AtkBonus: number?, H
|
|||||||
AI:StartTracking(Mob)
|
AI:StartTracking(Mob)
|
||||||
-- 关卡系数
|
-- 关卡系数
|
||||||
if AtkBonus then Mob:ChangeAttributeValue("attack", math.floor(Mob.Config.attack * (AtkBonus / 1000))) end
|
if AtkBonus then Mob:ChangeAttributeValue("attack", math.floor(Mob.Config.attack * (AtkBonus / 1000))) end
|
||||||
if HpBonus then Mob:ChangeAttributeValue("hp", math.floor(Mob.Config.hp * (HpBonus / 1000))) end
|
if HpBonus then
|
||||||
|
Mob:ChangeAttributeValue("hp", math.floor(Mob.Config.hp * (HpBonus / 1000)))
|
||||||
|
Mob:ChangeAttributeValue("maxhp", math.floor(Mob.Config.maxhp * (HpBonus / 1000)))
|
||||||
|
end
|
||||||
MobsProxy.pData[Player.UserId][Mob.Instance] = Mob
|
MobsProxy.pData[Player.UserId][Mob.Instance] = Mob
|
||||||
return Mob
|
return Mob
|
||||||
end
|
end
|
||||||
|
@ -65,6 +65,7 @@ function PlayerRole.new(Player: Player, CharacterId: number)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function PlayerRole:Died()
|
function PlayerRole:Died()
|
||||||
self:ChangeState("Died", true)
|
self:ChangeState("Died", true)
|
||||||
self.Humanoid.WalkSpeed = 0
|
self.Humanoid.WalkSpeed = 0
|
||||||
@ -119,7 +120,6 @@ function PlayerFightProxy:UpdatePlayerFightData(Player: Player)
|
|||||||
local AbilityProxy = require(ServerStorage.Proxy.AbilityProxy)
|
local AbilityProxy = require(ServerStorage.Proxy.AbilityProxy)
|
||||||
local GemProxy = require(ServerStorage.Proxy.GemProxy)
|
local GemProxy = require(ServerStorage.Proxy.GemProxy)
|
||||||
|
|
||||||
|
|
||||||
local AttributesData = {}
|
local AttributesData = {}
|
||||||
|
|
||||||
-- 计算角色基础属性值 + 装备属性值 + 宝石属性值,赋值属性
|
-- 计算角色基础属性值 + 装备属性值 + 宝石属性值,赋值属性
|
||||||
@ -178,8 +178,9 @@ function PlayerFightProxy:UpdatePlayerFightData(Player: Player)
|
|||||||
for _, behaviourName in behaviourNameList do
|
for _, behaviourName in behaviourNameList do
|
||||||
playerAI:AddBehaviour(behaviourName)
|
playerAI:AddBehaviour(behaviourName)
|
||||||
end
|
end
|
||||||
-- playerAI:AddBehaviour("Move")
|
playerAI:AddBehaviour("Move")
|
||||||
playerAI:AddBehaviour("SwordWave")
|
-- playerAI:AddBehaviour("SwordWave")
|
||||||
|
playerAI:AddBehaviour("Attack")
|
||||||
|
|
||||||
|
|
||||||
-- 给前端发送技能信息
|
-- 给前端发送技能信息
|
||||||
|
@ -5,7 +5,7 @@ local RunService = game:GetService("RunService")
|
|||||||
local player = Players.LocalPlayer
|
local player = Players.LocalPlayer
|
||||||
local camera = workspace.CurrentCamera
|
local camera = workspace.CurrentCamera
|
||||||
|
|
||||||
local CAMERA_DISTANCE = 20
|
local CAMERA_DISTANCE = 30
|
||||||
local CAMERA_HEIGHT = 40
|
local CAMERA_HEIGHT = 40
|
||||||
local CAMERA_ANGLE = math.rad(-45)
|
local CAMERA_ANGLE = math.rad(-45)
|
||||||
local SCREEN_OFFSET = 5
|
local SCREEN_OFFSET = 5
|
||||||
|
159
src/StarterPlayerScripts/ClientMain/MobAnim.luau
Normal file
159
src/StarterPlayerScripts/ClientMain/MobAnim.luau
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
--[[
|
||||||
|
Evercyan @ March 2023
|
||||||
|
MobClient
|
||||||
|
|
||||||
|
Unlike MobLib which handles server-sided code, and most of it in general, we run
|
||||||
|
some code on the client for things such as custom health overlays & overwriting humanoid state types.
|
||||||
|
|
||||||
|
If you want to edit mob code to add new behavior or edit existing behavior, you likely want to refer
|
||||||
|
to the server-sided code under ServerStorage.
|
||||||
|
]]
|
||||||
|
|
||||||
|
--> Services
|
||||||
|
local CollectionService = game:GetService("CollectionService")
|
||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local Players = game:GetService("Players")
|
||||||
|
|
||||||
|
--> Player
|
||||||
|
local Player = Players.LocalPlayer
|
||||||
|
|
||||||
|
--> Dependencies
|
||||||
|
local Tween = require(ReplicatedStorage.Modules.Tween)
|
||||||
|
local Maid = require(ReplicatedStorage.Modules.Maid)
|
||||||
|
|
||||||
|
--> Variables
|
||||||
|
local Mobs = {}
|
||||||
|
|
||||||
|
-- Folder
|
||||||
|
local ClientMainPrefabs = Player.PlayerScripts.ClientMainPrefabs
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- WaitForChild keeps yielding, even if the Instance is removed.
|
||||||
|
-- Using this for safe yielding with StreamingEnabled!
|
||||||
|
local function safeWait(Item: Instance, Name: string): Instance?
|
||||||
|
if not Item then
|
||||||
|
return
|
||||||
|
elseif Item:FindFirstChild(Name) then
|
||||||
|
return Item:FindFirstChild(Name)
|
||||||
|
end
|
||||||
|
|
||||||
|
local ItemAdded = Instance.new("BindableEvent")
|
||||||
|
local Maid = Maid.new()
|
||||||
|
|
||||||
|
Maid:Add(Item.ChildAdded:Connect(function(Child)
|
||||||
|
if Child.Name == Name then
|
||||||
|
ItemAdded:Fire(Child)
|
||||||
|
ItemAdded:Destroy()
|
||||||
|
Maid:Destroy()
|
||||||
|
end
|
||||||
|
end))
|
||||||
|
Maid:Add(Item.Destroying:Connect(function()
|
||||||
|
ItemAdded:Fire()
|
||||||
|
ItemAdded:Destroy()
|
||||||
|
Maid:Destroy()
|
||||||
|
end))
|
||||||
|
|
||||||
|
return ItemAdded.Event:Wait()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Creates an "AnimationTrack" instance which is stored on the client for playing
|
||||||
|
local function LoadAnimationTrack(MobInstance: Model, Name: string, Priority: string) : AnimationTrack?
|
||||||
|
local Humanoid = MobInstance:FindFirstChild("Humanoid") :: Humanoid
|
||||||
|
local Animator = Humanoid and Humanoid:FindFirstChild("Animator") :: Animator
|
||||||
|
if not Animator then return nil end
|
||||||
|
|
||||||
|
local Animation
|
||||||
|
Animation = ClientMainPrefabs.MobClient.DefaultAnimations[Name]
|
||||||
|
|
||||||
|
local AnimationTrack = Animator:LoadAnimation(Animation)
|
||||||
|
AnimationTrack.Priority = Enum.AnimationPriority[Priority or "Core"]
|
||||||
|
|
||||||
|
return AnimationTrack
|
||||||
|
end
|
||||||
|
|
||||||
|
local function PerMob(MobInstance: Model)
|
||||||
|
if Mobs[MobInstance] then return end
|
||||||
|
|
||||||
|
local Humanoid = safeWait(MobInstance, "Humanoid") :: Humanoid
|
||||||
|
local Root = safeWait(MobInstance, "HumanoidRootPart") :: BasePart
|
||||||
|
if not Humanoid or not Root then return end
|
||||||
|
|
||||||
|
local Maid = Maid.new()
|
||||||
|
|
||||||
|
-- Set humanoid states (helps prevent falling down & useless calculations - you're unlikely to have an enemy climbing without pathfinding)
|
||||||
|
for _, EnumName in {"FallingDown", "Seated", "Flying", "Swimming", "Climbing"} do
|
||||||
|
local HumanoidStateType = Enum.HumanoidStateType[EnumName]
|
||||||
|
Humanoid:SetStateEnabled(HumanoidStateType, false)
|
||||||
|
if Humanoid:GetState() == HumanoidStateType then
|
||||||
|
Humanoid:ChangeState(Enum.HumanoidStateType.Running)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Animations / Behavior ---------------------------------------------------
|
||||||
|
|
||||||
|
local AnimationTracks = {
|
||||||
|
Running = LoadAnimationTrack(MobInstance, "Running", "Core"),
|
||||||
|
Jumping = LoadAnimationTrack(MobInstance, "Jumping", "Movement"),
|
||||||
|
Hit = LoadAnimationTrack(MobInstance, "Hit", "Action")
|
||||||
|
}
|
||||||
|
|
||||||
|
Maid:Add(Humanoid.Running:Connect(function(Speed)
|
||||||
|
if Speed > 0.01 then
|
||||||
|
local Percent = Speed/Humanoid.WalkSpeed
|
||||||
|
if not AnimationTracks.Running.IsPlaying then
|
||||||
|
AnimationTracks.Running:Play()
|
||||||
|
end
|
||||||
|
AnimationTracks.Running:AdjustSpeed(Percent)
|
||||||
|
else
|
||||||
|
AnimationTracks.Running:Stop()
|
||||||
|
end
|
||||||
|
end))
|
||||||
|
|
||||||
|
Maid:Add(Humanoid.Jumping:Connect(function()
|
||||||
|
AnimationTracks.Jumping.TimePosition = 0
|
||||||
|
if not AnimationTracks.Jumping.IsPlaying then
|
||||||
|
AnimationTracks.Jumping:Play()
|
||||||
|
end
|
||||||
|
end))
|
||||||
|
|
||||||
|
-- Maid:Add(Humanoid.Died:Once(function()
|
||||||
|
-- Root:ApplyImpulse(-Root.CFrame.LookVector * Root.AssemblyMass*50) -- Ragdoll Impulse
|
||||||
|
-- end))
|
||||||
|
|
||||||
|
Maid:Add(Root:GetPropertyChangedSignal("Anchored"):Connect(function()
|
||||||
|
if Root.Anchored then
|
||||||
|
AnimationTracks.Running:Stop()
|
||||||
|
end
|
||||||
|
end))
|
||||||
|
|
||||||
|
-- TODO: 攻击动画之后要做延迟处理和攻速处理
|
||||||
|
Maid:Add(Humanoid:GetAttributeChangedSignal("AttackState"):Connect(function()
|
||||||
|
if Humanoid:GetAttribute("AttackState") == "Hit" then
|
||||||
|
if AnimationTracks.Hit.IsPlaying then
|
||||||
|
AnimationTracks.Hit.TimePosition = 0
|
||||||
|
else
|
||||||
|
AnimationTracks.Hit:Play()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
AnimationTracks.Hit:Stop()
|
||||||
|
end
|
||||||
|
end))
|
||||||
|
|
||||||
|
local Mob = {}
|
||||||
|
Mob.Instance = MobInstance
|
||||||
|
Mob.AnimationTracks = AnimationTracks
|
||||||
|
Mobs[MobInstance] = Mob
|
||||||
|
|
||||||
|
Maid:Add(MobInstance.Destroying:Connect(function()
|
||||||
|
Mobs[MobInstance] = nil
|
||||||
|
Maid:Destroy()
|
||||||
|
end))
|
||||||
|
end
|
||||||
|
|
||||||
|
CollectionService:GetInstanceAddedSignal("Mob"):Connect(PerMob)
|
||||||
|
for _, MobInstance in CollectionService:GetTagged("Mob") do
|
||||||
|
task.spawn(PerMob, MobInstance)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {}
|
@ -35,8 +35,8 @@ end
|
|||||||
|
|
||||||
function DamageBoard:CreateNormalDamageBoard(DamageDetail: table)
|
function DamageBoard:CreateNormalDamageBoard(DamageDetail: table)
|
||||||
local DamageInitPos = DamageDetail.DamagePosition
|
local DamageInitPos = DamageDetail.DamagePosition
|
||||||
local BiasPos = Vector3.new(0, 4, 0)
|
local BiasPos = Vector3.new(0, 6, 0)
|
||||||
local MultPos = Vector3.new(0, 1.5, 0)
|
local MultPos = Vector3.new(0, 1, 0)
|
||||||
|
|
||||||
-- 根据元素类型排序
|
-- 根据元素类型排序
|
||||||
local DamageInfos = DamageDetail["DamageInfos"]
|
local DamageInfos = DamageDetail["DamageInfos"]
|
||||||
|
@ -56,7 +56,6 @@ RE_PerformanceEvent.OnClientEvent:Connect(function(ServerTime: number, CastTag:
|
|||||||
|
|
||||||
local delayTime = ServerTime - tick()
|
local delayTime = ServerTime - tick()
|
||||||
if CastTag == "Init" then
|
if CastTag == "Init" then
|
||||||
-- print("Init", BehaviourName)
|
|
||||||
-- 暂时就新增一个表,不调用初始化,因为服务端不是多个new做的,而是多次调用
|
-- 暂时就新增一个表,不调用初始化,因为服务端不是多个new做的,而是多次调用
|
||||||
if not PerformanceClient.pData[UserId][BehaviourName] then
|
if not PerformanceClient.pData[UserId][BehaviourName] then
|
||||||
PerformanceClient.pData[UserId][BehaviourName] = {}
|
PerformanceClient.pData[UserId][BehaviourName] = {}
|
||||||
|
@ -2,30 +2,57 @@ local UserInputService = game:GetService("UserInputService")
|
|||||||
|
|
||||||
local PlayerControl = {}
|
local PlayerControl = {}
|
||||||
|
|
||||||
-- 监听按键按下
|
-- 添加按键状态跟踪
|
||||||
function PlayerControl.ListenMoveKeyDown(onKeyDown)
|
local pressedKeys = {}
|
||||||
UserInputService.InputBegan:Connect(function(input, gameProcessed)
|
|
||||||
if gameProcessed then return end
|
|
||||||
if input.UserInputType == Enum.UserInputType.Keyboard then
|
|
||||||
local key = input.KeyCode
|
|
||||||
if key == Enum.KeyCode.W or key == Enum.KeyCode.A or key == Enum.KeyCode.S or key == Enum.KeyCode.D then
|
|
||||||
onKeyDown(key)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 监听按键松开
|
|
||||||
function PlayerControl.ListenMoveKeyUp(onKeyUp)
|
function PlayerControl.ListenMoveKeyUp(onKeyUp)
|
||||||
UserInputService.InputEnded:Connect(function(input, gameProcessed)
|
UserInputService.InputEnded:Connect(function(input, gameProcessed)
|
||||||
if gameProcessed then return end
|
if gameProcessed then return end
|
||||||
if input.UserInputType == Enum.UserInputType.Keyboard then
|
if input.UserInputType == Enum.UserInputType.Keyboard then
|
||||||
local key = input.KeyCode
|
local key = input.KeyCode
|
||||||
if key == Enum.KeyCode.W or key == Enum.KeyCode.A or key == Enum.KeyCode.S or key == Enum.KeyCode.D then
|
if key == Enum.KeyCode.W or key == Enum.KeyCode.A or key == Enum.KeyCode.S or key == Enum.KeyCode.D then
|
||||||
onKeyUp(key)
|
pressedKeys[key] = nil -- 移除当前按键状态
|
||||||
|
|
||||||
|
-- 检查是否还有其他移动按键在按下
|
||||||
|
local hasOtherKeysPressed = false
|
||||||
|
for k, v in pairs(pressedKeys) do
|
||||||
|
if k == Enum.KeyCode.W or k == Enum.KeyCode.A or k == Enum.KeyCode.S or k == Enum.KeyCode.D then
|
||||||
|
hasOtherKeysPressed = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 只有当没有其他移动按键按下时才调用onKeyUp
|
||||||
|
if not hasOtherKeysPressed then
|
||||||
|
onKeyUp(key)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- 添加按键按下监听
|
||||||
|
function PlayerControl.ListenMoveKeyDown(onKeyDown)
|
||||||
|
UserInputService.InputBegan:Connect(function(input, gameProcessed)
|
||||||
|
if gameProcessed then return end
|
||||||
|
if input.UserInputType == Enum.UserInputType.Keyboard then
|
||||||
|
local key = input.KeyCode
|
||||||
|
if key == Enum.KeyCode.W or key == Enum.KeyCode.A or key == Enum.KeyCode.S or key == Enum.KeyCode.D then
|
||||||
|
pressedKeys[key] = true
|
||||||
|
onKeyDown(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 添加获取当前按下按键的函数
|
||||||
|
function PlayerControl.GetPressedKeys()
|
||||||
|
return pressedKeys
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 添加检查特定按键是否按下的函数
|
||||||
|
function PlayerControl.IsKeyPressed(keyCode)
|
||||||
|
return pressedKeys[keyCode] == true
|
||||||
|
end
|
||||||
|
|
||||||
return PlayerControl
|
return PlayerControl
|
@ -128,6 +128,14 @@ function UIManager:IsOpened(WindowName: string)
|
|||||||
return UIManager.Instances[WindowName] ~= nil
|
return UIManager.Instances[WindowName] ~= nil
|
||||||
end
|
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:GetWindowStackInfo()
|
function UIManager:GetWindowStackInfo()
|
||||||
local info = {}
|
local info = {}
|
||||||
|
@ -62,14 +62,16 @@ function MainWindow:OnOpenWindow()
|
|||||||
table.insert(self.Connections, chaCon)
|
table.insert(self.Connections, chaCon)
|
||||||
table.insert(self.Connections, attributeUpgradeCon)
|
table.insert(self.Connections, attributeUpgradeCon)
|
||||||
|
|
||||||
local playerDataFolder = Utils:WaitPlayerDataFolder(LocalPlayer)
|
-- TODO: 暂时用主关卡数显示,我记得之前这里主要是记录的,Challenge中才是正在挑战的内容
|
||||||
local StatsFolder = playerDataFolder:WaitForChild("PlayerInfo"):WaitForChild("Stats")
|
-- TODO: 之后LevelProxy也应该挪到ReplicatedStorage下,之前可能是因为觉得Challenge是临时的内容所以放在workspace下,但是逻辑做的不统一
|
||||||
local levelCon = StatsFolder.level.Changed:Connect(function(newValue)
|
local playerDataFolder = game.Workspace:WaitForChild("Level"):WaitForChild(LocalPlayer.UserId)
|
||||||
|
local StatsFolder = playerDataFolder:WaitForChild("Progress")
|
||||||
|
local levelCon = StatsFolder.Main.Changed:Connect(function(newValue)
|
||||||
self:SetShowLevel(newValue)
|
self:SetShowLevel(newValue)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- 初始值设置
|
-- 初始值设置
|
||||||
self:SetShowLevel(StatsFolder.level.Value)
|
self:SetShowLevel(StatsFolder.Main.Value)
|
||||||
table.insert(self.Connections, levelCon)
|
table.insert(self.Connections, levelCon)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user