初始化提交
This commit is contained in:
		
							
								
								
									
										112
									
								
								Content/Lua/GamePlay/Level/BusyActorManagerSubSystem.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								Content/Lua/GamePlay/Level/BusyActorManagerSubSystem.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | ||||
| local FVector = import "Vector" | ||||
| local Vector2D = require("Utils.Vector2D") | ||||
| local Library = import "BusyGamePlayLibrary" | ||||
| local GameplayStatics = import("GameplayStatics") | ||||
|  | ||||
| local SubSystem = {} | ||||
|  | ||||
| local function GetNearestBonfire(system, x, y) | ||||
|     local selected_bonfire = nil | ||||
|     local selected_distance = nil | ||||
|  | ||||
|     for _, bonfire in ipairs(system.bonfire_list) do | ||||
|         local pos = bonfire:K2_GetActorLocation() | ||||
|         local distance = (x - pos.X) ^ 2 + (y - pos.Y) ^ 2 | ||||
|         if selected_distance == nil or distance < selected_distance then | ||||
|             selected_distance = distance | ||||
|             selected_bonfire = bonfire | ||||
|         end | ||||
|     end | ||||
|     return selected_bonfire | ||||
| end | ||||
|  | ||||
| function SubSystem:ctor() | ||||
|     self.current_role = nil | ||||
|     self.bonfire_list = {}      -- 所有的篝火列表 | ||||
| end | ||||
|  | ||||
| function SubSystem:ReceiveSubSystemInitialize() | ||||
|     self.current_role = nil | ||||
|     self.bonfire_list = {} | ||||
| end | ||||
|  | ||||
| function SubSystem:GetNearestBonfire() | ||||
|     if self.current_role then | ||||
|         local cur_pos = self.current_role:K2_GetActorLocation() | ||||
|         return GetNearestBonfire(self, cur_pos.X, cur_pos.Y) | ||||
|     end | ||||
|     return nil | ||||
| end | ||||
|  | ||||
| function SubSystem:SpawnBonfire(position) | ||||
|     local pos = FVector() | ||||
|     local world = self:K2_GetWorld() | ||||
|     local cls = Library.GetGameClass("Bonfire") | ||||
|     pos.X, pos.Y, pos.Z = position.X, position.Y, 20 | ||||
|     local bonfire = world:SpawnActor(cls, pos, nil, nil) | ||||
|     table.insert(self.bonfire_list, bonfire) | ||||
|     return bonfire | ||||
| end | ||||
|  | ||||
| function SubSystem:SpawnRole(bonfire) | ||||
|     local role_pos = FVector() | ||||
|     local world = self:K2_GetWorld() | ||||
|     local pos = bonfire:K2_GetActorLocation() | ||||
|     local cls = Library.GetGameClass("BusyRole") | ||||
|     role_pos.X, role_pos.Y, role_pos.Z = pos.X, pos.Y, pos.Z + 10 | ||||
|     self.current_role = world:SpawnActor(cls, role_pos, nil, nil) | ||||
|     if self.current_role ~= nil then | ||||
|         self.current_role:SetRole("Rabbit") | ||||
|         return self.current_role | ||||
|     else | ||||
|         return nil | ||||
|     end | ||||
| end | ||||
|  | ||||
| function SubSystem:SpawnLevelItem(item_id) | ||||
|     -- 随机在角色周围生成 | ||||
|  | ||||
|     local distance = math.random(128, 500) | ||||
|     local angle = (math.random(0, 360) / 360) * 2 * 3.14; | ||||
|  | ||||
|     local world = self:K2_GetWorld() | ||||
|     local item_position = FVector() | ||||
|     local center = self.current_role:K2_GetActorLocation() | ||||
|     local cls = import("BusyLevelItem") | ||||
|  | ||||
|     item_position.Z = center.Z - 1 | ||||
|     item_position.X = center.X + math.cos(angle) * distance | ||||
|     item_position.Y = center.Y + math.sin(angle) * distance | ||||
|  | ||||
|     local item = world:SpawnActor(cls, item_position, nil, nil) | ||||
|     item:SetLevelItemID(item_id) | ||||
|     return center | ||||
| end | ||||
|  | ||||
| function SubSystem:SpawnLevelItemReward(level_item) | ||||
|     assert(self.current_role ~= nil) | ||||
|  | ||||
|     local world = self:K2_GetWorld() | ||||
|     local cls = Library.GetGameClass("LevelItemReward") | ||||
|  | ||||
|     local random_angle = (math.random() - 0.5) * (math.pi / 2) | ||||
|     local direction = Vector2D.Normalize(self.current_role:GetMoveDirection()) | ||||
|  | ||||
|     local sin, cos = math.sin(random_angle), math.cos(random_angle) | ||||
|  | ||||
|     -- 应用旋转矩阵 | ||||
|     direction.X = direction.X * cos - direction.Y * sin | ||||
|     direction.Y = direction.X * sin + direction.Y * cos | ||||
|  | ||||
|     local item_location = level_item:K2_GetActorLocation() | ||||
|  | ||||
|     local reward_location = Vector2D.Add(item_location, Vector2D.Mul(direction, 200)) | ||||
|  | ||||
|     local item = world:SpawnActor(cls, | ||||
|         Vector2D.ToUnrealEngine3D(reward_location, item_location.Z), | ||||
|         nil, nil | ||||
|     ) | ||||
|     return item | ||||
| end | ||||
|  | ||||
| return Class(nil, nil, SubSystem) | ||||
							
								
								
									
										119
									
								
								Content/Lua/GamePlay/Level/BusyLevelItemGenerator.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								Content/Lua/GamePlay/Level/BusyLevelItemGenerator.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | ||||
| ---@class ItemGenerator 物品生成器类 | ||||
| local ItemGenerator = { | ||||
|     item_data = {}, | ||||
|     period = 100, | ||||
|     item_distributions = {} | ||||
| } | ||||
| ItemGenerator.__index = ItemGenerator | ||||
|  | ||||
| ---数组洗牌函数(Fisher-Yates算法) | ||||
| ---@param array any[] 需要打乱顺序的数组 | ||||
| local function ShuffleArray(array) | ||||
|     for i = #array, 2, -1 do  -- 从后往前遍历 | ||||
|         local j = math.random(i)  -- 生成1到i的随机数 | ||||
|         array[i], array[j] = array[j], array[i]  -- 交换元素位置 | ||||
|     end | ||||
| end | ||||
|  | ||||
| ---创建物品生成器实例 | ||||
| ---@param period number 生成周期次数 | ||||
| ---@param item_data table<number, number> 物品配置表 {物品ID = 总生成数量} | ||||
| ---@return ItemGenerator 物品生成器实例 | ||||
| local function CreateItemGenerator(period, item_data) | ||||
|     local self = setmetatable({}, ItemGenerator) | ||||
|     ---@type number 存储生成周期 | ||||
|     self.period = period | ||||
|     ---@type table<number, number> 原始配置数据 | ||||
|     self.item_data = item_data | ||||
|     ---@type number 当前调用次数 | ||||
|     self.current_call = 0 | ||||
|     ---@type table<number, number[]> 物品分布数据结构 | ||||
|     self.item_distributions = {} | ||||
|     self:InitializeDistributions() | ||||
|     return self | ||||
| end | ||||
|  | ||||
| ---初始化物品分布数据 | ||||
| function ItemGenerator:InitializeDistributions() | ||||
|     -- 遍历所有物品配置 | ||||
|     for item_id, total in pairs(self.item_data) do | ||||
|         -- 计算基础值和余数(保证总数 = 基础值*period + 余数) | ||||
|         local base = math.floor(total / self.period) | ||||
|         local remainder = total % self.period | ||||
|  | ||||
|         -- 创建初始分布数组(全部填充基础值) | ||||
|         local distribution = {} | ||||
|         for i = 1, self.period do | ||||
|             distribution[i] = base | ||||
|         end | ||||
|  | ||||
|         -- 生成索引数组并洗牌(用于随机分配余数) | ||||
|         local indices = {} | ||||
|         for i = 1, self.period do | ||||
|             indices[i] = i | ||||
|         end | ||||
|         ShuffleArray(indices)  -- 打乱索引顺序 | ||||
|  | ||||
|         -- 将余数随机分配到前remainder个位置 | ||||
|         for i = 1, remainder do | ||||
|             distribution[indices[i]] = distribution[indices[i]] + 1 | ||||
|         end | ||||
|  | ||||
|         -- 存储当前物品的分布数组 | ||||
|         self.item_distributions[item_id] = distribution | ||||
|     end | ||||
| end | ||||
|  | ||||
| ---重置生成器状态(当调用次数超过N时触发) | ||||
| function ItemGenerator:Reinitialize() | ||||
|     self:InitializeDistributions()  -- 重新生成分布数据 | ||||
|     self.current_call = 0           -- 重置调用计数器 | ||||
| end | ||||
|  | ||||
| ---生成物品列表(每次调用产生一个周期的结果) | ||||
| ---@return number[] 包含物品ID的数组(结果经过随机排序) | ||||
| function ItemGenerator:Generate() | ||||
|     -- 当超过周期次数时重置状态 | ||||
|     if self.current_call >= self.period then | ||||
|         self:Reinitialize() | ||||
|     end | ||||
|  | ||||
|     local current_step = self.current_call + 1  -- 获取当前步骤(1-based) | ||||
|     local result = {}  -- 结果收集器 | ||||
|  | ||||
|     -- 遍历所有物品的分布数据 | ||||
|     for item_id, distribution in pairs(self.item_distributions) do | ||||
|         local count = distribution[current_step]  -- 获取当前步骤应生成数量 | ||||
|         for _ = 1, count do | ||||
|             table.insert(result, item_id)  -- 按数量添加物品ID到结果集 | ||||
|         end | ||||
|     end | ||||
|  | ||||
|     ShuffleArray(result)  -- 打乱结果顺序保证随机性 | ||||
|     self.current_call = self.current_call + 1  -- 增加调用计数器 | ||||
|  | ||||
|     return result | ||||
| end | ||||
|  | ||||
| ---获取当前未生成的物品剩余数量 | ||||
| ---@return table<number, number> 返回物品ID和剩余数量的映射表 | ||||
| function ItemGenerator:GetRemainingItems() | ||||
|     local remaining = {} | ||||
|     local current_step = self.current_call  -- 注意这里使用已调用次数(0-based) | ||||
|  | ||||
|     -- 遍历所有物品的分布数据 | ||||
|     for item_id, distribution in pairs(self.item_distributions) do | ||||
|         local total_remaining = 0 | ||||
|  | ||||
|         -- 计算从下一个步骤到周期结束的总数量 | ||||
|         for step = current_step + 1, self.period do | ||||
|             total_remaining = total_remaining + distribution[step] | ||||
|         end | ||||
|  | ||||
|         remaining[item_id] = total_remaining | ||||
|     end | ||||
|  | ||||
|     return remaining | ||||
| end | ||||
|  | ||||
| return CreateItemGenerator | ||||
							
								
								
									
										69
									
								
								Content/Lua/GamePlay/Level/BusyLevelLogicSubSystem.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								Content/Lua/GamePlay/Level/BusyLevelLogicSubSystem.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| local SubSystem = {} | ||||
| local Reactive = require("Core.Reactive") | ||||
| local Library = import("BusyGamePlayLibrary") | ||||
| local GameplayStatics = import("GameplayStatics") | ||||
| local BusyGamePlayLibrary = import("BusyGamePlayLibrary") | ||||
|  | ||||
|  | ||||
| local function CreateItemGenerator(level_config_data) | ||||
|     local Generator = require("GamePlay.Level.BusyLevelItemGenerator") | ||||
|  | ||||
|     local item_data = {} | ||||
|     local period = level_config_data.Period | ||||
|     for k, v in pairs(level_config_data.LevelItemIds) do | ||||
|         item_data[k] = v.CountOfPeriod | ||||
|     end | ||||
|     return Generator(period, item_data) | ||||
| end | ||||
|  | ||||
| function SubSystem:ReceiveSubSystemInitialize() | ||||
|     local world = BusyGamePlayLibrary.K2_GetWorld(self) | ||||
|     self.start_time = GameplayStatics.GetTimeSeconds(world) | ||||
|  | ||||
|     self.proxy = Reactive.ReactiveProperty({ | ||||
|         current_seconds = 0 | ||||
|     }) | ||||
|  | ||||
| end | ||||
|  | ||||
| function SubSystem:ReceiveWorldBeginPlay() | ||||
|     local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem").Get(self) | ||||
|  | ||||
|     -- 读取关卡配置 | ||||
|     local is_suc, row_data = Library.GetLevelBaseConfig("Default", nil) | ||||
|     assert(is_suc == true, "Can't find level base config") | ||||
|     self.level_base_config = row_data | ||||
|  | ||||
|     -- 创建物品生成器 | ||||
|     self.generator = CreateItemGenerator(row_data) | ||||
|  | ||||
|     -- 创建初始篝火 | ||||
|     local bonfire = BusyActorManagerSubSystem:SpawnBonfire(row_data.FirstBonfirePosition) | ||||
|  | ||||
|     -- 创建角色 | ||||
|     local role = BusyActorManagerSubSystem:SpawnRole(bonfire) | ||||
|     GameplayStatics.GetPlayerController(self, 0):Possess(role) | ||||
| end | ||||
|  | ||||
| function SubSystem:ReceiveSubSystemTick(DeltaTime) | ||||
|     -- local proxy = self.proxy | ||||
|     -- local world = BusyGamePlayLibrary.K2_GetWorld(self) | ||||
|     -- local current_time = GameplayStatics.GetTimeSeconds(world) | ||||
|     -- local escapse_time = math.floor(current_time - self.start_time) | ||||
|     -- if escapse_time > proxy.current_seconds then | ||||
|     --     self:TrySpawnLevelItem() | ||||
|     --     proxy.current_seconds = escapse_time | ||||
|     --     print(proxy.current_seconds) | ||||
|     -- end | ||||
| end | ||||
|  | ||||
| function SubSystem:TrySpawnLevelItem() | ||||
|     local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem").Get(self) | ||||
|     local items = self.generator:Generate() | ||||
|     for i, item_id in pairs(items) do | ||||
|         BusyActorManagerSubSystem:SpawnLevelItem(item_id) | ||||
|         print(i, item_id) | ||||
|     end | ||||
| end | ||||
|  | ||||
| return Class(nil, nil, SubSystem) | ||||
		Reference in New Issue
	
	Block a user