剔除不需要的插件依赖,比如Paper2D系列 #8
Paper2D系列还需要,如瓦片地图。提出了对PaperZD的依赖,以及依赖FlipBook组件的Actor
This commit is contained in:
		| @ -11,7 +11,6 @@ | |||||||
| 			"AdditionalDependencies": [ | 			"AdditionalDependencies": [ | ||||||
| 				"slua_unreal", | 				"slua_unreal", | ||||||
| 				"Engine", | 				"Engine", | ||||||
| 				"PaperZD", |  | ||||||
| 				"CoreUObject", | 				"CoreUObject", | ||||||
| 				"GameplayAbilities", | 				"GameplayAbilities", | ||||||
| 				"UMG" | 				"UMG" | ||||||
| @ -26,11 +25,6 @@ | |||||||
| 				"Editor" | 				"Editor" | ||||||
| 			] | 			] | ||||||
| 		}, | 		}, | ||||||
| 		{ |  | ||||||
| 			"Name": "PaperZD", |  | ||||||
| 			"Enabled": true, |  | ||||||
| 			"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/c4b43502026047d89296cd7bffd92828" |  | ||||||
| 		}, |  | ||||||
| 		{ | 		{ | ||||||
| 			"Name": "GameplayAbilities", | 			"Name": "GameplayAbilities", | ||||||
| 			"Enabled": true | 			"Enabled": true | ||||||
|  | |||||||
| @ -1,21 +0,0 @@ | |||||||
| local Bonfire = {} |  | ||||||
| local GamePlayUtils = require("GamePlay.Utils") |  | ||||||
| local Utils = require("GamePlay.Utils") |  | ||||||
|  |  | ||||||
| local item_effect_health_tag = "Change.Role.Health" |  | ||||||
| local item_effect_hunger_tag = "Change.Role.Health" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function Bonfire:ctor() |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Bonfire:ReceiveBeginPlay() |  | ||||||
|     self.Inventory:SetInventoryCapacity(20) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Bonfire:StoreItem(item_id) |  | ||||||
|     return self.Inventory:DepositItems(item_id, 1) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| return Class(nil, nil, Bonfire) |  | ||||||
| @ -1,108 +0,0 @@ | |||||||
| -- 禁用不必要的if诊断警告 |  | ||||||
| ---@diagnostic disable: unnecessary-if |  | ||||||
|  |  | ||||||
| -- 导入基类模块 |  | ||||||
| local PWClass = require("Core.PWClass") |  | ||||||
|  |  | ||||||
| --- @class StorageClass |  | ||||||
| --- @field max_capacity number 最大容量(格子总数) |  | ||||||
| --- @field cur_capacity number 当前已用容量 |  | ||||||
| --- @field grids_list table[] 存储格子列表 |  | ||||||
| local StorageClass = PWClass.derive("StorageClass") |  | ||||||
|  |  | ||||||
| --- 创建新物品格子 |  | ||||||
| --- @param item_id any 物品唯一标识 |  | ||||||
| --- @return table 新创建的物品格子 |  | ||||||
| local function CreateGrid(item_id) |  | ||||||
|     return { |  | ||||||
|         item_id = item_id,  -- 物品ID |  | ||||||
|         cur_cnt = 0,        -- 当前数量 |  | ||||||
|         max_cnt = 1         -- 最大堆叠数(可扩展为配置项) |  | ||||||
|     } |  | ||||||
| end |  | ||||||
|  |  | ||||||
| --- 查找或创建可用物品格子 |  | ||||||
| --- @param storage StorageClass 存储实例 |  | ||||||
| --- @param item_id any 目标物品ID |  | ||||||
| --- @return table 可用格子(找不到时创建新格子) |  | ||||||
| local function FindOrCreateAvailableGrid(storage, item_id) |  | ||||||
|     -- 优先查找同类型且未满的格子 |  | ||||||
|     for _, grid in ipairs(storage.grids_list) do |  | ||||||
|         if grid.item_id == item_id and grid.cur_cnt < grid.max_cnt then |  | ||||||
|             return grid |  | ||||||
|         end |  | ||||||
|     end |  | ||||||
|  |  | ||||||
|     -- 无可用格子时创建新的物品类型格子 |  | ||||||
|     local new_grid = CreateGrid(item_id) |  | ||||||
|     table.insert(storage.grids_list, new_grid) |  | ||||||
|     return new_grid |  | ||||||
| end |  | ||||||
|  |  | ||||||
| --- 构造函数 |  | ||||||
| function StorageClass:ctor() |  | ||||||
|     self.max_capacity = 10     -- 默认最大容量 |  | ||||||
|     self.cur_capacity = 0      -- 当前使用容量 |  | ||||||
|     self.grids_list = {}       -- 格子容器 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| --- 设置存储容量上限 |  | ||||||
| --- @param capacity number 新的最大容量 |  | ||||||
| function StorageClass:SetMaxCapacity(capacity) |  | ||||||
|     self.max_capacity = capacity |  | ||||||
| end |  | ||||||
|  |  | ||||||
| --- 存储物品 |  | ||||||
| --- @param item_id any 要存储的物品ID |  | ||||||
| function StorageClass:Store(item_id) |  | ||||||
|     -- 容量检查 |  | ||||||
|     if self.cur_capacity >= self.max_capacity then |  | ||||||
|         return false  -- 建议返回操作结果 |  | ||||||
|     end |  | ||||||
|  |  | ||||||
|     local grid = FindOrCreateAvailableGrid(self, item_id) |  | ||||||
|     grid.cur_cnt = grid.cur_cnt + 1 |  | ||||||
|     self.cur_capacity = self.cur_capacity + 1 |  | ||||||
|     return true  -- 建议添加返回值 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| --- 取出物品 |  | ||||||
| --- @param item_id any 目标物品ID |  | ||||||
| --- @return boolean 是否成功取出 |  | ||||||
| function StorageClass:Withdraw(item_id) |  | ||||||
|     -- 逆序遍历提高取出效率(通常新物品在末尾) |  | ||||||
|     for i = #self.grids_list, 1, -1 do |  | ||||||
|         local grid = self.grids_list[i] |  | ||||||
|         if grid ~= nil and grid.item_id == item_id and grid.cur_cnt > 0 then |  | ||||||
|             grid.cur_cnt = grid.cur_cnt - 1 |  | ||||||
|             self.cur_capacity = self.cur_capacity - 1 |  | ||||||
|  |  | ||||||
|             -- 清空空格子 |  | ||||||
|             if grid.cur_cnt == 0 then |  | ||||||
|                 table.remove(self.grids_list, i) |  | ||||||
|             end |  | ||||||
|             return true |  | ||||||
|         end |  | ||||||
|     end |  | ||||||
|     return false |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function StorageClass:Visit(vistor) |  | ||||||
|     for _, grid in ipairs(self.grids_list) do vistor(_, grid) end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| --- 查询物品(满足条件的物品及数量) |  | ||||||
| --- @param query_function fun(item_id:any):boolean 物品过滤函数 |  | ||||||
| --- @return table 物品ID到数量的映射表 |  | ||||||
| function StorageClass:QueryItem(query_function) |  | ||||||
|     local items = {} |  | ||||||
|     for _, grid in ipairs(self.grids_list) do |  | ||||||
|         -- 仅统计有物品且满足查询条件的格子 |  | ||||||
|         if grid.cur_cnt > 0 and query_function(grid.item_id) then |  | ||||||
|             items[grid.item_id] = (items[grid.item_id] or 0) + grid.cur_cnt |  | ||||||
|         end |  | ||||||
|     end |  | ||||||
|     return items |  | ||||||
| end |  | ||||||
|  |  | ||||||
| return StorageClass |  | ||||||
| @ -1,18 +0,0 @@ | |||||||
| local PlayerState = {} |  | ||||||
|  |  | ||||||
| function PlayerState:ctor() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function PlayerState:ReceiveBeginPlay() |  | ||||||
|     print(self, "PlayerState:ReceiveBeginPlay") |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function PlayerState:ReceiveEndPlay() |  | ||||||
|     print(self, "PlayerState:ReceiveEndPlay") |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| return Class(nil, nil, PlayerState) |  | ||||||
| @ -1,112 +0,0 @@ | |||||||
| 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) |  | ||||||
| @ -1,119 +0,0 @@ | |||||||
| ---@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 |  | ||||||
| @ -1,73 +0,0 @@ | |||||||
| 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:Bp_ShouldCreateSubsystem(world) |  | ||||||
|     return false |  | ||||||
| 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) |  | ||||||
| @ -1,103 +0,0 @@ | |||||||
| --- @class BusyLevelItem |  | ||||||
| local LevelItem = {} |  | ||||||
| local Reactive = require("Core.Reactive") |  | ||||||
| local RoleUtils = require("GamePlay.Utils.RoleUtils") |  | ||||||
| local GameplayUtils = require("GamePlay.Utils") |  | ||||||
| local KismetSystemLibrary = import("KismetSystemLibrary") |  | ||||||
|  |  | ||||||
| function LevelItem:ReceiveBeginPlay() |  | ||||||
|     self:SetLevelItemID(self.CurrentItemID) |  | ||||||
|     self.world = self:GetWorld() |  | ||||||
|     print("LevelItem:ReceiveBeginPlay") |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function LevelItem:TempSetting() |  | ||||||
|     self:ReceiveBeginPlay() |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function LevelItem:ReceiveLevelItemSetted(Config) |  | ||||||
|     self.config = Config |  | ||||||
|     self.PickBar.Widget:BindLevelItem(self) |  | ||||||
|  |  | ||||||
|     print("LevelItem:ReceiveLevelItemSetted", KismetSystemLibrary.IsValid(self)) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     self.attribute_watcher = Reactive.Watcher(function() |  | ||||||
|         if self.LuaLevelItemAttribute.Health <= 0 then |  | ||||||
|             self:GenerateDropItems() |  | ||||||
|             local location = self:K2_GetActorLocation() |  | ||||||
|             location.Z = -1000 |  | ||||||
|             self:K2_SetActorLocation(location, false, nil, false) |  | ||||||
|             self:SetLifeSpan(0.3) |  | ||||||
|             self.attribute_watcher:Destroy() |  | ||||||
|         end |  | ||||||
|     end) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function LevelItem:GenerateDropItems() |  | ||||||
|     local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem").Get(self.world) |  | ||||||
|     local role = RoleUtils.GetRole(self) |  | ||||||
|     local role_location = role:K2_GetActorLocation() |  | ||||||
|     local curr_location = self:K2_GetActorLocation() |  | ||||||
|  |  | ||||||
|     local collection_config = GameplayUtils.GetItemConfigByID(self.CurrentItemID) |  | ||||||
|  |  | ||||||
|     local generated_dict = {} |  | ||||||
|     for _, config in pairs(collection_config.DropConfigs) do |  | ||||||
|         local base = 0 |  | ||||||
|         local seed = math.random() |  | ||||||
|         for _, rate in pairs(config.configs) do |  | ||||||
|             local min = base |  | ||||||
|             local max = base + rate.Rate |  | ||||||
|             if seed >= min and seed < max then |  | ||||||
|                 generated_dict[config.ItemID] = rate.Count |  | ||||||
|                 break |  | ||||||
|             end |  | ||||||
|             base = max |  | ||||||
|         end |  | ||||||
|  |  | ||||||
|     end |  | ||||||
|  |  | ||||||
|     for item_id, count in pairs(generated_dict) do |  | ||||||
|         for _ = 1, count do |  | ||||||
|             local reward = BusyActorManagerSubSystem:SpawnLevelItemReward(self) |  | ||||||
|  |  | ||||||
|             reward.Movement.speed = 300.0 |  | ||||||
|             reward.Movement.accelerate = 600.0 |  | ||||||
|             reward.Movement.direction = { |  | ||||||
|                 X = curr_location.X - role_location.X, |  | ||||||
|                 Y = curr_location.Y - role_location.Y |  | ||||||
|             } |  | ||||||
|             reward:SetRewardID(item_id) |  | ||||||
|         end |  | ||||||
|     end |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| -- 接口 |  | ||||||
| function LevelItem:GetPickProcess() |  | ||||||
|     local process = self.LuaLevelItemAttribute.Health / self.config.PickTimeCost |  | ||||||
|     print("current process", process) |  | ||||||
|     return process |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function LevelItem:GetPickCost() |  | ||||||
|     return self.LevelItemConfig.PickHungerCost |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function LevelItem:IsAlive() |  | ||||||
|     return self.LuaLevelItemAttribute.Health > 0 |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function LevelItem:GetItemID() |  | ||||||
|     return self.CurrentItemID |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| return Class(nil, nil, LevelItem) |  | ||||||
| @ -1,24 +0,0 @@ | |||||||
| local PlayerController = {} |  | ||||||
| local KismetSystemLibrary = import("KismetSystemLibrary") |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| function PlayerController:convertCursorToWorldPosition() |  | ||||||
|     -- 将当前鼠标的位置转化为世界的位置 |  | ||||||
|     local FVector = import("Vector") |  | ||||||
|     local WorldOrigin, WorldDirection = FVector(), FVector() |  | ||||||
|     local _, MouseX, MouseY = self:GetMousePosition(nil, nil) |  | ||||||
|     if self:DeprojectScreenPositionToWorld( |  | ||||||
|         MouseX, MouseY, WorldOrigin, WorldDirection |  | ||||||
|     )then |  | ||||||
|         return WorldOrigin.X, WorldOrigin.Y |  | ||||||
|     else |  | ||||||
|         return nil, nil |  | ||||||
|     end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function PlayerController:QuitGame() |  | ||||||
|     KismetSystemLibrary.QuitGame(self, self, 0, false) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| return Class(nil, nil, PlayerController) |  | ||||||
| @ -1,203 +0,0 @@ | |||||||
| local UIUtils = require("UI.Utils") |  | ||||||
| local Reactive = require("Core.Reactive") |  | ||||||
| local ERoleState = import("EBusyRoleState") |  | ||||||
| local EBusyItemEffectType = import("EBusyItemEffectType") |  | ||||||
| local GameplayStatics = import ("GameplayStatics") |  | ||||||
| local GetGameplayTag = require("GamePlay.Utils").GetGameplayTag |  | ||||||
| local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem") |  | ||||||
| local GamePlayUtils = require("GamePlay.Utils") |  | ||||||
| local KismetMathLibrary = import("KismetMathLibrary") |  | ||||||
|  |  | ||||||
| local LevelItemRewardClass = import("LevelItemReward") |  | ||||||
|  |  | ||||||
| --- @class BusyRole |  | ||||||
| local Role={ |  | ||||||
|     movement_watcher = nil, |  | ||||||
|     interacte_item = nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| local PickAbilityTag    = "Ability.Role.Pick" |  | ||||||
| local RecoverAbilityTag = "Ability.Role.Recover" |  | ||||||
| local ConsumeAbilityTag = "Ability.Role.AttributeConsume" |  | ||||||
| local RollAbilityTag = "Ability.Role.Roll" |  | ||||||
|  |  | ||||||
| -- 私有函数 |  | ||||||
|  |  | ||||||
| -- 采集相关 |  | ||||||
|  |  | ||||||
| --- @param role BusyRole |  | ||||||
| --- @param pick_targer BusyLevelItem |  | ||||||
| local function ResetPickWatcher(role, pick_targer) |  | ||||||
|     if role.pick_watcher ~= nil then |  | ||||||
|         role.pick_watcher:Destroy() |  | ||||||
|     end |  | ||||||
|     role.pick_watcher = Reactive.Watcher(function() |  | ||||||
|         if not pick_targer:IsAlive() then |  | ||||||
|             role.pick_watcher:Destroy() |  | ||||||
|             role.pick_watcher = nil |  | ||||||
|             role.carried_item_id = pick_targer:GetItemID() |  | ||||||
|         end |  | ||||||
|     end) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| --- 存储正在搬运的物品 |  | ||||||
| local function StoreCarriedItem(role) |  | ||||||
|     -- if not role.carried_item_id then return end |  | ||||||
|     -- local sub_system = BusyActorManagerSubSystem.Get(role) |  | ||||||
|     -- local bonfire = sub_system:GetNearestBonfire() |  | ||||||
|     -- if bonfire:StoreItem(role.carried_item_id) then |  | ||||||
|     --     role.carried_item_id = nil |  | ||||||
|     -- end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:ctor() |  | ||||||
|     self.pick_timer = nil |  | ||||||
|     self.carried_item_id = nil |  | ||||||
|     self.time_limited_tags = {} |  | ||||||
|     self.pick_watcher = nil  -- 监听正在采集物品的状态 |  | ||||||
|     self.proxy = Reactive.ReactiveProperty({ |  | ||||||
|         state = ERoleState.BonfireIdle, |  | ||||||
|         is_alive = true, |  | ||||||
|     }) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:ReceiveBeginPlay() |  | ||||||
|     self.bCanEverTick = false |  | ||||||
|     self.Inventory:DepositItems(200001, 2) |  | ||||||
|     self.movement_watcher = Reactive.Watcher(function() |  | ||||||
|         self:UpdateRoleState() |  | ||||||
|     end) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:ReceiveEndPlay() |  | ||||||
|     print(self, "Role:ReceiveEndPlay") |  | ||||||
|  |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:ReceiveSetRole(_) |  | ||||||
|     self:TryActiveAbility(ConsumeAbilityTag, nil) |  | ||||||
|     UIUtils.ShowWidget(self, "RoleState", {role=self}) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:UpdateRoleState() |  | ||||||
|     -- 在auto run中访问Reactive Property的值,会导致多次调用,有性能隐患 |  | ||||||
|     local role_state = Reactive.RawGet(self.proxy, "state") |  | ||||||
|     local move_proxy = self.Movement.proxy |  | ||||||
|     if move_proxy.isIdle then |  | ||||||
|         if role_state == ERoleState.Searching or role_state == ERoleState.PickFinished then |  | ||||||
|             self.proxy.state = ERoleState.BackBonfire |  | ||||||
|             self.Movement:BackBonfire() |  | ||||||
|         elseif role_state == ERoleState.BackBonfire then |  | ||||||
|             -- StoreCarriedItem(self) |  | ||||||
|             self.proxy.state = ERoleState.BonfireIdle |  | ||||||
|         end |  | ||||||
|     else |  | ||||||
|         if role_state == ERoleState.BonfireIdle then |  | ||||||
|             self.proxy.state = ERoleState.Searching |  | ||||||
|         end |  | ||||||
|     end |  | ||||||
|     print("old", role_state, "new", Reactive.RawGet(self.proxy, "state"), move_proxy.isIdle) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:StartPick(level_item) |  | ||||||
|     local GameplayEventData = import("GameplayEventData") |  | ||||||
|     local EventData = GameplayEventData() |  | ||||||
|     EventData.Instigator = self |  | ||||||
|     EventData.Target = level_item |  | ||||||
|     self.proxy.state = ERoleState.Picking |  | ||||||
|     self:TryActiveAbility(PickAbilityTag, EventData) |  | ||||||
|     -- ResetPickWatcher(self, level_item) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:OnTouch(_) |  | ||||||
|     local role_proxy = self.proxy |  | ||||||
|     if role_proxy.state == ERoleState.BonfireIdle then |  | ||||||
|         local pc = GameplayStatics.GetPlayerController(self:GetWorld(), 0) |  | ||||||
|         local world_x, world_y = pc:convertCursorToWorldPosition() |  | ||||||
|         role_proxy.state = ERoleState.Searching |  | ||||||
|         self.Movement:SetDestination(world_x, world_y) |  | ||||||
|     else |  | ||||||
|         print("nothing") |  | ||||||
|     end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:OnOverlapBegin(OverlappedComp, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult) |  | ||||||
|     if KismetMathLibrary.ClassIsChildOf(OtherActor:GetClass(), LevelItemRewardClass) then |  | ||||||
|         self.Inventory:DepositItems(OtherActor.RewardID, 1) |  | ||||||
|         OtherActor:ConditionalBeginDestroy() |  | ||||||
|     else |  | ||||||
|         if self.proxy.state ~= ERoleState.Searching then return end |  | ||||||
|         self.proxy.state = ERoleState.Picking |  | ||||||
|         self.Movement:Stop() |  | ||||||
|         self:StartPick(OtherActor) |  | ||||||
|     end |  | ||||||
|  |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| --- 使用翻滚技能 |  | ||||||
| function Role:UseRollSkill() |  | ||||||
|     self:TryActiveAbility(RollAbilityTag, nil) |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| --  接口 |  | ||||||
| function Role:GetPickEffect() |  | ||||||
|     return self.RoleConfig.PickEffect |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:GetHealthPercent() |  | ||||||
|     local current_health = self.LuaRoleAttribute.Health or 0 |  | ||||||
|     return current_health / self.RoleConfig.Health |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:GetHungerPercent() |  | ||||||
|     return self.LuaRoleAttribute.Hunger / self.RoleConfig.Hunger |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:GetHungerConsumeSpeed() |  | ||||||
|     if self.time_limited_tags["SkillRole"] ~= nil then |  | ||||||
|         return self.RoleConfig.HungerConsumeSpeed * 8 |  | ||||||
|     else |  | ||||||
|         return self.RoleConfig.HungerConsumeSpeed |  | ||||||
|     end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:GetSpeed() |  | ||||||
|     return self.LuaRoleAttribute.MoveSpeed |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:GetMoveDirection() |  | ||||||
|     return self.Movement.proxy.direction |  | ||||||
| end |  | ||||||
|  |  | ||||||
|  |  | ||||||
| --- 返回即将消耗的饥饿值和生命值 |  | ||||||
| function Role:CalcRealChangeByHunger(value) |  | ||||||
|     local config = self.RoleConfig |  | ||||||
|     local fixed_change, extra_health_need = 0, 0 |  | ||||||
|     local cost_rate = config.HealthConsumeSpeed / config.HungerConsumeSpeed |  | ||||||
|     local remain_hunger = self.LuaRoleAttribute.Hunger + value |  | ||||||
|     if remain_hunger < 0 then |  | ||||||
|         fixed_change = remain_hunger |  | ||||||
|         extra_health_need = remain_hunger * cost_rate |  | ||||||
|     elseif remain_hunger > self.RoleConfig.Hunger then |  | ||||||
|         fixed_change = remain_hunger - self.RoleConfig.Hunger |  | ||||||
|     end |  | ||||||
|     return value - fixed_change, self:CalcRealChangeByHealth(extra_health_need) |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function Role:CalcRealChangeByHealth(value) |  | ||||||
|     if value == 0 then return 0 end |  | ||||||
|     local fixed_change = 0 |  | ||||||
|     local remain_health = self.LuaRoleAttribute.Health + value |  | ||||||
|     if remain_health < 0 then |  | ||||||
|         fixed_change = remain_health |  | ||||||
|     elseif remain_health > self.RoleConfig.Health then |  | ||||||
|         fixed_change = remain_health - self.RoleConfig.Health |  | ||||||
|     end |  | ||||||
|     return value - fixed_change |  | ||||||
| end |  | ||||||
|  |  | ||||||
| return Class(nil, nil, Role) |  | ||||||
| @ -55,14 +55,6 @@ bool UBusyGameplayLibrary::GetLevelItemConfig(const FName& RowName, FBusyLevelIt | |||||||
| 	return GetTableConfig<FBusyLevelItemConfig>(TEXT("LevelItems"), RowName, RowData); | 	return GetTableConfig<FBusyLevelItemConfig>(TEXT("LevelItems"), RowName, RowData); | ||||||
| } | } | ||||||
|  |  | ||||||
| bool UBusyGameplayLibrary::GetRoleConfig(const FName& RowName, FBusyRoleConfig& RowData){ |  | ||||||
| 	return GetTableConfig<FBusyRoleConfig>(TEXT("RoleConfig"), RowName, RowData); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool UBusyGameplayLibrary::GetItemResourceConfig(const FName& RowName, FBusyLevelItemResourceConfig& RowData){ |  | ||||||
| 	return GetTableConfig<FBusyLevelItemResourceConfig>(TEXT("LevelItemResource"), RowName, RowData); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool UBusyGameplayLibrary::GetLevelItemDescription(const FName& RowName, FBusyLevelItemDescription& RowData){ | bool UBusyGameplayLibrary::GetLevelItemDescription(const FName& RowName, FBusyLevelItemDescription& RowData){ | ||||||
| 	return GetTableConfig<FBusyLevelItemDescription>(TEXT("LevelItemDesc"), RowName, RowData); | 	return GetTableConfig<FBusyLevelItemDescription>(TEXT("LevelItemDesc"), RowName, RowData); | ||||||
| } | } | ||||||
|  | |||||||
| @ -118,7 +118,7 @@ void UPW_TableSwitcher::RebuildSwitcher(const TMap<FName, FTableSwitcherInfo>& I | |||||||
| 		Widget = CreateWidget<UPW_TableSwitcherWidget>(this, Info.SwitcherWidget); | 		Widget = CreateWidget<UPW_TableSwitcherWidget>(this, Info.SwitcherWidget); | ||||||
| 		UHorizontalBoxSlot *WidgetSlot = SwitcherBar->AddChildToHorizontalBox(Widget); | 		UHorizontalBoxSlot *WidgetSlot = SwitcherBar->AddChildToHorizontalBox(Widget); | ||||||
| 		if (WidgetSlot) { | 		if (WidgetSlot) { | ||||||
| 			WidgetSlot->VerticalAlignment = VAlign_Fill; | 			WidgetSlot->SetVerticalAlignment(VAlign_Fill); | ||||||
| 		} | 		} | ||||||
| 		Widget->SetSwitcherName(PageName); | 		Widget->SetSwitcherName(PageName); | ||||||
| 		Widget->SetSwitcherTitle(Info.TableSwitcherName); | 		Widget->SetSwitcherTitle(Info.TableSwitcherName); | ||||||
|  | |||||||
| @ -1,117 +0,0 @@ | |||||||
| // Fill out your copyright notice in the Description page of Project Settings. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "Level/BusyLevelItem.h" |  | ||||||
| #include "Components/CapsuleComponent.h" |  | ||||||
| #include "Components/WidgetComponent.h" |  | ||||||
| #include "BusyGameplayLibrary.h" |  | ||||||
|  |  | ||||||
| ABusyLevelItem::ABusyLevelItem(): CurrentItemID("100001") { |  | ||||||
| 	LuaFilePath = TEXT("GamePlay.LevelItem.LevelItem"); |  | ||||||
|  |  | ||||||
| 	SceneComp = CreateDefaultSubobject<USceneComponent>(TEXT("RootScene")); |  | ||||||
| 	CapsuleComp = CreateDefaultSubobject<UCapsuleComponent>(TEXT("LevelItemCapsule")); |  | ||||||
| 	Sprite = CreateDefaultSubobject<UPaperFlipbookComponent>(TEXT("Sprite")); |  | ||||||
|  |  | ||||||
| 	PickBar = CreateDefaultSubobject<UWidgetComponent>(TEXT("PickBar")); |  | ||||||
| 	LevelItemAttribute = CreateDefaultSubobject<UBusyLevelItemAttributeSet>("LevelItemAttribute"); |  | ||||||
|  |  | ||||||
| 	InitSprite(); |  | ||||||
| 	InitCapsule(); |  | ||||||
| 	InitPickBar(); |  | ||||||
|  |  | ||||||
| 	PickBar->SetupAttachment(CapsuleComp); |  | ||||||
| 	Sprite->SetupAttachment(CapsuleComp); |  | ||||||
| 	CapsuleComp->SetupAttachment(SceneComp); |  | ||||||
| 	this->RootComponent = SceneComp; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyLevelItem::OnConstruction(const FTransform& Transform){ |  | ||||||
| 	Super::OnConstruction(Transform); |  | ||||||
| 	SetItemDisplay(CurrentItemID); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyLevelItem::BeginPlay(){ |  | ||||||
| 	UClass* cls = UBusyGameplayLibrary::GetGameUIClass("PickBar"); |  | ||||||
| 	if (cls != nullptr) { |  | ||||||
| 		PickBar->SetWidgetClass(cls); |  | ||||||
| 	} |  | ||||||
| 	Super::BeginPlay(); |  | ||||||
| 	bIsBeginPlay = true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyLevelItem::EndPlay(const EEndPlayReason::Type EndPlayReason){ |  | ||||||
| 	Super::EndPlay(EndPlayReason); |  | ||||||
| 	bIsBeginPlay = false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyLevelItem::PostLuaHook(){ |  | ||||||
| 	if (bIsBeginPlay) { |  | ||||||
| 		CallLuaFunctionIfExist("TempSetting"); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyLevelItem::InitCapsule(){ |  | ||||||
|  |  | ||||||
| 	CapsuleComp->SetCollisionProfileName(TEXT("Custom")); |  | ||||||
| 	CapsuleComp->SetNotifyRigidBodyCollision(false); |  | ||||||
| 	CapsuleComp->SetSimulatePhysics(false); |  | ||||||
| 	CapsuleComp->SetEnableGravity(false); |  | ||||||
|  |  | ||||||
| 	CapsuleComp->SetCollisionObjectType(ECC_WorldStatic); // 设置对象类型 |  | ||||||
|  |  | ||||||
| 	// 逐个通道设置响应 |  | ||||||
| 	CapsuleComp->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); |  | ||||||
| 	//CapsuleComp->SetCollisionResponseToAllChannels(ECR_Ignore); |  | ||||||
| 	CapsuleComp->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap); |  | ||||||
| 	CapsuleComp->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Ignore); |  | ||||||
|  |  | ||||||
| 	CapsuleComp->SetCapsuleRadius(10); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyLevelItem::InitSprite(){ |  | ||||||
| 	Sprite->SetRelativeRotation(FRotator(0.0, 0.0, -90.0)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyLevelItem::InitPickBar(){ |  | ||||||
| 	PickBar->SetRelativeRotation(FRotator(90.0, 0.0, -90.0)); |  | ||||||
| 	PickBar->SetRelativeLocation(FVector(0.0, -180.0, 0.0)); |  | ||||||
| 	PickBar->SetGenerateOverlapEvents(false); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyLevelItem::SetItemDisplay(const FName& ItemID){ |  | ||||||
| 	UDataTable* Resource = UBusyGameplayLibrary::GetGameDataTable(TEXT("LevelItemResource")); |  | ||||||
|  |  | ||||||
| 	// 查物品信息 |  | ||||||
| 	FBusyLevelItemResourceConfig* ResourceConfig = Resource->FindRow<FBusyLevelItemResourceConfig>( |  | ||||||
| 		ItemID, TEXT("ABusyLevelItem::SetLevelItemID"), true |  | ||||||
| 	); |  | ||||||
|  |  | ||||||
| 	// 设置资源 |  | ||||||
| 	if (ResourceConfig != nullptr && ResourceConfig->StaticResource) { |  | ||||||
| 		this->Sprite->SetFlipbook(ResourceConfig->StaticResource); |  | ||||||
| 		this->CurrentItemID = ItemID; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyLevelItem::SetLevelItemID(const FName& ItemID){ |  | ||||||
| 	// 取物品资源表 |  | ||||||
| 	UDataTable* ConfigTable = UBusyGameplayLibrary::GetGameDataTable(TEXT("LevelItems")); |  | ||||||
| 	// 查物品信息 |  | ||||||
| 	FBusyLevelItemConfig* ItemConfig = ConfigTable->FindRow<FBusyLevelItemConfig>( |  | ||||||
| 		ItemID, TEXT("ABusyLevelItem::SetLevelItemID"), true |  | ||||||
| 	); |  | ||||||
| 	SetItemDisplay(ItemID); |  | ||||||
|  |  | ||||||
| 	// 设置配置属性 |  | ||||||
| 	if (ItemConfig == nullptr) return; |  | ||||||
|  |  | ||||||
| 	// 初始化Attribute |  | ||||||
| 	LevelItemAttribute->InitHealth(ItemConfig->PickTimeCost); |  | ||||||
| 	LevelItemAttribute->RegisterCustomAttribute(); |  | ||||||
|  |  | ||||||
| 	CurrentItemID = ItemID; |  | ||||||
| 	LevelItemConfig = *ItemConfig; |  | ||||||
| 	ReceiveLevelItemSetted(LevelItemConfig); |  | ||||||
| } |  | ||||||
| @ -1,33 +0,0 @@ | |||||||
| // Fill out your copyright notice in the Description page of Project Settings. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "Level/LevelItemReward.h" |  | ||||||
| #include "Components/CapsuleComponent.h" |  | ||||||
| #include "Components/SceneComponent.h" |  | ||||||
| #include "PaperFlipbook.h" |  | ||||||
| #include "PaperFlipbookComponent.h" |  | ||||||
| #include "BusyGameplayLibrary.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ALevelItemReward::ALevelItemReward(){ |  | ||||||
| 	SceneComp = CreateDefaultSubobject<USceneComponent>(TEXT("RootScene")); |  | ||||||
| 	CapsuleComp = CreateDefaultSubobject<UCapsuleComponent>(TEXT("RoleCapsule")); |  | ||||||
| 	Sprite = CreateDefaultSubobject<UPaperFlipbookComponent>(TEXT("Sprite")); |  | ||||||
| 	CapsuleComp->SetupAttachment(SceneComp); |  | ||||||
| 	Sprite->SetupAttachment(CapsuleComp); |  | ||||||
| 	this->RootComponent = SceneComp; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ALevelItemReward::OnConstruction(const FTransform& Transform){ |  | ||||||
| 	SetRewardID(RewardID); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ALevelItemReward::SetRewardID(const FName& CurrentRewardID){ |  | ||||||
| 	bool bIsFind = false; |  | ||||||
| 	FBusyLevelItemDescription Desc; |  | ||||||
| 	if (CurrentRewardID.IsNone()) return; |  | ||||||
| 	bIsFind = UBusyGameplayLibrary::GetLevelItemDescription(CurrentRewardID, Desc); |  | ||||||
| 	if (!bIsFind) return; |  | ||||||
| 	this->RewardID = CurrentRewardID; |  | ||||||
| 	this->Sprite->SetFlipbook(Desc.LevelResource.LoadSynchronous()); |  | ||||||
| } |  | ||||||
| @ -1,110 +0,0 @@ | |||||||
| // Fill out your copyright notice in the Description page of Project Settings. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "Role/BusyRole.h" |  | ||||||
| #include "GameFramework/SpringArmComponent.h" |  | ||||||
| #include "Components/CapsuleComponent.h" |  | ||||||
| #include "Components/SceneComponent.h" |  | ||||||
| #include "BusyCameraComponent.h" |  | ||||||
| #include "PaperFlipbookComponent.h" |  | ||||||
| #include "Role/BusyRoleMovement.h" |  | ||||||
| #include "Role/RoleAnimation.h" |  | ||||||
| #include "BusyGameplayLibrary.h" |  | ||||||
| #include "Components/InventoryComponent.h" |  | ||||||
| #include "Core/PW_AbilitySystemComponent.h" |  | ||||||
| #include "EnhancedInputComponent.h" |  | ||||||
| #include "EnhancedInputSubsystems.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ABusyRole::ABusyRole(){ |  | ||||||
| 	SceneComp = CreateDefaultSubobject<USceneComponent>(TEXT("RootScene")); |  | ||||||
| 	CapsuleComp = CreateDefaultSubobject<UCapsuleComponent>(TEXT("RoleCapsule")); |  | ||||||
| 	SpringArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm")); |  | ||||||
| 	CameraComp = CreateDefaultSubobject<UBusyCameraComponent>(TEXT("RoleCamera")); |  | ||||||
| 	Sprite = CreateDefaultSubobject<UPaperFlipbookComponent>(TEXT("Sprite")); |  | ||||||
|  |  | ||||||
| 	Movement = CreateDefaultSubobject<UBusyRoleMovement>(TEXT("Movement")); |  | ||||||
| 	RoleAnimation = CreateDefaultSubobject<URoleAnimation>(TEXT("RoleAnimation")); |  | ||||||
| 	Inventory = CreateDefaultSubobject<UInventoryComponent>(TEXT("Inventory")); |  | ||||||
|  |  | ||||||
| 	RoleAbility = CreateDefaultSubobject<UPW_AbilitySystemComponent>("RoleAbility"); |  | ||||||
| 	RoleAttribute = CreateDefaultSubobject<UBusyRoleAttributeSet>(TEXT("RoleAttributeSet")); |  | ||||||
|  |  | ||||||
| 	SpringArmComp->SetRelativeRotation(FRotator(-90.0, -90.0, 0.0)); |  | ||||||
| 	this->InitCapsule(); |  | ||||||
|  |  | ||||||
| 	Sprite->SetupAttachment(CapsuleComp); |  | ||||||
| 	CapsuleComp->SetupAttachment(SceneComp); |  | ||||||
| 	SpringArmComp->SetupAttachment(CapsuleComp); |  | ||||||
| 	CameraComp->SetupAttachment(SpringArmComp); |  | ||||||
|  |  | ||||||
| 	PrimaryActorTick.bCanEverTick = true; |  | ||||||
| 	this->RootComponent = SceneComp; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyRole::BeginPlay(){ |  | ||||||
| 	Super::BeginPlay(); |  | ||||||
|  |  | ||||||
| 	if (APlayerController* PlayerController = Cast<APlayerController>(GetController())) { |  | ||||||
| 		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer())) { |  | ||||||
| 			Subsystem->AddMappingContext(InputMapping, 0); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyRole::Tick(float InDeltaSeconds){ |  | ||||||
| 	Super::Tick(InDeltaSeconds); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyRole::SetRole(const FName& Name){ |  | ||||||
| 	UDataTable* Table = UBusyGameplayLibrary::GetGameDataTable("RoleConfig"); |  | ||||||
| 	if (Table == nullptr) { |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	FBusyRoleConfig *Row = Table->FindRow<FBusyRoleConfig>(Name, TEXT("ABusyRole::SetRole")); |  | ||||||
| 	if (Row == nullptr) { |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	RoleName = Name; |  | ||||||
| 	RoleConfig = *Row; |  | ||||||
|  |  | ||||||
| 	// <20><><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> |  | ||||||
| 	if (RoleAttribute) { |  | ||||||
| 		RoleAttribute->InitHealth(Row->Health); |  | ||||||
| 		RoleAttribute->InitHunger(Row->Hunger); |  | ||||||
| 		RoleAttribute->InitMoveSpeed(Row->MoveSpeed); |  | ||||||
| 		RoleAttribute->RegisterCustomAttribute(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// <20><><EFBFBD>ü<EFBFBD><C3BC><EFBFBD> |  | ||||||
| 	for (UClass* AbilityClass : Row->DefaultAbilities) { |  | ||||||
| 		if (AbilityClass) { |  | ||||||
| 			RoleAbility->GiveAbility(FGameplayAbilitySpec(AbilityClass)); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	ReceiveSetRole(RoleConfig); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyRole::TryActiveAbility(const FName& TagName,const FGameplayEventData& EventData){ |  | ||||||
| 	RoleAbility->HandleGameplayEvent(FGameplayTag::RequestGameplayTag(TagName), &EventData); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyRole::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent){ |  | ||||||
| 	Super::SetupPlayerInputComponent(PlayerInputComponent); |  | ||||||
|  |  | ||||||
| 	if (UEnhancedInputComponent* EnhancedInput = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) { |  | ||||||
| 		EnhancedInput->BindAction(TouchAction, ETriggerEvent::Triggered, this, FName("OnTouch")); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ABusyRole::InitCapsule(){ |  | ||||||
| 	FScriptDelegate OverlapDelegate; |  | ||||||
| 	CapsuleComp->SetCollisionProfileName(TEXT("Pawn")); |  | ||||||
| 	CapsuleComp->SetNotifyRigidBodyCollision(false); |  | ||||||
| 	OverlapDelegate.BindUFunction(this, "OnOverlapBegin"); |  | ||||||
| 	CapsuleComp->OnComponentBeginOverlap.Add(OverlapDelegate); |  | ||||||
|  |  | ||||||
| 	CapsuleComp->SetCapsuleRadius(10); |  | ||||||
| } |  | ||||||
| @ -1,25 +0,0 @@ | |||||||
| // Fill out your copyright notice in the Description page of Project Settings. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "Role/BusyRoleMovement.h" |  | ||||||
| #include "PaperFlipbookComponent.h" |  | ||||||
|  |  | ||||||
| UBusyRoleMovement::UBusyRoleMovement(){ |  | ||||||
| 	LuaFilePath = TEXT("GamePlay/BusyRole/Movement"); |  | ||||||
| 	this->PrimaryComponentTick.bCanEverTick = true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void UBusyRoleMovement::BeginPlay(){ |  | ||||||
| 	Super::BeginPlay(); |  | ||||||
| 	ReceiveComponentBeginPlay(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void UBusyRoleMovement::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) |  | ||||||
| { |  | ||||||
| 	Super::TickComponent(DeltaTime, TickType, ThisTickFunction); |  | ||||||
| 	const AActor* Owner = GetOwner(); |  | ||||||
| 	if (!Owner) return; |  | ||||||
| 	this->ReceiveComponentTick(DeltaTime); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @ -1,115 +0,0 @@ | |||||||
| // Fill out your copyright notice in the Description page of Project Settings. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "Role/RoleAnimation.h" |  | ||||||
| #include "Role/BusyRole.h" |  | ||||||
| #include "BusyGameplayLibrary.h" |  | ||||||
|  |  | ||||||
| DEFINE_LOG_CATEGORY(LogRoleAnimation); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| URoleAnimation::URoleAnimation(){ |  | ||||||
| 	LuaFilePath = TEXT("GamePlay.BusyRole.Animation"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void URoleAnimation::SetMoveAnimation(ERoleMoveDirection direction){ |  | ||||||
| 	FBusyRoleAnimationData* Config; |  | ||||||
| 	UPaperFlipbookComponent* Sprite; |  | ||||||
|  |  | ||||||
| 	if (!GetOwnerRoleInfo(Sprite, Config)) { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::SetMoveAnimation, Can't get owner info")); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	SetRoleAnimation(Sprite, Config->MoveAnimations.Find(direction)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void URoleAnimation::SetIdleAnimation(ERoleMoveDirection direction){ |  | ||||||
| 	FBusyRoleAnimationData* Config; |  | ||||||
| 	UPaperFlipbookComponent* Sprite; |  | ||||||
|  |  | ||||||
| 	if (!GetOwnerRoleInfo(Sprite, Config)) { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::SetMoveAnimation, Can't get owner info")); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	SetRoleAnimation(Sprite, Config->IdleAnimations.Find(direction)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void URoleAnimation::PlayPickAnimation(const FName& ItemName, ERoleMoveDirection Direction, EBusyAnimationPhase Phase, float PlayRate){ |  | ||||||
| 	FBusyRoleAnimationData* Config; |  | ||||||
| 	UPaperFlipbookComponent* Sprite; |  | ||||||
|  |  | ||||||
| 	if (!GetOwnerRoleInfo(Sprite, Config)) { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::SetPickAnimation, Can't get owner info")); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	FBusyRolePickingAnimationData *Directions = Config->PickingAnimations.Find(ItemName); |  | ||||||
| 	if (Directions == nullptr) { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::SetPickAnimation, Can't get Directions Animation")); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	FBusyAnimationPhaseData *PhaseData = Directions->DirectionAnimations.Find(Direction); |  | ||||||
| 	if (PhaseData == nullptr) { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::SetPickAnimation, Can't get PhaseData Animation")); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	UPaperFlipbook **Animation = PhaseData->PhaseAnimation.Find(Phase); |  | ||||||
| 	if (Animation == nullptr) { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::SetPickAnimation, Can't get Animation")); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	PlayAnimationOnce(Sprite, Animation, PlayRate); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| bool URoleAnimation::GetOwnerRoleInfo(UPaperFlipbookComponent*& Sprite, FBusyRoleAnimationData*& AnimationData){ |  | ||||||
| 	ABusyRole* Role = Cast<ABusyRole>(this->GetOwner()); |  | ||||||
| 	if (Role == nullptr) { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::GetPaperFilpBookComponent, Can't get Role")); |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	UDataTable* DataTable = UBusyGameplayLibrary::GetGameDataTable("RoleAnimation"); |  | ||||||
| 	if (DataTable == nullptr) { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::GetOwnerRoleInfo, Can't get Animation DataTable")) |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	FBusyRoleAnimationData* Config = DataTable->FindRow<FBusyRoleAnimationData>( |  | ||||||
| 		Role->RoleName, TEXT("URoleAnimation::GetOwnerRoleInfo") |  | ||||||
| 	); |  | ||||||
|  |  | ||||||
| 	if (Config == nullptr) { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::GetOwnerRoleInfo, Can't get role info from table")) |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	Sprite = Role->Sprite; |  | ||||||
| 	AnimationData = Config; |  | ||||||
|  |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void URoleAnimation::SetRoleAnimation(UPaperFlipbookComponent* Sprite, UPaperFlipbook** Anim){ |  | ||||||
| 	if (Anim && *Anim) { |  | ||||||
| 		Sprite->Stop(); |  | ||||||
| 		Sprite->SetLooping(true); |  | ||||||
| 		Sprite->SetPlayRate(1.0); |  | ||||||
| 		Sprite->SetFlipbook(*Anim); |  | ||||||
| 		Sprite->PlayFromStart(); |  | ||||||
| 	} else { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::SetRoleAnimation, Can't set role animation")); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void URoleAnimation::PlayAnimationOnce(UPaperFlipbookComponent* Sprite, UPaperFlipbook** Anim, float PlayRate){ |  | ||||||
| 	if (Anim && *Anim) { |  | ||||||
| 		Sprite->Stop(); |  | ||||||
| 		Sprite->SetLooping(false); |  | ||||||
| 		Sprite->SetPlayRate(PlayRate); |  | ||||||
| 		Sprite->SetFlipbook(*Anim); |  | ||||||
| 		Sprite->PlayFromStart(); |  | ||||||
| 	} |  | ||||||
| 	else { |  | ||||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::PlayAnimationOnce failed")); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -3,9 +3,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "CoreMinimal.h" | #include "CoreMinimal.h" | ||||||
| #include "Role/BusyRole.h" |  | ||||||
| #include "Engine/World.h" | #include "Engine/World.h" | ||||||
| #include "Level/BusyLevelItem.h" |  | ||||||
| #include "Engine/DataTable.h" | #include "Engine/DataTable.h" | ||||||
| #include "Kismet/BlueprintFunctionLibrary.h" | #include "Kismet/BlueprintFunctionLibrary.h" | ||||||
| #include "GameAsset/BusyItem.h" | #include "GameAsset/BusyItem.h" | ||||||
| @ -35,12 +33,6 @@ public: | |||||||
| 	UFUNCTION(BlueprintPure) | 	UFUNCTION(BlueprintPure) | ||||||
| 	static bool GetLevelItemConfig(const FName& RowName, FBusyLevelItemConfig& RowData); | 	static bool GetLevelItemConfig(const FName& RowName, FBusyLevelItemConfig& RowData); | ||||||
|  |  | ||||||
| 	UFUNCTION(BlueprintPure) |  | ||||||
| 	static bool GetRoleConfig(const FName& RowName, FBusyRoleConfig& RowData); |  | ||||||
|  |  | ||||||
| 	UFUNCTION(BlueprintPure) |  | ||||||
| 	static bool GetItemResourceConfig(const FName& RowName, FBusyLevelItemResourceConfig& RowData); |  | ||||||
|  |  | ||||||
| 	UFUNCTION(BlueprintPure) | 	UFUNCTION(BlueprintPure) | ||||||
| 	static bool GetLevelItemDescription(const FName& RowName, FBusyLevelItemDescription& RowData); | 	static bool GetLevelItemDescription(const FName& RowName, FBusyLevelItemDescription& RowData); | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,7 +1,10 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "CoreMinimal.h" | #include "CoreMinimal.h" | ||||||
|  | #include "GameplayTagContainer.h" | ||||||
| #include "BusyItem.generated.h" | #include "BusyItem.generated.h" | ||||||
|  |  | ||||||
|  | class UPaperFlipbook; | ||||||
|  |  | ||||||
| UENUM(BlueprintType)  // 烹饪火候 | UENUM(BlueprintType)  // 烹饪火候 | ||||||
| enum class ECookingHeat : uint8 { | enum class ECookingHeat : uint8 { | ||||||
| 	LOW_HEAT,      // 小火 | 	LOW_HEAT,      // 小火 | ||||||
|  | |||||||
| @ -1,21 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "LuaOverriderInterface.h" |  | ||||||
| #include "GameplayModMagnitudeCalculation.h" |  | ||||||
| #include "BusyMagnitudeCalculation.generated.h" |  | ||||||
|  |  | ||||||
| UCLASS() |  | ||||||
| class UBusyMagnitudeCalculation : public UGameplayModMagnitudeCalculation, public ILuaOverriderInterface |  | ||||||
| { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| public: |  | ||||||
| 	virtual FString GetLuaFilePath_Implementation(); |  | ||||||
| 	 |  | ||||||
| protected: |  | ||||||
| 	UPROPERTY(EditDefaultsOnly) |  | ||||||
| 	FString LuaFilePath; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| inline FString UBusyMagnitudeCalculation::GetLuaFilePath_Implementation() |  | ||||||
| { |  | ||||||
| 	return LuaFilePath; |  | ||||||
| } |  | ||||||
| @ -1,116 +0,0 @@ | |||||||
| // Fill out your copyright notice in the Description page of Project Settings. |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "CoreMinimal.h" |  | ||||||
| #include "LuaActor.h" |  | ||||||
| #include "Engine/Datatable.h" |  | ||||||
| #include "PaperFlipbookComponent.h" |  | ||||||
| #include "Gas/BusyAttributeSet.h" |  | ||||||
| #include "GameplayTagContainer.h" |  | ||||||
| #include "GameAsset/BusyItem.h" |  | ||||||
| #include "BusyLevelItem.generated.h" |  | ||||||
|  |  | ||||||
| UENUM(BlueprintType) |  | ||||||
| enum class EBusyItemEffectType: uint8 { |  | ||||||
| 	Health = 0, |  | ||||||
| 	Hunger = 1, |  | ||||||
| 	Speed = 2, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| UENUM(BlueprintType) |  | ||||||
| enum class EBusyLevelItemType : uint8 { |  | ||||||
| 	None = 0, |  | ||||||
| 	Collection = 1, |  | ||||||
| 	Building = 2, |  | ||||||
| 	Reward= 3, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| USTRUCT(BlueprintType) |  | ||||||
| struct FBusyLevelItemResourceConfig : public FTableRowBase {  // 物品资源表 |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "物品图标资源") |  | ||||||
| 	TObjectPtr<UTexture2D> IconResource; |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "物品静态资源") |  | ||||||
| 	TObjectPtr<UPaperFlipbook> StaticResource; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| USTRUCT(BlueprintType) |  | ||||||
| struct FBusyLevelItemGenerateConfig { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "每个周期生成物品的数量") |  | ||||||
| 	int CountOfPeriod; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  *  |  | ||||||
|  */ |  | ||||||
| UCLASS() |  | ||||||
| class BUSYRABBIT_API ABusyLevelItem : public ALuaActor |  | ||||||
| { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| public: |  | ||||||
| 	ABusyLevelItem(); |  | ||||||
|  |  | ||||||
| public: |  | ||||||
| 	virtual void OnConstruction(const FTransform& Transform) override; |  | ||||||
|  |  | ||||||
| 	virtual void BeginPlay() override; |  | ||||||
|  |  | ||||||
| 	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason)override; |  | ||||||
|  |  | ||||||
| 	virtual void PostLuaHook() override; |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	void InitCapsule(); |  | ||||||
| 	void InitSprite(); |  | ||||||
| 	void InitPickBar(); |  | ||||||
|  |  | ||||||
| 	void SetItemDisplay(const FName &ItemID); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| public: |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UCapsuleComponent> CapsuleComp; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class USceneComponent> SceneComp; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UPaperFlipbookComponent> Sprite; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UBusyAbilitySystemComponent> AbilityComponent;	// 技能组件 |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UWidgetComponent> PickBar; |  | ||||||
|  |  | ||||||
| public: |  | ||||||
| 	UPROPERTY(EditAnyWhere, BlueprintReadOnly) |  | ||||||
| 	FName CurrentItemID; |  | ||||||
|  |  | ||||||
| public:  // 提供给蓝图的接口 |  | ||||||
| 	UFUNCTION(BlueprintCallable) |  | ||||||
| 	void SetLevelItemID(const FName& ItemID); |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	UPROPERTY(BlueprintReadOnly) |  | ||||||
| 	FBusyLevelItemConfig LevelItemConfig; |  | ||||||
|  |  | ||||||
| 	UPROPERTY() |  | ||||||
| 	TObjectPtr<UBusyLevelItemAttributeSet> LevelItemAttribute; |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	bool bIsBeginPlay; |  | ||||||
|  |  | ||||||
| public:  // 需要蓝图实现的函数 |  | ||||||
| 	// LevelItem被设置时的回调 |  | ||||||
| 	UFUNCTION(BlueprintImplementableEvent) |  | ||||||
| 	void ReceiveLevelItemSetted(const FBusyLevelItemConfig& Config); |  | ||||||
| }; |  | ||||||
| @ -1,57 +0,0 @@ | |||||||
| // Fill out your copyright notice in the Description page of Project Settings. |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "CoreMinimal.h" |  | ||||||
| #include "LuaActor.h" |  | ||||||
| #include "Engine/Datatable.h" |  | ||||||
| #include "GameplayTagContainer.h" |  | ||||||
| #include "Core/BusyLuaActorComponent.h" |  | ||||||
| #include "LevelItemReward.generated.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| USTRUCT(BlueprintType) |  | ||||||
| struct FLevelItemRewardConfig : public FTableRowBase { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "道具备注") |  | ||||||
| 	FString Comment; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "物品标签列表") |  | ||||||
| 	FGameplayTagContainer TypeTagContainer; |  | ||||||
| 	 |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName = "使用后能带来的效果") |  | ||||||
| 	TMap<FGameplayTag, float> GameplayEffects; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  *  |  | ||||||
|  */ |  | ||||||
| UCLASS() |  | ||||||
| class BUSYRABBIT_API ALevelItemReward : public ALuaActor |  | ||||||
| { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| public: |  | ||||||
| 	ALevelItemReward(); |  | ||||||
|  |  | ||||||
| public: |  | ||||||
| 	virtual void OnConstruction(const FTransform& Transform) override; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UCapsuleComponent> CapsuleComp; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class USceneComponent> SceneComp; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UPaperFlipbookComponent> Sprite; |  | ||||||
|  |  | ||||||
| public: |  | ||||||
| 	UFUNCTION(BlueprintCallable) |  | ||||||
| 	void SetRewardID(const FName& CurrentRewardID); |  | ||||||
|  |  | ||||||
| public: |  | ||||||
| 	UPROPERTY(EditAnyWhere, BlueprintReadOnly) |  | ||||||
| 	FName RewardID; |  | ||||||
| }; |  | ||||||
| @ -1,148 +0,0 @@ | |||||||
| // Fill out your copyright notice in the Description page of Project Settings. |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "slua.h" |  | ||||||
| #include "CoreMinimal.h" |  | ||||||
| #include "LuaPawn.h" |  | ||||||
| #include "Engine/Datatable.h" |  | ||||||
| #include "Gas/BusyAttributeSet.h" |  | ||||||
| #include "AbilitySystemComponent.h" |  | ||||||
| #include "BusyRole.generated.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| UENUM(BlueprintType) |  | ||||||
| enum class EBusyRoleState : uint8{ |  | ||||||
| 	BonfireIdle,	// 篝火旁闲置 |  | ||||||
| 	Searching,		// 外出搜索物品 |  | ||||||
| 	Picking,		// 正在与物品交互 |  | ||||||
| 	PickFinished,	// 与物品交互完毕 |  | ||||||
| 	BackBonfire,	// 返回篝火  |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| USTRUCT(BlueprintType) |  | ||||||
| struct FBusyRoleConfig: public FTableRowBase { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "角色的生命值") |  | ||||||
| 	int32 Health; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "角色的饥饿值") |  | ||||||
| 	int32 Hunger; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "角色饥饿值消耗速度") |  | ||||||
| 	int HungerConsumeSpeed; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "角色生命值消耗速度") |  | ||||||
| 	int HealthConsumeSpeed; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "角色的采集效率") |  | ||||||
| 	int PickEffect; |  | ||||||
| 	 |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "角色的移动速度") |  | ||||||
| 	int MoveSpeed; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "角色的技能列表") |  | ||||||
| 	TArray<TSubclassOf<UGameplayAbility>> DefaultAbilities; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| USTRUCT(BlueprintType) |  | ||||||
| struct FBusyRoleResourceConfig : public FTableRowBase { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "角色头像图标") |  | ||||||
| 	int32 Health; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  *  |  | ||||||
|  */ |  | ||||||
| UCLASS() |  | ||||||
| class BUSYRABBIT_API ABusyRole : public ALuaPawn{ |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| public: |  | ||||||
| 	ABusyRole(); |  | ||||||
| 	virtual void BeginPlay()override; |  | ||||||
| 	virtual void Tick(float InDeltaSeconds)override; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class USceneComponent> SceneComp; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class USpringArmComponent> SpringArmComp; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UCapsuleComponent> CapsuleComp; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UBusyCameraComponent> CameraComp; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UPaperFlipbookComponent> Sprite; |  | ||||||
| 	 |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UBusyRoleMovement> Movement;  // 移动组件 |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UPW_AbilitySystemComponent> RoleAbility;	// 技能组件 |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class UInventoryComponent> Inventory;  // 仓库组件 |  | ||||||
|  |  | ||||||
| 	UPROPERTY(BlueprintReadWrite) |  | ||||||
| 	TObjectPtr<class URoleAnimation> RoleAnimation; |  | ||||||
|  |  | ||||||
| public:  // 蓝图接口 |  | ||||||
| 	UFUNCTION(BlueprintCallable) |  | ||||||
| 	void SetRole(const FName& Name); |  | ||||||
|  |  | ||||||
| 	UFUNCTION(BlueprintCallable) |  | ||||||
| 	void TryActiveAbility(const FName& TagName, const FGameplayEventData& EventData); |  | ||||||
|  |  | ||||||
| public: |  | ||||||
| 	// 输入相关 |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, Category = "Input") |  | ||||||
| 	TObjectPtr<class UInputMappingContext> InputMapping; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditDefaultsOnly, Category = "Input") |  | ||||||
| 	TObjectPtr<class UInputAction> TouchAction; |  | ||||||
|  |  | ||||||
| 	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)override; |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	void InitCapsule(); |  | ||||||
|  |  | ||||||
| public: // 蓝图实现 |  | ||||||
| 	UFUNCTION(BlueprintImplementableEvent) |  | ||||||
| 	void OnTouch(const FInputActionValue& Value) const; |  | ||||||
|  |  | ||||||
| 	UFUNCTION(BlueprintImplementableEvent) |  | ||||||
| 	void OnOverlapBegin( |  | ||||||
| 		UPrimitiveComponent* OverlappedComp, |  | ||||||
| 		AActor* OtherActor, |  | ||||||
| 		UPrimitiveComponent* OtherComp, |  | ||||||
| 		int32 OtherBodyIndex, |  | ||||||
| 		bool bFromSweep, |  | ||||||
| 		const FHitResult& SweepResult |  | ||||||
| 	); |  | ||||||
|  |  | ||||||
| 	UFUNCTION(BlueprintImplementableEvent) |  | ||||||
| 	void ReceiveSetRole(const FBusyRoleConfig& RoleTableConfig); |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	FTimerHandle TimerHandle; |  | ||||||
|  |  | ||||||
| public:  // 角色属性 |  | ||||||
| 	UPROPERTY(BlueprintReadOnly) |  | ||||||
| 	FName RoleName; |  | ||||||
| 	UPROPERTY(BlueprintReadOnly, Category = "Value") |  | ||||||
| 	FBusyRoleConfig RoleConfig; |  | ||||||
|  |  | ||||||
| private: |  | ||||||
| 	UPROPERTY() |  | ||||||
| 	TObjectPtr<UBusyRoleAttributeSet> RoleAttribute; |  | ||||||
|  |  | ||||||
| public:  // 不暴露给蓝图的属性 |  | ||||||
|  |  | ||||||
| }; |  | ||||||
| @ -1,43 +0,0 @@ | |||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "CoreMinimal.h" |  | ||||||
| #include "LuaOverriderInterface.h" |  | ||||||
| #include "LuaActorComponent.h" |  | ||||||
| #include "GameFramework/MovementComponent.h" |  | ||||||
| #include "BusyRoleMovement.generated.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| UENUM(BlueprintType) |  | ||||||
| enum class ERoleMoveDirection: uint8 { |  | ||||||
| 	Move_Right, |  | ||||||
| 	Move_Left, |  | ||||||
| 	Move_All_Cnt |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  *  |  | ||||||
|  */ |  | ||||||
| UCLASS() |  | ||||||
| class BUSYRABBIT_API UBusyRoleMovement : public ULuaActorComponent |  | ||||||
| { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
|  |  | ||||||
| public: |  | ||||||
| 	UBusyRoleMovement(); |  | ||||||
|  |  | ||||||
| public: |  | ||||||
| 	 |  | ||||||
| public: |  | ||||||
| 	virtual void BeginPlay()override; |  | ||||||
|  |  | ||||||
| 	UFUNCTION(BlueprintImplementableEvent) |  | ||||||
| 	void ReceiveComponentTick(float DeltaTime); |  | ||||||
|  |  | ||||||
| 	UFUNCTION(BlueprintImplementableEvent) |  | ||||||
| 	void ReceiveComponentBeginPlay(); |  | ||||||
|  |  | ||||||
| 	virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)override; |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	FVector MovementDirection; |  | ||||||
| }; |  | ||||||
| @ -1,77 +0,0 @@ | |||||||
| // Fill out your copyright notice in the Description page of Project Settings. |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "CoreMinimal.h" |  | ||||||
| #include "LuaActorComponent.h" |  | ||||||
| #include "Engine/Datatable.h" |  | ||||||
| #include "PaperFlipbookComponent.h" |  | ||||||
| #include "BusyRoleMovement.h" |  | ||||||
| #include "../Core/BusyLuaActorComponent.h" |  | ||||||
| #include "RoleAnimation.generated.h" |  | ||||||
|  |  | ||||||
| DECLARE_LOG_CATEGORY_EXTERN(LogRoleAnimation, Log, All); |  | ||||||
|  |  | ||||||
| UENUM(BlueprintType) |  | ||||||
| enum class EBusyAnimationPhase : uint8{ |  | ||||||
| 	PrepareCast,	// 动作前摇阶段 |  | ||||||
| 	Casting,		// 动作释放阶段 |  | ||||||
| 	PostCast,		// 动作后摇阶段 |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| USTRUCT(BlueprintType) |  | ||||||
| struct FBusyAnimationPhaseData : public FTableRowBase { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "各个阶段的动作") |  | ||||||
| 	TMap<EBusyAnimationPhase, UPaperFlipbook*> PhaseAnimation; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| USTRUCT(BlueprintType) |  | ||||||
| struct FBusyRolePickingAnimationData : public FTableRowBase { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "各个方向的采集动作") |  | ||||||
| 	TMap<ERoleMoveDirection, FBusyAnimationPhaseData> DirectionAnimations; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| USTRUCT(BlueprintType) |  | ||||||
| struct FBusyRoleAnimationData : public FTableRowBase { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "移动时的动作") |  | ||||||
| 	TMap<ERoleMoveDirection, UPaperFlipbook*> MoveAnimations; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "静止时的动作") |  | ||||||
| 	TMap<ERoleMoveDirection, UPaperFlipbook*> IdleAnimations; |  | ||||||
|  |  | ||||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName = "采集物品时的动作") |  | ||||||
| 	TMap<FName, FBusyRolePickingAnimationData> PickingAnimations; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  *  |  | ||||||
|  */ |  | ||||||
| UCLASS() |  | ||||||
| class BUSYRABBIT_API URoleAnimation : public UBusyLuaActorComponent |  | ||||||
| { |  | ||||||
| 	GENERATED_BODY() |  | ||||||
| public: |  | ||||||
| 	URoleAnimation(); |  | ||||||
|  |  | ||||||
| public: |  | ||||||
| 	UFUNCTION(BlueprintCallable) |  | ||||||
| 	void SetMoveAnimation(ERoleMoveDirection direction); |  | ||||||
|  |  | ||||||
| 	UFUNCTION(BlueprintCallable) |  | ||||||
| 	void SetIdleAnimation(ERoleMoveDirection direction); |  | ||||||
|  |  | ||||||
| 	UFUNCTION(BlueprintCallable) |  | ||||||
| 	void PlayPickAnimation(const FName& ItemName, ERoleMoveDirection Direction, EBusyAnimationPhase Phase, float PlayRate); |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	bool GetOwnerRoleInfo(UPaperFlipbookComponent* &Sprite, FBusyRoleAnimationData* &AnimationData); |  | ||||||
|  |  | ||||||
| 	// 设置表格里面的动作 |  | ||||||
| 	void SetRoleAnimation(UPaperFlipbookComponent* Sprite, UPaperFlipbook** Anim); |  | ||||||
| 	 |  | ||||||
| 	void PlayAnimationOnce(UPaperFlipbookComponent* Sprite, UPaperFlipbook** Anim, float PlayRate); |  | ||||||
| }; |  | ||||||
		Reference in New Issue
	
	Block a user