-- 关卡代理 local LevelProxy = {} --> Services local ReplicatedStorage = game:GetService("ReplicatedStorage") local ServerStorage = game:GetService("ServerStorage") local Players = game:GetService("Players") --> Variables local Utils = require(ReplicatedStorage.Tools.Utils) local ArchiveProxy = require(ServerStorage.Proxy.ArchiveProxy) local MobsProxy = require(ServerStorage.Proxy.MobsProxy) local TypeList = require(ServerStorage.Base.TypeList) --> Json local JsonLevel = require(ReplicatedStorage.Json.Level) --> Constants local STORE_NAME = "Level" local ENUM_LEVEL_TYPE = { Main = 1, } -------------------------------------------------------------------------------- -- 初始化生成关卡目录 local LevelFolder = Utils:CreateFolder(STORE_NAME, game.Workspace) -------------------------------------------------------------------------------- -- 获取玩家关卡文件夹 local function GetPlayerLevelFolder(Player: Player) local pData = Utils:GetPlayerDataFolder(Player) if not pData then return end local LevelFolder = pData:FindFirstChild("Level") return LevelFolder end -- 获取玩家关卡Workspace目录 local function GetPlayerLevelWorkspaceFolder(PlayerUserId: string) return LevelFolder:FindFirstChild(PlayerUserId) end -- 创建关卡信息实例 local function CreateLevelInstance(Player: Player, Folder: Instance, LevelKey: string, LevelValue: number) if not Player or not Folder or not LevelKey or not LevelValue then return end local LevelInstance = Instance.new("NumberValue") LevelInstance.Name = LevelKey LevelInstance.Parent = Folder LevelInstance.Value = LevelValue return LevelInstance end -- 初始化玩家关卡信息 local function ExtraAddPlayerLevel(Player: Player, LevelData: table) if not Player or not LevelData then return end -- 如果列表中不包含信息就添加到表中 for LevelKey, LevelValue in ENUM_LEVEL_TYPE do if not LevelData[LevelKey] then LevelData[LevelKey] = LevelValue end end end local EXCEPT_KEY = { "Task", "Mobs"} local function ChangeValue(Player: Player, Folder: Instance, LevelKey: string, LevelValue: any) if not Player or not Folder or not LevelKey or not LevelValue then return end local ValueInstance = Folder:FindFirstChild(LevelKey) if not ValueInstance then return end local storeTable if Folder.Name == "Challenge" then storeTable = LevelProxy.pData[Player.UserId] else storeTable = ArchiveProxy.pData[Player.UserId][STORE_NAME].Progress end storeTable[LevelKey] = LevelValue if not table.find(EXCEPT_KEY, LevelKey) then ValueInstance.Value = LevelValue end 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) -- 怪物清除判断 local LevelData = Utils:GetJsonData(JsonLevel, LevelProxy.pData[Player.UserId].LevelId) if LevelProxy.pData[Player.UserId].SpawnWaveFinish and #LevelProxy.pData[Player.UserId].Mobs == 0 then if LevelProxy.pData[Player.UserId].NowWave < #LevelData["wave"] then -- 波数增长 LevelProxy.pData[Player.UserId].NowWave = LevelProxy.pData[Player.UserId].NowWave + 1 -- 新波次重置怪物生成状态标记 local ChallengeFolder = LevelFolder:FindFirstChild("Challenge") ChangeValue(Player, ChallengeFolder, "SpawnWaveFinish", false) elseif LevelProxy.pData[Player.UserId].NowWave >= #LevelData["wave"] then -- 结束判断 LevelProxy:ChallengeEnd(Player, true) end end break end end -------------------------------------------------------------------------------- function LevelProxy:InitPlayer(Player: Player) local pData = Utils:GetPlayerDataFolder(Player) if not pData then return end local LevelFolder = Utils:CreateFolder(STORE_NAME, pData) local ProgressFolder = Utils:CreateFolder("Progress", LevelFolder) local DungeonFolder = Utils:CreateFolder("Dungeon", LevelFolder) local ChallengeFolder = Utils:CreateFolder("Challenge", LevelFolder) -- 当前关卡状态 Utils:CreateFolder("Stats", LevelFolder) -- 关卡目录下生成玩家目录 local spawnFloder = Utils:CreateFolder(Player.UserId, game.Workspace:FindFirstChild(STORE_NAME)) -- 新玩家数据初始化 if not ArchiveProxy.pData[Player.UserId][STORE_NAME] then ArchiveProxy.pData[Player.UserId][STORE_NAME] = {} ArchiveProxy.pData[Player.UserId][STORE_NAME].Progress = {} -- 副本之后再做 ArchiveProxy.pData[Player.UserId][STORE_NAME].Dungeon = {} end ExtraAddPlayerLevel(Player, ArchiveProxy.pData[Player.UserId][STORE_NAME].Progress) -- 前端变化 for LevelKey, LevelValue in ArchiveProxy.pData[Player.UserId][STORE_NAME].Progress do CreateLevelInstance(Player, ProgressFolder, LevelKey, LevelValue) end -- 本地内容初始化(关卡挑战信息,不存储) if not LevelProxy.pData then LevelProxy.pData = {} end if not LevelProxy.pData[Player.UserId] then LevelProxy.pData[Player.UserId] = {} end LevelProxy.pData[Player.UserId].Task = nil LevelProxy.pData[Player.UserId].Time = 0 LevelProxy.pData[Player.UserId].LevelId = 0 LevelProxy.pData[Player.UserId].MaxTime = 0 LevelProxy.pData[Player.UserId].IsBoss = false LevelProxy.pData[Player.UserId].NowWave = 0 LevelProxy.pData[Player.UserId].ShouldWave = 0 LevelProxy.pData[Player.UserId].SpawnWaveFinish = false LevelProxy.pData[Player.UserId].Mobs = {} -- 关卡挑战信息前端 for key, value in LevelProxy.pData[Player.UserId] do if key == "Task" or key == "Mobs" then continue end CreateLevelInstance(Player, ChallengeFolder, key, value) end end -- 挑战关卡(挑战副本用另一个函数) function LevelProxy:ChallengeLevel(Player: Player, LevelId: number) local LevelData = Utils:GetJsonData(JsonLevel, LevelId) if not LevelData then warn("Level Data not found", LevelId) return end -- 给前端传数据,做表现 -- 场景后端生成 -- 后端生成当前关卡状态数据 local LevelFolder = GetPlayerLevelWorkspaceFolder(Player.UserId) local ChallengeFolder = LevelFolder:FindFirstChild("Challenge") if not ChallengeFolder then return end local levelTask = task.defer(function() ChangeValue(Player, ChallengeFolder, "IsBoss", LevelData.type == 1 and true or false) ChangeValue(Player, ChallengeFolder, "LevelId", LevelId) ChangeValue(Player, ChallengeFolder, "Time", 0) ChangeValue(Player, ChallengeFolder, "NowWave", 0) ChangeValue(Player, ChallengeFolder, "ShouldWave", 1) ChangeValue(Player, ChallengeFolder, "MaxTime", LevelData.timeLimit or 0) ChangeValue(Player, ChallengeFolder, "Mobs", {}) if LevelData.timeLimit then while task.wait(1) do ChangeValue(Player, ChallengeFolder, "Time", LevelProxy.pData[Player.UserId].Time + 1) -- 关卡生成 if LevelProxy.pData[Player.UserId].Wave < #LevelData.wave then ChangeValue(Player, ChallengeFolder, "Wave", LevelProxy.pData[Player.UserId].Wave + 1) end if LevelProxy.pData[Player.UserId].NowWave < LevelProxy.pData[Player.UserId].ShouldWave then ChangeValue(Player, ChallengeFolder, "NowWave", LevelProxy.pData[Player.UserId].NowWave + 1) local waveData = LevelData.wave[LevelProxy.pData[Player.UserId].NowWave] for i = 1, #waveData, 3 do local mobId = waveData[i + 1] local mobCount = waveData[i + 2] for _ = 1, mobCount do local mob = MobsProxy:CreateMob(Player, mobId, LevelData.atkBonus, LevelData.hpBonus, OnMobDied) table.insert(LevelProxy.pData[Player.UserId].Mobs, mob) end end ChangeValue(Player, ChallengeFolder, "SpawnWaveFinish", true) end -- 时间结束 if LevelProxy.pData[Player.UserId].Time >= LevelData.timeLimit then self:ChallengeEnd(Player, false) break end end end end) ChangeValue(Player, ChallengeFolder, "Task", levelTask) end -- 挑战结束 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) -- 清除剩余怪物 for _, mob in LevelProxy.pData[Player.UserId].Mobs do mob:Died() end LevelProxy.pData[Player.UserId].Mobs = {} -- 判断玩家是否通关 if result then ChangeValue(Player, ProgressFolder, "LevelId", LevelProxy.pData[Player.UserId].LevelId + 1) end end function LevelProxy:OnPlayerRemoving(Player: Player) -- 关卡文件夹清除 local PlayerLevelFolder = GetPlayerLevelWorkspaceFolder(Player.UserId) if PlayerLevelFolder then PlayerLevelFolder:Destroy() end -- 关卡存储数据清除 if LevelProxy.pData[Player.UserId].Task then LevelProxy.pData[Player.UserId].Task:Cancel() end LevelProxy.pData[Player.UserId] = nil end -- ReplicatedStorage.Remotes.PlayerRemoving.Event:Connect(function(PlayerUserId: string) -- LevelProxy:OnPlayerRemoving(PlayerUserId) -- end) Players.PlayerRemoving:Connect(function(Player: Player) LevelProxy:OnPlayerRemoving(Player) end) return LevelProxy