更新
This commit is contained in:
parent
f1728a045b
commit
c1c22aa963
BIN
excel/cha.xlsx
BIN
excel/cha.xlsx
Binary file not shown.
13
src/ReplicatedStorage/Json/AttributesUpgrade.json
Normal file
13
src/ReplicatedStorage/Json/AttributesUpgrade.json
Normal file
@ -0,0 +1,13 @@
|
||||
[
|
||||
{"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":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},
|
||||
{"id":10,"type":2,"effectAttribute":"wearNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":4},
|
||||
{"id":11,"type":2,"effectAttribute":"skillNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":3},
|
||||
{"id":12,"type":2,"effectAttribute":"extraAttributeNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":3},
|
||||
{"id":13,"type":2,"effectAttribute":"elementNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":3},
|
||||
{"id":14,"type":2,"effectAttribute":"elementDefNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":3},
|
||||
{"id":15,"type":2,"effectAttribute":"gemNumber","cost":[1,10,20],"lvAdd":[1,1],"battleValueLimit":[5,20],"maxLv":3}
|
||||
]
|
@ -40,22 +40,21 @@ end
|
||||
|
||||
-- 检查当前状态是否可执行
|
||||
function Behaviour:CheckStat()
|
||||
if not self.Character then warn("Behaviour Character not found") return false end
|
||||
if not self.Character then return true end
|
||||
-- 死亡检查
|
||||
if self.Character:GetState("Died") then return false end
|
||||
if self.Character:GetState("Died") then return true end
|
||||
|
||||
-- 执行状态中检查
|
||||
local ExecutingState = self.PlayerAI.ExecutingState
|
||||
-- 其他内容执行中,就false
|
||||
if ExecutingState == true then return false end
|
||||
return true
|
||||
if ExecutingState == true then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
-- 改变当前执行状态标记
|
||||
function Behaviour:ChangeExecutingState(State: boolean)
|
||||
if not self.Character then warn("Behaviour Character not found") return end
|
||||
local ExecutingState = self.PlayerAI.ExecutingState
|
||||
ExecutingState.Value = State
|
||||
self.PlayerAI.ExecutingState = State
|
||||
end
|
||||
|
||||
-- 销毁
|
||||
|
@ -20,6 +20,7 @@ function Character.new(Player: Player, CharacterModel: Model, CharacterData: tab
|
||||
self.Root = HumanoidRootPart
|
||||
self.Humanoid = mobHumanoid
|
||||
self.Origin = HumanoidRootPart:GetPivot()
|
||||
self.Player = Player
|
||||
self.TargetPlayerUserID = Player.UserId
|
||||
self.Connections = {}
|
||||
self.Stats = {}
|
||||
|
@ -12,6 +12,7 @@ local MobsProxy = require(ServerStorage.Proxy.MobsProxy)
|
||||
|
||||
local Move = {}
|
||||
Move.__index = Move
|
||||
setmetatable(Move, {__index = Behaviour})
|
||||
|
||||
function Move:Init(PlayerAI, Character: TypeList.Character, Player: Player)
|
||||
local self = Behaviour:Init(PlayerAI, Character)
|
||||
@ -24,7 +25,7 @@ function Move:Check(CheckInfo: table)
|
||||
if Behaviour.CheckStat(self) then return -1, self.CheckData end
|
||||
|
||||
local PlayerMobs = MobsProxy:GetPlayerMobs(self.Player)
|
||||
if not PlayerMobs then warn("PlayerMobs not found") return end
|
||||
if not PlayerMobs then return end
|
||||
|
||||
local closestMob, minDistance = nil, math.huge
|
||||
for _, Mob in PlayerMobs do
|
||||
@ -50,7 +51,7 @@ end
|
||||
function Move:Execute()
|
||||
self.ExeTask = task.spawn(function ()
|
||||
self:ChangeExecutingState(true)
|
||||
self.Character.Humanoid.WalkToPart.CFrame = self.CheckData["ClosestCharacter"].Instance.PrimaryPart.CFrame
|
||||
self.Character.Humanoid:MoveTo(self.CheckData["ClosestCharacter"].Instance:GetPivot().Position)
|
||||
task.wait(0.5)
|
||||
self:ChangeExecutingState(false)
|
||||
end)
|
||||
|
@ -31,6 +31,12 @@ function ArchiveProxy:IsPlayerDataLoaded(Player: Player)
|
||||
return true -- 成功加载
|
||||
end
|
||||
|
||||
function ArchiveProxy:CleanPlayerData(Player: Player)
|
||||
if not ArchiveProxy.pData[Player.UserId] then warn('CleanPlayerData: ', Player.Name, '数据不存在') return end
|
||||
ArchiveProxy.pData[Player.UserId] = {}
|
||||
print("清除数据成功")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local PlayerData = Instance.new("Configuration")
|
||||
|
@ -57,6 +57,7 @@ function DamageProxy:TakeDamage(Caster: TypeList.Character, Victim: TypeList.Cha
|
||||
-- 伤害计算
|
||||
local VictimHealth = Victim:GetAttributeValue("hp")
|
||||
Victim:ChangeAttributeValue("hp", math.max(0, VictimHealth - Damage))
|
||||
print("伤害数据打印", Damage, VictimHealth)
|
||||
end
|
||||
end
|
||||
|
||||
|
24
src/ServerStorage/Proxy/HelpProxy.luau
Normal file
24
src/ServerStorage/Proxy/HelpProxy.luau
Normal file
@ -0,0 +1,24 @@
|
||||
local HelpProxy = {}
|
||||
|
||||
--> Server
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
--> Events
|
||||
local RE_PlayerHelper = ReplicatedStorage.Events.RE_PlayerHelper
|
||||
|
||||
function HelpProxy:CleanPlayerData(Player: Player)
|
||||
local ArchiveProxy = require(script.Parent.ArchiveProxy)
|
||||
ArchiveProxy:CleanPlayerData(Player)
|
||||
end
|
||||
|
||||
RE_PlayerHelper.OnServerEvent:Connect(function(Player: Player, EventName: string, EventData: any)
|
||||
if EventName == "CleanPlayerData" then
|
||||
HelpProxy:CleanPlayerData(Player)
|
||||
elseif EventName == "AddItem" then
|
||||
local PlayerInfoProxy = require(script.Parent.PlayerInfoProxy)
|
||||
PlayerInfoProxy:ChangeItemCount(Player, EventData[1], EventData[2])
|
||||
print("添加物品成功", PlayerInfoProxy:GetItemCount(Player, EventData[1]))
|
||||
end
|
||||
end)
|
||||
|
||||
return HelpProxy
|
@ -15,6 +15,9 @@ local TypeList = require(ServerStorage.Base.TypeList)
|
||||
--> Json
|
||||
local JsonLevel = require(ReplicatedStorage.Json.Level)
|
||||
|
||||
--> Events
|
||||
local BD_ChallengeEnd = ReplicatedStorage.Events.BD_ChallengeEnd
|
||||
|
||||
--> Constants
|
||||
local STORE_NAME = "Level"
|
||||
local ENUM_LEVEL_TYPE = {
|
||||
@ -84,7 +87,7 @@ end
|
||||
local function OnMobDied(Player: Player, Mob: TypeList.Character)
|
||||
for _, mob in LevelProxy.pData[Player.UserId].Mobs do
|
||||
if mob ~= Mob then continue end
|
||||
table.remove(LevelProxy.pData[Player.UserId].Mobs, mob)
|
||||
table.remove(LevelProxy.pData[Player.UserId].Mobs, table.find(LevelProxy.pData[Player.UserId].Mobs, mob))
|
||||
|
||||
-- 怪物清除判断
|
||||
local LevelData = Utils:GetJsonData(JsonLevel, LevelProxy.pData[Player.UserId].LevelId)
|
||||
@ -149,8 +152,6 @@ function LevelProxy:InitPlayer(Player: Player)
|
||||
if key == "Task" or key == "Mobs" then continue end
|
||||
CreateLevelInstance(Player, ChallengeFolder, key, value)
|
||||
end
|
||||
|
||||
-- self:ChallengeLevel(Player, 1)
|
||||
end
|
||||
|
||||
-- 挑战关卡(挑战副本用另一个函数)
|
||||
@ -165,7 +166,7 @@ function LevelProxy:ChallengeLevel(Player: Player, LevelId: number)
|
||||
local LevelFolder = GetPlayerLevelWorkspaceFolder(Player.UserId)
|
||||
local ChallengeFolder = LevelFolder:FindFirstChild("Challenge")
|
||||
if not ChallengeFolder then warn("ChallengeFolder not found") return end
|
||||
local levelTask = task.defer(function()
|
||||
local levelTask = task.spawn(function()
|
||||
ChangeValue(Player, ChallengeFolder, "IsBoss", LevelData.type == 2 and true or false)
|
||||
ChangeValue(Player, ChallengeFolder, "LevelId", LevelId)
|
||||
ChangeValue(Player, ChallengeFolder, "Time", 0)
|
||||
@ -218,7 +219,7 @@ function LevelProxy:ChallengeLevel(Player: Player, LevelId: number)
|
||||
end
|
||||
end
|
||||
end)
|
||||
ChangeValue(Player, ChallengeFolder, "Task", levelTask)
|
||||
LevelProxy.pData[Player.UserId].Task = levelTask
|
||||
end
|
||||
|
||||
-- 挑战结束
|
||||
@ -226,8 +227,15 @@ function LevelProxy:ChallengeEnd(Player: Player, result: boolean)
|
||||
local pData = Utils:GetPlayerDataFolder(Player)
|
||||
local LevelFolder = Utils:CreateFolder(STORE_NAME, pData)
|
||||
local ProgressFolder = Utils:CreateFolder("Progress", LevelFolder)
|
||||
|
||||
-- 停止关卡循环
|
||||
if LevelProxy.pData[Player.UserId].Task then
|
||||
task.cancel(LevelProxy.pData[Player.UserId].Task)
|
||||
LevelProxy.pData[Player.UserId].Task = nil
|
||||
end
|
||||
|
||||
-- 清除剩余怪物
|
||||
for _, mob in LevelProxy.pData[Player.UserId].Mobs do mob:Died() end
|
||||
for _, mob in LevelProxy.pData[Player.UserId].Mobs do mob:Died(true) end
|
||||
LevelProxy.pData[Player.UserId].Mobs = {}
|
||||
|
||||
-- 判断玩家是否通关
|
||||
@ -239,6 +247,7 @@ function LevelProxy:ChallengeEnd(Player: Player, result: boolean)
|
||||
ChangeValue(Player, ProgressFolder, "BossFail", LevelProxy.pData[Player.UserId].LevelId)
|
||||
end
|
||||
end
|
||||
BD_ChallengeEnd:Fire(Player, LevelProxy.pData[Player.UserId].LevelId, result)
|
||||
end
|
||||
|
||||
function LevelProxy:OnPlayerRemoving(Player: Player)
|
||||
@ -249,7 +258,7 @@ function LevelProxy:OnPlayerRemoving(Player: Player)
|
||||
end
|
||||
-- 关卡存储数据清除
|
||||
if LevelProxy.pData[Player.UserId].Task then
|
||||
LevelProxy.pData[Player.UserId].Task:Cancel()
|
||||
task.cancel(LevelProxy.pData[Player.UserId].Task)
|
||||
end
|
||||
LevelProxy.pData[Player.UserId] = nil
|
||||
end
|
||||
|
@ -20,33 +20,27 @@ function AI:GetModelDistance(Unit1: Model, Unit2: Model): number
|
||||
end
|
||||
|
||||
function AI:GetClosestPlayer(Mob: TypeList.Character): (Player?, number?)
|
||||
local Closest = {Player = nil, Magnitude = math.huge}
|
||||
local Closest = {PlayerRole = nil, Magnitude = math.huge, Player = nil}
|
||||
|
||||
local ActivePlayer -- We retain a reference to this, so they have to get further away from the mob to stop following, instead of the usual distance.
|
||||
if Mob.Humanoid.WalkToPart then
|
||||
local Player = Players:GetPlayerFromCharacter(Mob.Humanoid.WalkToPart.Parent)
|
||||
if Player then
|
||||
ActivePlayer = Player
|
||||
end
|
||||
end
|
||||
|
||||
-- 临时的
|
||||
local PlayerRole = Mob.PlayerRole
|
||||
local Character = PlayerRole.Instance
|
||||
if Character == nil then warn("AI:GetClosestPlayer Character not found", Mob.Name) return end
|
||||
|
||||
for _, Player in Players:GetPlayers() do
|
||||
if Mob.TargetPlayerUserID == Player.UserId then
|
||||
local Character = Player.Character
|
||||
if not Character then continue end
|
||||
|
||||
local Magnitude = (Character:GetPivot().Position - Mob.Instance:GetPivot().Position).Magnitude
|
||||
local MaxDistance = (ActivePlayer == Player and (Mob.Config.FollowDistance or 32) * 2) or Mob.Config.FollowDistance or 32
|
||||
|
||||
if Magnitude <= MaxDistance and Magnitude < Closest.Magnitude then
|
||||
Closest.Player = Player
|
||||
Closest.Magnitude = Magnitude
|
||||
end
|
||||
Closest.Player = Player
|
||||
end
|
||||
end
|
||||
|
||||
local Magnitude = (Character:GetPivot().Position - Mob.Instance:GetPivot().Position).Magnitude
|
||||
-- 最大距离暂时设置大值
|
||||
local MaxDistance = Mob.Config.FollowDistance or 10000
|
||||
if Magnitude <= MaxDistance and Magnitude < Closest.Magnitude then
|
||||
Closest.PlayerRole = PlayerRole
|
||||
Closest.Magnitude = Magnitude
|
||||
end
|
||||
|
||||
return Closest.Player, Closest.Player and Closest.Magnitude
|
||||
return Closest.Player, Closest.PlayerRole, Closest.PlayerRole and Closest.Magnitude
|
||||
end
|
||||
|
||||
-- Adds the mob to the ActiveMobs table. This table runs a few times per second and updates follow & jump code for active mobs.
|
||||
@ -66,7 +60,10 @@ task.defer(function()
|
||||
for MobInstance, Mob in ActiveMobs do
|
||||
task.spawn(function()
|
||||
if not Mob.Stats.Died then
|
||||
local Player, distance = AI:GetClosestPlayer(Mob)
|
||||
-- 执行其他内容就停止
|
||||
if Mob.ExecutingState then return end
|
||||
|
||||
local Player, PlayerRole, distance = AI:GetClosestPlayer(Mob)
|
||||
local Enemy = Mob.Humanoid
|
||||
|
||||
-- Simulation
|
||||
@ -79,16 +76,22 @@ task.defer(function()
|
||||
end
|
||||
|
||||
-- Tracking
|
||||
if Player and Enemy then
|
||||
if Player and Enemy and PlayerRole then
|
||||
if PlayerRole.Stats.Died then return end
|
||||
if distance > 5 then
|
||||
Enemy:MoveTo(Player.Character:GetPivot().Position, Player.Character.PrimaryPart)
|
||||
else
|
||||
Mob.ExecutingState = true
|
||||
-- 停止移动
|
||||
Enemy:MoveTo(MobInstance:GetPivot().Position)
|
||||
-- 触发攻击逻辑
|
||||
task.wait(Mob.Config.attackSpeed)
|
||||
|
||||
-- 攻击间隔后再次判断状态
|
||||
if Mob.Stats.Died then return end
|
||||
if not Player then return end
|
||||
if PlayerRole.Stats.Died then return end
|
||||
|
||||
if AI:GetModelDistance(MobInstance, Player.Character) <= 5 then
|
||||
-- 调用伤害模块
|
||||
DamageProxy:TakeDamage(Mob, Mob.PlayerRole, {
|
||||
@ -99,6 +102,7 @@ task.defer(function()
|
||||
}
|
||||
})
|
||||
end
|
||||
Mob.ExecutingState = false
|
||||
end
|
||||
end
|
||||
else
|
||||
|
@ -62,6 +62,7 @@ function Mob.new(Player: Player, MobId: number, OnMobDied: ((Player: Player, Mob
|
||||
setmetatable(self, Mob) -- 继承Mob方法
|
||||
local PlayerFightProxy = require(ServerStorage.Proxy.PlayerFightProxy)
|
||||
self.PlayerRole = PlayerFightProxy:GetPlayerRole(Player)
|
||||
self.ExecutingState = false
|
||||
|
||||
-- 放入关卡中
|
||||
newMobModel.Parent = playerMobsFolder
|
||||
@ -80,9 +81,11 @@ function Mob.new(Player: Player, MobId: number, OnMobDied: ((Player: Player, Mob
|
||||
return self
|
||||
end
|
||||
|
||||
function Mob:Died()
|
||||
function Mob:Died(IsSkinOnDied: boolean?)
|
||||
MobsProxy:RemoveMob(self.Player, self.Instance)
|
||||
if self.OnDied then self.OnDied(self.Player, self) end
|
||||
if not IsSkinOnDied then
|
||||
if self.OnDied then self.OnDied(self.Player, self) end
|
||||
end
|
||||
Character.Died(self)
|
||||
end
|
||||
|
||||
@ -93,8 +96,8 @@ function MobsProxy:CreateMob(Player: Player, MobId: number, AtkBonus: number?, H
|
||||
local Mob = Mob.new(Player, MobId, OnMobDied)
|
||||
AI:StartTracking(Mob)
|
||||
-- 关卡系数
|
||||
-- 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 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
|
||||
MobsProxy.pData[Player.UserId][Mob.Instance] = Mob
|
||||
return Mob
|
||||
end
|
||||
|
@ -20,12 +20,12 @@ local JsonLevel = require(ReplicatedStorage.Json.Level)
|
||||
local LevelLoop = {}
|
||||
LevelLoop.__index = LevelLoop
|
||||
|
||||
function LevelLoop.new(Player: Player, Character: TypeList.Character)
|
||||
function LevelLoop.new(Player: Player, PlayerRole: TypeList.Character)
|
||||
print("LevelLoop:Init")
|
||||
local self = {}
|
||||
setmetatable(self, LevelLoop)
|
||||
self.Player = Player
|
||||
self.Character = Character
|
||||
self.PlayerRole = PlayerRole
|
||||
self.TaskAutoChallenge = nil
|
||||
|
||||
self.ConChallengeEnd = BD_ChallengeEnd.Event:Connect(function(Player: Player, LevelId: number)
|
||||
@ -38,7 +38,9 @@ function LevelLoop.new(Player: Player, Character: TypeList.Character)
|
||||
end
|
||||
|
||||
function LevelLoop:AutoChallenge()
|
||||
print("AutoChallenge")
|
||||
-- 重置玩家状态(先临时调用角色复活,之后复杂的内容再说)
|
||||
self.PlayerRole:Respawn()
|
||||
|
||||
local LevelFolder = game.Workspace:WaitForChild("Level"):WaitForChild(self.Player.UserId)
|
||||
local ProgressFolder = LevelFolder:FindFirstChild("Progress")
|
||||
|
||||
@ -51,7 +53,7 @@ function LevelLoop:AutoChallenge()
|
||||
LevelProxy:ChallengeLevel(self.Player, LevelId)
|
||||
end
|
||||
|
||||
function LevelLoop:OnChallengeEnd(Player: Player, LevelId: number)
|
||||
function LevelLoop:OnChallengeEnd(Player: Player, LevelId: number, result: boolean)
|
||||
self.TaskAutoChallenge = task.defer(function()
|
||||
task.wait(3)
|
||||
self:AutoChallenge()
|
||||
|
@ -5,10 +5,14 @@ PlayerAI.__index = PlayerAI
|
||||
--> Services
|
||||
local Players = game:GetService("Players")
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
--> Dependencies
|
||||
local TypeList = require(ServerStorage.Base.TypeList)
|
||||
|
||||
--> Events
|
||||
local RE_PlayerAI = ReplicatedStorage.Events.RE_PlayerAI
|
||||
|
||||
--> Variables
|
||||
local DamageProxy = require(ServerStorage.Proxy.DamageProxy)
|
||||
local ActivePlayers = {}
|
||||
@ -42,14 +46,21 @@ function PlayerAI.new(Player: Player, PlayerRole: TypeList.Character)
|
||||
self.Character = PlayerRole
|
||||
self.Player = Player
|
||||
self.ExecutingState = false
|
||||
self.PlayerControling = false
|
||||
|
||||
self.BehaviourList = {}
|
||||
self.LoopTask = task.spawn(function()
|
||||
while task.wait(0.25) do
|
||||
if self.Character.Stats.Died then continue end
|
||||
if self.PlayerControling then continue end
|
||||
self:Update()
|
||||
end
|
||||
end)
|
||||
|
||||
self.PlayerControlCon = RE_PlayerAI.OnServerEvent:Connect(function(Player: Player, ControlState: boolean)
|
||||
if Player ~= self.Player then return end
|
||||
self.PlayerControling = ControlState
|
||||
end)
|
||||
return self
|
||||
end
|
||||
|
||||
|
@ -48,11 +48,13 @@ end
|
||||
|
||||
function PlayerRole:Died()
|
||||
self:ChangeState("Died", true)
|
||||
self.Humanoid.WalkSpeed = 0
|
||||
LevelProxy:ChallengeEnd(self.Player, false)
|
||||
end
|
||||
|
||||
function PlayerRole:Respawn()
|
||||
self:ChangeState("Died", false)
|
||||
self.Humanoid.WalkSpeed = self.Config.walkSpeed
|
||||
self:ChangeAttributeValue("hp", self.Config.maxhp)
|
||||
-- 重置玩家位置
|
||||
|
||||
|
@ -12,6 +12,11 @@ local ArchiveProxy = require(ServerStorage.Proxy.ArchiveProxy)
|
||||
--> Json
|
||||
local JsonPlayerLv = require(ReplicatedStorage.Json.PlayerLv)
|
||||
local JsonItem = require(ReplicatedStorage.Json.ItemProp)
|
||||
local JsonAttributesUpgrade = require(ReplicatedStorage.Json.AttributesUpgrade)
|
||||
|
||||
--> Events
|
||||
local RE_PlayerTip = ReplicatedStorage.Events.RE_PlayerTip
|
||||
local RE_UpgradeAttributes = ReplicatedStorage.Events.RE_UpgradeAttributes
|
||||
|
||||
--> Constants
|
||||
local STORE_NAME = "PlayerInfo"
|
||||
@ -34,7 +39,7 @@ local function GetPlayerInfoFolder(Player: Player)
|
||||
end
|
||||
|
||||
-- 创建玩家信息实例
|
||||
local function CreateInfoInstance(Player: Player, Folder: any, StateKey: string, StateType: string, StateValue: any)
|
||||
local function CreateInfoInstance(Player: Player, Folder: any, StateKey: string, StateType: string, StateValue: any?)
|
||||
if not Player and not Folder and not StateKey and not StateType then
|
||||
warn('创建玩家信息实例失败: ' , Player.Name, Folder.Name, StateKey, StateType, StateValue)
|
||||
return
|
||||
@ -81,21 +86,83 @@ function PlayerInfoProxy:InitPlayer(Player: Player)
|
||||
local PlayerInfoFolder = Utils:CreateFolder("PlayerInfo", pData)
|
||||
local StatsFolder = Utils:CreateFolder("Stats", PlayerInfoFolder)
|
||||
local ItemsFolder = Utils:CreateFolder("Items", PlayerInfoFolder)
|
||||
local AttributesUpgradeFolder = Utils:CreateFolder("AttributesUpgrade", PlayerInfoFolder)
|
||||
|
||||
-- 新玩家数据初始化
|
||||
if not ArchiveProxy.pData[Player.UserId][STORE_NAME] then
|
||||
ArchiveProxy.pData[Player.UserId][STORE_NAME] = {}
|
||||
ArchiveProxy.pData[Player.UserId][STORE_NAME].Stats = {}
|
||||
ArchiveProxy.pData[Player.UserId][STORE_NAME].Items = {}
|
||||
ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade = {}
|
||||
end
|
||||
|
||||
-- 放在外面是为了以后系统新增内容方便(同时不用在初始化数据是做写入了)
|
||||
ExtraAddPlayerStats(Player, ArchiveProxy.pData[Player.UserId][STORE_NAME].Stats)
|
||||
|
||||
-- 创建玩家信息实例
|
||||
for ItemId, ItemValue in ArchiveProxy.pData[Player.UserId][STORE_NAME].Items do
|
||||
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)
|
||||
end
|
||||
for AttributeId, AttributeLv in ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade do
|
||||
CreateInfoInstance(Player, AttributesUpgradeFolder, AttributeId, "NumberValue", AttributeLv)
|
||||
end
|
||||
end
|
||||
|
||||
-- 玩家属性升级
|
||||
function PlayerInfoProxy:UpgradeAttribute(Player: Player, AttributeId: number)
|
||||
if not Player or not AttributeId then warn('升级属性失败: ', Player.Name, AttributeId) return end
|
||||
|
||||
local AttributesUpgradeFolder = GetPlayerInfoFolder(Player):FindFirstChild("AttributesUpgrade")
|
||||
|
||||
local upgradeTable = ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade
|
||||
local nowLv = upgradeTable[AttributeId]
|
||||
if nowLv == nil then nowLv = 0 end
|
||||
|
||||
local attributeData = Utils:GetIdDataFromJson(JsonAttributesUpgrade, AttributeId)
|
||||
local requireBattleValue, requireMoney
|
||||
|
||||
if nowLv == 0 then
|
||||
requireMoney = attributeData["cost"][2]
|
||||
requireBattleValue = attributeData["battleValueLimit"][1]
|
||||
else
|
||||
requireMoney = attributeData["cost"][2] + (nowLv - 1) * attributeData["cost"][3]
|
||||
requireBattleValue = attributeData["battleValueLimit"][1] + (nowLv - 1) * attributeData["battleValueLimit"][2]
|
||||
end
|
||||
|
||||
-- TODO 判断战力是否足够(暂无战力计算)
|
||||
|
||||
-- 判断是否到达等级上限
|
||||
print(nowLv, attributeData["maxLv"])
|
||||
if attributeData["maxLv"] ~= nil then
|
||||
if nowLv >= attributeData["maxLv"] then
|
||||
local tip = '升级属性失败: ' .. AttributeId .. ' 已到达等级上限'
|
||||
RE_PlayerTip:FireClient(Player, tip)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- 判断钱是否足够
|
||||
if not self:HasEnoughItem(Player, attributeData["cost"][1], requireMoney) then
|
||||
local tip = '升级属性失败: ' .. AttributeId .. ' 钱不够'
|
||||
RE_PlayerTip:FireClient(Player, tip)
|
||||
return
|
||||
end
|
||||
-- 扣钱
|
||||
self:ChangeItemCount(Player, 1, -requireMoney)
|
||||
|
||||
-- 升级
|
||||
if nowLv == 0 then
|
||||
-- 首次生成属性
|
||||
upgradeTable[AttributeId] = 1
|
||||
CreateInfoInstance(Player, AttributesUpgradeFolder, AttributeId, "NumberValue", upgradeTable[AttributeId])
|
||||
else
|
||||
-- 更新属性显示
|
||||
upgradeTable[AttributeId] = nowLv + 1
|
||||
ChangeInfoInstance(Player, AttributesUpgradeFolder, AttributeId, upgradeTable[AttributeId])
|
||||
end
|
||||
end
|
||||
|
||||
-- 添加经验
|
||||
@ -161,6 +228,29 @@ function PlayerInfoProxy:GetItemCount(Player: Player, ItemId: number)
|
||||
return playerInfoData[ItemId]
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- 获取升级加点属性
|
||||
function PlayerInfoProxy:GetPlayerUpgradeAttributes(Player: Player)
|
||||
if not Player then warn('获取玩家属性失败: ', Player.Name) return end
|
||||
local playerInfoData = ArchiveProxy.pData[Player.UserId][STORE_NAME]
|
||||
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]
|
||||
end
|
||||
return attributes
|
||||
end
|
||||
|
||||
-- 获取玩家属性
|
||||
function PlayerInfoProxy:GetPlayerAttributes(Player: Player)
|
||||
local attributesList = {}
|
||||
attributesList.UpgradeAttributes = self:GetPlayerUpgradeAttributes(Player)
|
||||
return attributesList
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function PlayerInfoProxy:OnPlayerRemoving(Player: Player)
|
||||
|
||||
end
|
||||
@ -169,4 +259,9 @@ ReplicatedStorage.Remotes.PlayerRemoving.Event:Connect(function(Player: Player)
|
||||
PlayerInfoProxy:OnPlayerRemoving(Player)
|
||||
end)
|
||||
|
||||
RE_UpgradeAttributes.OnServerEvent:Connect(function(Player: Player, AttributeId: number)
|
||||
PlayerInfoProxy:UpgradeAttribute(Player, AttributeId)
|
||||
print(ArchiveProxy.pData[Player.UserId][STORE_NAME].AttributesUpgrade)
|
||||
end)
|
||||
|
||||
return PlayerInfoProxy
|
32
src/StarterPlayerScripts/ClientMain/Helper.luau
Normal file
32
src/StarterPlayerScripts/ClientMain/Helper.luau
Normal file
@ -0,0 +1,32 @@
|
||||
local Helper = {}
|
||||
|
||||
--> Server
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
--> Events
|
||||
local RE_PlayerHelper = ReplicatedStorage.Events.RE_PlayerHelper
|
||||
local RE_UpgradeAttributes = ReplicatedStorage.Events.RE_UpgradeAttributes
|
||||
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
UserInputService.InputBegan:Connect(function(input, gameProcessed)
|
||||
if gameProcessed then return end
|
||||
if input.UserInputType == Enum.UserInputType.Keyboard then
|
||||
if input.KeyCode == Enum.KeyCode.H then
|
||||
RE_PlayerHelper:FireServer("CleanPlayerData")
|
||||
elseif input.KeyCode == Enum.KeyCode.J then
|
||||
print("添加物品")
|
||||
RE_PlayerHelper:FireServer("AddItem", {1, 100})
|
||||
elseif input.KeyCode == Enum.KeyCode.K then
|
||||
RE_UpgradeAttributes:FireServer(1)
|
||||
elseif input.KeyCode == Enum.KeyCode.L then
|
||||
RE_UpgradeAttributes:FireServer(2)
|
||||
elseif input.KeyCode == Enum.KeyCode.M then
|
||||
RE_UpgradeAttributes:FireServer(3)
|
||||
elseif input.KeyCode == Enum.KeyCode.N then
|
||||
RE_UpgradeAttributes:FireServer(4)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
return Helper
|
31
src/StarterPlayerScripts/ClientMain/PlayerControl.luau
Normal file
31
src/StarterPlayerScripts/ClientMain/PlayerControl.luau
Normal file
@ -0,0 +1,31 @@
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
local PlayerControl = {}
|
||||
|
||||
-- 监听按键按下
|
||||
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
|
||||
onKeyDown(key)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- 监听按键松开
|
||||
function PlayerControl.ListenMoveKeyUp(onKeyUp)
|
||||
UserInputService.InputEnded: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
|
||||
onKeyUp(key)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return PlayerControl
|
@ -19,6 +19,11 @@ local PlayerGui = Player:WaitForChild("PlayerGui")
|
||||
local FormatNumber = require(ReplicatedStorage.Modules.FormatNumber)
|
||||
local Tween = require(ReplicatedStorage.Modules.Tween)
|
||||
local SFX = require(ReplicatedStorage.Modules.SFX)
|
||||
local PlayerControl = require(script.PlayerControl)
|
||||
local Helper = require(script.Helper)
|
||||
|
||||
--> Events
|
||||
local RE_PlayerAI = ReplicatedStorage.Events.RE_PlayerAI
|
||||
|
||||
--> Variables
|
||||
local Random = Random.new()
|
||||
@ -28,6 +33,16 @@ local ClientMainPrefabs = Player.PlayerScripts.ClientMainPrefabs
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
PlayerControl.ListenMoveKeyDown(function(key)
|
||||
-- print("按下了: ", key.Name)
|
||||
RE_PlayerAI:FireServer(true)
|
||||
end)
|
||||
|
||||
PlayerControl.ListenMoveKeyUp(function(key)
|
||||
-- print("松开了: ", key.Name)
|
||||
RE_PlayerAI:FireServer(false)
|
||||
end)
|
||||
|
||||
-- Initially require client-sided modules
|
||||
for _, Item in script:GetChildren() do
|
||||
if Item:IsA("ModuleScript") then
|
||||
|
Loading…
x
Reference in New Issue
Block a user