初始化提交

This commit is contained in:
2025-07-09 01:08:35 +08:00
parent d3296791cf
commit 62e0f56c60
618 changed files with 173543 additions and 0 deletions

39
BusyRabbit.uproject Normal file
View File

@ -0,0 +1,39 @@
{
"FileVersion": 3,
"EngineAssociation": "5.4",
"Category": "",
"Description": "",
"Modules": [
{
"Name": "BusyRabbit",
"Type": "Runtime",
"LoadingPhase": "Default",
"AdditionalDependencies": [
"slua_unreal",
"Engine",
"PaperZD",
"CoreUObject",
"GameplayAbilities",
"UMG"
]
}
],
"Plugins": [
{
"Name": "ModelingToolsEditorMode",
"Enabled": true,
"TargetAllowList": [
"Editor"
]
},
{
"Name": "PaperZD",
"Enabled": true,
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/c4b43502026047d89296cd7bffd92828"
},
{
"Name": "GameplayAbilities",
"Enabled": true
}
]
}

24
Config/DefaultEngine.ini Normal file
View File

@ -0,0 +1,24 @@
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]
bEnablePlugin=True
bAllowNetworkConnection=True
SecurityToken=F11C92564C113408B7629390F03B2D8B
bIncludeInShipping=False
bAllowExternalStartInShipping=False
bCompileAFSProject=False
bUseCompression=False
bLogFiles=False
bReportStats=False
ConnectionType=USBOnly
bUseManualIPAddress=False
ManualIPAddress=
[/Script/EngineSettings.GameMapsSettings]
GlobalDefaultGameMode=/Game/Blueprint/Bp_BusyGameMode.Bp_BusyGameMode_C
GameInstanceClass=/Script/BusyRabbit.BusyGameInstance
EditorStartupMap=/Game/Level/FalconPlain.FalconPlain
GameDefaultMap=/Game/Level/FalconPlain.FalconPlain
[/Script/Engine.RendererSettings]
r.Mobile.AntiAliasing=0
r.AntiAliasingMethod=2

96
Config/DefaultGame.ini Normal file
View File

@ -0,0 +1,96 @@
[/Script/UnrealEd.ProjectPackagingSettings]
Build=IfProjectHasCode
BuildConfiguration=PPBC_Shipping
BuildTarget=
FullRebuild=False
ForDistribution=False
IncludeDebugFiles=False
BlueprintNativizationMethod=Disabled
bIncludeNativizedAssetsInProjectGeneration=False
bExcludeMonolithicEngineHeadersInNativizedCode=False
UsePakFile=True
bUseIoStore=True
bUseZenStore=False
bMakeBinaryConfig=False
bGenerateChunks=False
bGenerateNoChunks=False
bChunkHardReferencesOnly=False
bForceOneChunkPerFile=False
MaxChunkSize=0
bBuildHttpChunkInstallData=False
HttpChunkInstallDataDirectory=(Path="")
WriteBackMetadataToAssetRegistry=Disabled
bWritePluginSizeSummaryJsons=False
bCompressed=True
PackageCompressionFormat=Oodle
bForceUseProjectCompressionFormatIgnoreHardwareOverride=False
PackageAdditionalCompressionOptions=
PackageCompressionMethod=Kraken
PackageCompressionLevel_DebugDevelopment=4
PackageCompressionLevel_TestShipping=4
PackageCompressionLevel_Distribution=7
PackageCompressionMinBytesSaved=1024
PackageCompressionMinPercentSaved=5
bPackageCompressionEnableDDC=False
PackageCompressionMinSizeToConsiderDDC=0
HttpChunkInstallDataVersion=
IncludePrerequisites=True
IncludeAppLocalPrerequisites=False
bShareMaterialShaderCode=True
bDeterministicShaderCodeOrder=False
bSharedMaterialNativeLibraries=True
ApplocalPrerequisitesDirectory=(Path="")
IncludeCrashReporter=False
InternationalizationPreset=English
-CulturesToStage=en
+CulturesToStage=en
LocalizationTargetCatchAllChunkId=0
bCookAll=False
bCookMapsOnly=True
bSkipEditorContent=False
bSkipMovies=False
-IniKeyDenylist=KeyStorePassword
-IniKeyDenylist=KeyPassword
-IniKeyDenylist=rsa.privateexp
-IniKeyDenylist=rsa.modulus
-IniKeyDenylist=rsa.publicexp
-IniKeyDenylist=aes.key
-IniKeyDenylist=SigningPublicExponent
-IniKeyDenylist=SigningModulus
-IniKeyDenylist=SigningPrivateExponent
-IniKeyDenylist=EncryptionKey
-IniKeyDenylist=DevCenterUsername
-IniKeyDenylist=DevCenterPassword
-IniKeyDenylist=IOSTeamID
-IniKeyDenylist=SigningCertificate
-IniKeyDenylist=MobileProvision
-IniKeyDenylist=IniKeyDenylist
-IniKeyDenylist=IniSectionDenylist
+IniKeyDenylist=KeyStorePassword
+IniKeyDenylist=KeyPassword
+IniKeyDenylist=rsa.privateexp
+IniKeyDenylist=rsa.modulus
+IniKeyDenylist=rsa.publicexp
+IniKeyDenylist=aes.key
+IniKeyDenylist=SigningPublicExponent
+IniKeyDenylist=SigningModulus
+IniKeyDenylist=SigningPrivateExponent
+IniKeyDenylist=EncryptionKey
+IniKeyDenylist=DevCenterUsername
+IniKeyDenylist=DevCenterPassword
+IniKeyDenylist=IOSTeamID
+IniKeyDenylist=SigningCertificate
+IniKeyDenylist=MobileProvision
+IniKeyDenylist=IniKeyDenylist
+IniKeyDenylist=IniSectionDenylist
-IniSectionDenylist=HordeStorageServers
-IniSectionDenylist=StorageServers
+IniSectionDenylist=HordeStorageServers
+IniSectionDenylist=StorageServers
+MapsToCook=(FilePath="/Game/Level/FalconPlain")
+DirectoriesToAlwaysStageAsUFS=(Path="Lua")
bRetainStagedDirectory=False
CustomStageCopyHandler=

View File

@ -0,0 +1,28 @@
[/Script/GameplayTags.GameplayTagsSettings]
ImportTagsFromConfig=True
WarnOnInvalidTags=True
ClearInvalidTags=False
AllowEditorTagUnloading=True
AllowGameTagUnloading=False
FastReplication=False
InvalidTagCharacters="\"\',"
NumBitsForContainerSize=6
NetIndexFirstBitSegment=16
+GameplayTagList=(Tag="Ability.Role.AttributeConsume",DevComment="角色属性损耗debuff")
+GameplayTagList=(Tag="Ability.Role.EatFood",DevComment="干饭")
+GameplayTagList=(Tag="Ability.Role.Pick",DevComment="角色采集物品")
+GameplayTagList=(Tag="Ability.Role.Recover",DevComment="角色状态恢复技能")
+GameplayTagList=(Tag="Ability.Role.Roll",DevComment="角色无敌翻滚")
+GameplayTagList=(Tag="Buff.Indispersible.HungerConsume",DevComment="饥饿值消耗,不可被驱散")
+GameplayTagList=(Tag="Buff.RoleConsume.Health",DevComment="角色因饥饿掉血的debuff")
+GameplayTagList=(Tag="Buff.RoleConsume.Hunger",DevComment="角色每秒钟的饥饿消耗")
+GameplayTagList=(Tag="Change.LevelItem.Health",DevComment="物品采集进度")
+GameplayTagList=(Tag="Change.Role.Health",DevComment="角色生命值发生的变动")
+GameplayTagList=(Tag="Change.Role.Hunger",DevComment="角色饥饿值发生变动")
+GameplayTagList=(Tag="Change.Role.MoveSpeed",DevComment="改变角色移动速度")
+GameplayTagList=(Tag="GameItem.Building",DevComment="建筑物")
+GameplayTagList=(Tag="GameItem.Food",DevComment="游戏内的可食用物品")
+GameplayTagList=(Tag="Recover.Role.Health",DevComment="回复生命值")
+GameplayTagList=(Tag="Recover.Role.Hunger",DevComment="恢复饥饿值")
+GameplayTagList=(Tag="Status.Role.Invincible",DevComment="不掉血标签")

86
Config/DefaultInput.ini Normal file
View File

@ -0,0 +1,86 @@
[/Script/Engine.InputSettings]
-AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
-AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
-AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
-AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
-AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f))
-AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f))
-AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f))
+AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MouseWheelAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_LeftTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
bAltEnterTogglesFullscreen=True
bF11TogglesFullscreen=True
bUseMouseForTouch=False
bEnableMouseSmoothing=True
bEnableFOVScaling=True
bCaptureMouseOnLaunch=True
bEnableLegacyInputScales=True
bEnableMotionControls=True
bFilterInputByPlatformUser=False
bEnableInputDeviceSubsystem=True
bShouldFlushPressedKeysOnViewportFocusLost=True
bEnableDynamicComponentInputBinding=True
bAlwaysShowTouchInterface=False
bShowConsoleOnFourFingerTap=True
bEnableGestureRecognizer=False
bUseAutocorrect=False
DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown
DefaultViewportMouseLockMode=LockOnCapture
FOVScale=0.011110
DoubleClickTime=0.200000
DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput
DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent
DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks
-ConsoleKeys=Tilde
+ConsoleKeys=Tilde

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Level/HomeLand.umap Normal file

Binary file not shown.

33
Content/Lua/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,33 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lua",
"request": "launch",
"tag": "normal",
"name": "LuaPanda",
"cwd": "${workspaceFolder}",
"luaFileExtension": "",
"connectionPort": 8818,
"stopOnEntry": true,
"useCHook": true,
"autoPathMode": true,
},
{
"type": "lua",
"request": "launch",
"tag": "independent_file",
"name": "LuaPanda-IndependentFile",
"luaPath": "",
"packagePath": [],
"luaFileExtension": "",
"connectionPort": 8820,
"stopOnEntry": true,
"useCHook": true,
}
]
}

View File

@ -0,0 +1,38 @@
---@enum EBusyRoleState
local EBusyRoleState = {
BonfireIdle = 0,
Searching = 1,
Picking = 2,
PickFinished = 3,
BackBonfire = 4
}
---@enum ERoleMoveDirection
local ERoleMoveDirection = {
Move_Right = 0,
Move_Left = 1,
Move_All_Cnt = 2
};
---@enum EBusyItemEffectType
local EBusyItemEffectType = {
Health = 0,
Hunger = 1,
Speed = 2,
};
---@enum EBusyAnimationPhase
local EBusyAnimationPhase = {
PrepareCast = 0,
Casting = 1,
PostCast = 2,
};
---@enum EWidgetLayoutType
local EWidgetLayoutType = {
MainLayer = 0,
PopupLayer = 1,
FloatLayer = 2,
TopLayer = 3,
LayerTypeMax = 4
};

View File

@ -0,0 +1,24 @@
-- 这个返回值固定返回的是string我希望当我使用import("ERoleState")时它返回的是ERoleState的注解或者是ERoleState.lua这个文件返回值的注解
-- ---自定义导入函数功能类似require但支持额外特性
-- ---@generic T
-- ---@param modulePath T 模块路径或预加载的模块
-- ---@param hotReload? boolean 是否启用热重载
-- ---@return T 返回加载的模块
-- function import(modulePath, hotReload) end
---自定义模块导入函数,支持类型感知的模块加载
---@generic T : string -- 限定modulePath为字符串类型
---@param modulePath `T` 模块路径(如"ERoleState"
---@param hotReload? boolean 是否启用热重载
---@return T 返回对应模块的类型
---@error 当模块加载失败时抛出错误
function import(modulePath, hotReload) end
function Class(a, b, c) end
---@class slua
slua = {
createDelegate = function(func) end
}

View File

@ -0,0 +1,8 @@
---@enum ESlateVisibility
local ESlateVisibility = {
Visible = 0,
Collapsed = 1,
Hidden = 2,
HitTestInvisible = 3,
SelfHitTestInvisible = 4
}

View File

@ -0,0 +1,22 @@
local PWClass = {}
local function MetaCall(cls, ...)
local inst = {
__CLASS = cls
}
cls.ctor(inst, ...)
return setmetatable(inst, cls)
end
function PWClass.derive(name, base)
local cls = {
__CLASS_NAME = name
}
cls.__index = cls
return setmetatable(cls, {
__call = MetaCall
})
end
return PWClass

View File

@ -0,0 +1,164 @@
local Module = {}
local ReactiveWatcherMeta = {}
local ReactivePropertyMeta = {}
local reactive_watcher_stack = {}
local auto_run_watcher_mapping = {}
local triggered_watchers = {} -- 由SetProperty激活的watcher列表
local function CreateReactiveWatcher(auto_run)
local watcher = rawget(auto_run_watcher_mapping, auto_run)
if watcher == nil then
watcher = {
auto_run = auto_run,
properties = {},
}
rawset(auto_run_watcher_mapping, auto_run, watcher)
setmetatable(watcher, ReactiveWatcherMeta)
end
return watcher
end
local function PushWatcher(watcher)
table.insert(reactive_watcher_stack, watcher)
end
local function PeekWatcher()
local watcher_stack_deepth = #reactive_watcher_stack
if watcher_stack_deepth > 0 then
return reactive_watcher_stack[watcher_stack_deepth]
else
return nil
end
end
local function PopWatcher()
local watcher = PeekWatcher()
if watcher then
table.remove(reactive_watcher_stack)
end
return watcher
end
local function AddPropertyToWatcher(watcher, property, key)
local properties = watcher.properties
local keys = properties[property] or {}
keys[key] = true
properties[property] = keys
end
local function ClearAllPropertiesOfWatcher(watcher)
local properties = watcher.properties
for property, keys in pairs(properties) do
local property_watchers = property.watchers
for key, state in pairs(keys) do
if state == true then
local key_watchers = property_watchers[key]
key_watchers[watcher] = nil
end
end
end
rawset(watcher, "properties", {})
end
local function RunFunctionOfWatcher(watcher)
local auto_run = watcher.auto_run
assert(auto_run ~= nil, "can't find auto run function")
ClearAllPropertiesOfWatcher(watcher) -- 解绑所有的binding由auto_run重新生成
PushWatcher(watcher)
auto_run()
local poped_watcher = PopWatcher()
assert(watcher == poped_watcher, "fatal")
end
local function GetReactiveProperty(property, key)
local meta = property.meta
local property_watchers = property.watchers
local current_watcher = PeekWatcher()
if current_watcher ~= nil then
local key_watchers = property_watchers[key] or {}
key_watchers[current_watcher] = true
property_watchers[key] = key_watchers
AddPropertyToWatcher(current_watcher, property, key)
end
return rawget(meta, key)
end
local function SetReactiveProperty(property, key, value)
local meta = property.meta
local property_watchers = property.watchers
rawset(meta, key, value)
local key_watchers = property_watchers[key] or {}
for watcher, state in pairs(key_watchers) do
if state == true then
triggered_watchers[watcher] = true
end
end
end
ReactiveWatcherMeta.__index = ReactiveWatcherMeta
ReactivePropertyMeta.__index = GetReactiveProperty
ReactivePropertyMeta.__newindex = SetReactiveProperty
-- 销毁Reactive Watcher
function ReactiveWatcherMeta:Destroy()
ClearAllPropertiesOfWatcher(self)
auto_run_watcher_mapping[self.auto_run] = nil
self.auto_run = nil
end
function ReactivePropertyMeta:Destroy()
local watchers = rawget(self, "watchers")
return watchers
end
-- 创建auto_run的watcher, 并运行auto_run函数
function Module.Watcher(auto_run)
local watcher = CreateReactiveWatcher(auto_run)
RunFunctionOfWatcher(watcher)
return watcher
end
function Module.ReactiveProperty(data)
local Property = {
meta = data or {},
watchers = {},
}
return setmetatable(Property, ReactivePropertyMeta)
end
function Module.RawGet(property, key)
local meta = rawget(property, "meta")
return rawget(meta, key)
end
function Module.RawSet(property, key, value)
local meta = rawget(property, "meta")
rawset(meta, key, value)
end
function Module.Process()
local limit = 64
while next(triggered_watchers) and limit > 0 do
local triggered_list = {}
for w, state in pairs(triggered_watchers) do
if state == true then table.insert(triggered_list, w) end
end
for _, w in ipairs(triggered_list) do
limit = limit - 1
triggered_watchers[w] = nil
RunFunctionOfWatcher(w)
end
end
end
return Module

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,222 @@
#ifndef LIBPDEBUG_H
#define LIBPDEBUG_H
//1.使用源码编译要打开宏USE_SOURCE_CODE. win下要设置LUA_INTEGER和lua版本号
#define LUA_DEBUGGER_NAME "LuaPanda" //debugger's name in LuaDebug.lua
#define HOOK_LIB_VERSION "3.2.0" //lib version
//#define USE_SOURCE_CODE //using source code to build
#if !defined(USE_SOURCE_CODE) && defined(_WIN32)
#define LUA_INTEGER long long //set LUA_INTEGER. In 501 is ptrdiff_t. 503 can set longlong(64bit) or int(32bit)
#define LUA_VERSION_NUM 503 //lua version used by WIN32 build lib. eg. 501,503
#endif
//setting end
#if !defined(USE_SOURCE_CODE) && defined(_WIN32)
#include <Windows.h>
#include <Tlhelp32.h>
#else
//2.如果lua源码是C++形式注释掉下面extern "C"
extern "C"{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "luaconf.h"
}
#endif
//3.如果lua代码在命名空间中要设置用户命名空间. 防止找不到lua方法
//using namespace slua;
#ifdef USE_SOURCE_CODE
extern "C" void pdebug_init(lua_State* L);
#endif
#if !defined(USE_SOURCE_CODE) && defined(_WIN32)
/*
** Lua - An Extensible Extension Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
*/
#if LUA_VERSION_NUM == 501
#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
#endif
#define LUA_TNONE (-1)
#define LUA_TNIL 0
#define LUA_TBOOLEAN 1
#define LUA_TLIGHTUSERDATA 2
#define LUA_TNUMBER 3
#define LUA_TSTRING 4
#define LUA_TTABLE 5
#define LUA_TFUNCTION 6
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
#define LUA_NUMBER double
#define LUA_REGISTRYINDEX (-10000)
#define LUA_ENVIRONINDEX (-10001)
#define LUA_GLOBALSINDEX (-10002)
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))
#define LUA_IDSIZE 60
#define LUA_HOOKCALL 0
#define LUA_HOOKRET 1
#define LUA_HOOKLINE 2
#define LUA_HOOKCOUNT 3
#define LUA_HOOKTAILRET 4
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
#define LUA_MASKRET (1 << LUA_HOOKRET)
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
#define lua_pop(L,n) lua_settop(L, -(n)-1)
#define lua_newtable(L) lua_createtable(L, 0, 0)
struct lua_State;
struct lua_Debug {
int event;
const char *name; /* (n) */
const char *namewhat; /* (n) `global', `local', `field', `method' */
const char *what; /* (S) `Lua', `C', `main', `tail' */
const char *source; /* (S) */
int currentline; /* (l) */
int nups; /* (u) number of upvalues */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
char short_src[LUA_IDSIZE]; /* (S) */
/* private part */
int i_ci; /* active function */
};
typedef LUA_INTEGER lua_Integer;
typedef LUA_NUMBER lua_Number;
typedef int (*lua_CFunction) (lua_State *L);
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
#define LUA_KCONTEXT ptrdiff_t
typedef LUA_KCONTEXT lua_KContext;
//lua function
typedef lua_Integer(*luaDLL_checkinteger) (lua_State *L, int numArg);
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
typedef const lua_Number *(*luaDLL_version)(lua_State *L);
typedef void (*luaLDLL_register)(lua_State *L, const char *libname, const luaL_Reg *l);
typedef int (*luaDLL_gettop)(lua_State *L);
typedef const char *(*luaDLL_pushstring)(lua_State *L, const char *s);
typedef int (*luaDLL_settop)(lua_State *L, int idx);
typedef int (*luaDLL_tointeger)(lua_State *L, int idx);
typedef int (*luaDLL_next)(lua_State *L, int idx);
typedef int (*luaDLL_pcall)(lua_State *L, int nargs, int nresults, int errfunc);
typedef void (*luaDLL_pushnil)(lua_State *L);
typedef void (*luaDLL_getfield)(lua_State *L, int idx, const char *k);
typedef int (*luaDLL_getinfo)(lua_State *L, const char *what, void *ar);
typedef void (*luaDLL_pushinteger) (lua_State *L, lua_Integer n);
#if LUA_VERSION_NUM == 501
typedef int(*luaDLL_sethook)(lua_State *L, void* func, int mask, int count);
#else
typedef void (*luaDLL_sethook)(lua_State *L, lua_Hook f, int mask, int count);
#endif
typedef void (*luaDLL_pushnumber)(lua_State *L, lua_Number n);
typedef lua_Number (*luaDLL_checknumber)(lua_State *L, int narg);
typedef const char *(*luaDLL_checklstring)(lua_State *L, int narg, size_t *len);
typedef const char *(*luaDLL_tolstring)(lua_State *L, int idx, size_t *len);
typedef int (*luaDLL_type)(lua_State *L, int idx);
//5.3
typedef void (*luaDLL_createtable)(lua_State *L, int narray, int nrec);
typedef void (*luaDLL_setfuncs)(lua_State *L, const luaL_Reg *l, int nup);
typedef lua_Integer(*luaDLL_tointegerx)(lua_State *L, int idx, int *pisnum);
typedef int (*luaDLL_getglobal)(lua_State *L, const char *name);
typedef int (*luaDLL_pcallk)(lua_State *L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k);
typedef int (*luaDLL_toboolean)(lua_State *L, int index);
luaDLL_checkinteger luaL_checkinteger;
luaDLL_version lua_version;
luaDLL_gettop lua_gettop;
luaDLL_pushstring lua_pushstring;
luaLDLL_register luaL_register;
luaDLL_settop lua_settop;
luaDLL_pcall lua_pcall;
luaDLL_pushnumber lua_pushnumber;
luaDLL_checklstring luaL_checklstring;
luaDLL_tointeger lua_tointeger;
luaDLL_pushnil lua_pushnil;
luaDLL_getfield lua_getfield;
luaDLL_next lua_next;
luaDLL_getinfo lua_getinfo;
luaDLL_sethook lua_sethook;
luaDLL_checknumber luaL_checknumber;
luaDLL_type lua_type;
luaDLL_tolstring lua_tolstring;
luaDLL_pushinteger lua_pushinteger;
luaDLL_toboolean lua_toboolean;
//
HMODULE hInstLibrary;
//slua-ue header
#if LUA_VERSION_NUM > 501
//5.3
luaDLL_createtable lua_createtable;
luaDLL_setfuncs luaL_setfuncs;
luaDLL_tointegerx lua_tointegerx;
luaDLL_getglobal lua_getglobal;
luaDLL_pcallk lua_pcallk;
#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL);
#define PURE_API =0
namespace slua {
struct LuaInterface {
virtual const lua_Number *lua_version(lua_State *L) PURE_API;
virtual const char *lua_pushstring(lua_State *L, const char *s) PURE_API;
virtual int lua_gettop(lua_State *L) PURE_API;
virtual void lua_settop(lua_State *L, int index) PURE_API;
virtual int lua_pcallk(lua_State *L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k) PURE_API;
virtual void lua_pushnumber(lua_State *L, lua_Number n) PURE_API;
virtual const char *luaL_checklstring(lua_State *L, int arg, size_t *l) PURE_API;
virtual const char *lua_tolstring(lua_State *L, int index, size_t *len) PURE_API;
virtual int lua_type(lua_State *L, int index) PURE_API;
virtual lua_Integer lua_tointegerx(lua_State *L, int index, int *isnum) PURE_API;
virtual void lua_pushnil(lua_State *L) PURE_API;
virtual int lua_getfield(lua_State *L, int index, const char *k) PURE_API;
virtual int lua_next(lua_State *L, int index) PURE_API;
virtual int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar) PURE_API;
virtual void lua_sethook(lua_State *L, lua_Hook f, int mask, int count) PURE_API;
virtual lua_Number luaL_checknumber(lua_State *L, int arg) PURE_API;
virtual void lua_createtable(lua_State *L, int narr, int nrec) PURE_API;
virtual void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) PURE_API;
virtual int lua_getglobal(lua_State *L, const char *name) PURE_API;
virtual int lua_toboolean(lua_State *L, int index) PURE_API;
};
}
typedef slua::LuaInterface* (*dll_GetLuaInterface)();
dll_GetLuaInterface getInter;
#endif //LUA_VERSION_NUM > 501
#endif //_WIN32
#endif //LIBPDEBUG_H
/******************************************************************************
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/

View File

@ -0,0 +1,10 @@
local GameInstance = {}
local Reactive = require("Core.Reactive")
function GameInstance.OnEndFrame()
Reactive.Process()
end
return GameInstance

View File

@ -0,0 +1,27 @@
local Ability = {}
local GetGameplayTag = require("GamePlay.Utils").GetGameplayTag
local AbilitySystemBlueprintLibrary = import("AbilitySystemBlueprintLibrary")
function Ability:K2_ActivateAbilityFromEvent(_)
local RoleUtils = require("GamePlay.Utils.RoleUtils")
local owner = self:GetOwningActorFromActorInfo()
local asc = AbilitySystemBlueprintLibrary.GetAbilitySystemComponent(owner)
local increase_handle = asc:MakeOutgoingSpec(
self.DefaultEffectConfig, 1, asc:MakeEffectContext()
)
AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
increase_handle, GetGameplayTag("Change.Role.MoveSpeed"), self.SpeedIncrease
)
asc:BP_ApplyGameplayEffectSpecToSelf(increase_handle)
RoleUtils.ChangeHunger(owner, -100)
end
-- function Ability:K2_OnEndAbility(bWasCancelled)
-- print(bWasCancelled, "Ability:K2_OnEndAbility")
-- end
return Class(nil, nil, Ability)

View File

@ -0,0 +1,29 @@
local EatFoodAbility = {}
local Utils = require("GamePlay.Utils")
local RoleUtils = require("GamePlay.Utils.RoleUtils")
local function HandleHealthChange(role, effects)
local tag = Utils.GetGameplayTag("Change.Role.Health")
local value = effects:Get(tag)
if value ~= nil then
RoleUtils.ChangeHealth(role, value)
end
end
local function HandleHungerChange(role, effects)
local tag = Utils.GetGameplayTag("Change.Role.Hunger")
local value = effects:Get(tag)
if value ~= nil then
RoleUtils.ChangeHunger(role, value)
end
end
function EatFoodAbility:K2_ActivateAbilityFromEvent(EventData)
local item_config = Utils.GetItemConfigByID(math.floor(EventData.EventMagnitude))
local owner = self:GetOwningActorFromActorInfo()
HandleHealthChange(owner, item_config.GameplayEffects)
HandleHungerChange(owner, item_config.GameplayEffects)
self:K2_EndAbility()
end
return Class(nil, nil, EatFoodAbility)

View File

@ -0,0 +1,94 @@
local Ability = {}
local EBusyRoleState = import("EBusyRoleState")
local ERoleMoveDirection = import("ERoleMoveDirection")
local EBusyAnimationPhase = import("EBusyAnimationPhase")
local KismetSystemLibrary = import("KismetSystemLibrary")
local AbilitySystemBlueprintLibrary = import("AbilitySystemBlueprintLibrary")
local GetGameplayTag = require("GamePlay.Utils").GetGameplayTag
local item_pick_tag = "Change.LevelItem.Health"
local role_pick_cost_health_tag = "Change.Role.Health"
local role_pick_cost_hunger_tag = "Change.Role.Hunger"
local function GetSelfPickConsume(item_id)
end
function Ability:ctor()
self.target = nil
self.pick_phase = nil
self.delay_timer = nil
self.event_data = nil
end
function Ability:K2_ActivateAbilityFromEvent(EventData)
print("Pick Ability:K2_ActivateAbility")
self.pick_phase = EBusyAnimationPhase.PrepareCast
self:ProcessAbilityPhase()
self.event_data = EventData
self.target = EventData.Target
end
function Ability:K2_OnEndAbility()
local owner = self:GetOwningActorFromActorInfo()
if self.target:IsAlive() then
owner:TryActiveAbility("Ability.Role.Pick", self.event_data)
else
owner.proxy.state = EBusyRoleState.PickFinished
owner:UpdateRoleState()
end
end
function Ability:ProcessAbilityPhase()
local owner = self:GetOwningActorFromActorInfo()
local Animation = owner["RoleAnimation"]
Animation:PlayPickAnimation("Tree", Animation:GetMoveDirection(), self.pick_phase, 1.0)
if self.delay_timer ~= nil then
KismetSystemLibrary.K2_ClearTimerHandle(self, self.delay_timer)
end
if self.pick_phase == EBusyAnimationPhase.PrepareCast then
local delegate = slua.createDelegate(function()
self.pick_phase = EBusyAnimationPhase.Casting
self:ProcessAbilityPhase()
end)
self.delay_timer = KismetSystemLibrary.K2_SetTimerDelegate(delegate, 0.5, false, true, 0, 0)
elseif self.pick_phase == EBusyAnimationPhase.Casting then
self.pick_phase = EBusyAnimationPhase.PostCast
self:ProcessAbilityPhase()
self:ApplayEffect(owner.RoleAbility)
else
local delegate = slua.createDelegate(function()
self:K2_EndAbility()
end)
self.delay_timer = KismetSystemLibrary.K2_SetTimerDelegate(delegate, 0.2, false, true, 0, 0)
end
end
function Ability:ApplayEffect(asc)
local RoleUtils = require("GamePlay.Utils.RoleUtils")
local owner = self:GetOwningActorFromActorInfo()
-- 物品的采集效果
local item_asc = AbilitySystemBlueprintLibrary.GetAbilitySystemComponent(self.target)
local pick_handle = asc:MakeOutgoingSpec(
self.AbilityEffectConfigs:Get("LevelItem"), 1, asc:MakeEffectContext()
)
AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
pick_handle, GetGameplayTag(item_pick_tag), -owner.RoleConfig.PickEffect
)
-- 自己的消耗
RoleUtils.ChangeHunger(owner,-self.target.LevelItemConfig.PickHungerCost)
asc:BP_ApplyGameplayEffectSpecToTarget(pick_handle, item_asc)
end
return Class(nil, nil, Ability)

View File

@ -0,0 +1,26 @@
local Ability = {}
local GetGameplayTag = require("GamePlay.Utils").GetGameplayTag
local BlueprintGameplayTagLibrary = import("BlueprintGameplayTagLibrary")
local AbilitySystemBlueprintLibrary = import("AbilitySystemBlueprintLibrary")
function Ability:K2_ActivateAbilityFromEvent(EventData)
local tag = EventData.tag
local value = EventData.EventMagnitude
local asc = AbilitySystemBlueprintLibrary.GetAbilitySystemComponent(self.target)
if tag == "Recover.Role.Health" then
local spec_handle = asc:MakeOutgoingSpec(
self.AbilityEffectConfigs:Get("Role"), 1, asc:MakeEffectContext()
)
AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
spec_handle, GetGameplayTag("Change.Role.Health"), value
)
asc:BP_ApplyGameplayEffectSpecToSelf(spec_handle)
end
end
return Class(nil, nil, Ability)

View File

@ -0,0 +1,71 @@
local Ability = {}
local Reactive = require("Core.Reactive")
local GetGameplayTag = require("GamePlay.Utils").GetGameplayTag
local AbilitySystemBlueprintLibrary = import("AbilitySystemBlueprintLibrary")
local hunger_consume_tag_name = "Buff.RoleConsume.Hunger"
local health_consume_tag_name = "Buff.RoleConsume.Health"
function Ability:K2_ActivateAbilityFromEvent(_)
print("Role Consume Ability:K2_ActivateAbility")
if self.hunger_watcher ~= nil then
self.hunger_watcher:Destroy()
end
self.hunger_watcher = Reactive.Watcher(function() self:ConsumeWatcher() end)
end
function Ability:ConsumeWatcher()
local owner = self:GetOwningActorFromActorInfo()
local asc = owner["RoleAbility"]
if owner.LuaRoleAttribute.Hunger > 0 then
if not asc:IsGameplayCueActive(GetGameplayTag(hunger_consume_tag_name)) then
self:ApplyHungerConsume(asc)
end
if asc:IsGameplayCueActive(GetGameplayTag(health_consume_tag_name)) then
if self.health_consume_handle ~= nil then
asc:RemoveActiveGameplayEffect(self.health_consume_handle, -1)
end
self.health_consume_handle = nil
end
elseif owner.LuaRoleAttribute.Hunger <= 0 then
if not asc:IsGameplayCueActive(GetGameplayTag(health_consume_tag_name)) then
self:ApplyHealthConsume(asc)
end
if asc:IsGameplayCueActive(GetGameplayTag(hunger_consume_tag_name)) then
if self.hunger_consume_handle ~= nil then
asc:RemoveActiveGameplayEffect(self.hunger_consume_handle, -1)
end
self.hunger_consume_handle = nil
owner.LuaRoleAttribute.Hunger = 0
end
end
end
function Ability:ApplyConsumeEffect(asc, effect_tag_name, value)
local spec_handle = asc:MakeOutgoingSpec(
self.EffectConfigs:Get(GetGameplayTag(effect_tag_name)),
1, asc:MakeEffectContext()
)
AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
spec_handle, GetGameplayTag(effect_tag_name), value
)
return asc:BP_ApplyGameplayEffectSpecToSelf(spec_handle)
end
function Ability:ApplyHungerConsume(asc)
local owner = asc:GetOwner()
local consume_speed_peer_second = owner.RoleConfig.HungerConsumeSpeed
self.hunger_consume_handle = self:ApplyConsumeEffect(
asc, hunger_consume_tag_name, -consume_speed_peer_second / 10
)
end
function Ability:ApplyHealthConsume(asc)
local owner = asc:GetOwner()
local consume_speed_peer_second = owner.RoleConfig.HungerConsumeSpeed
self.health_consume_handle = self:ApplyConsumeEffect(
asc, health_consume_tag_name, -consume_speed_peer_second/10
)
end
return Class(nil, nil, Ability)

View File

@ -0,0 +1,21 @@
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)

View File

@ -0,0 +1,108 @@
-- 禁用不必要的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

View File

@ -0,0 +1,18 @@
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)

View File

@ -0,0 +1,68 @@
local Animation = {}
local ERoleState = import("EBusyRoleState")
local ERoleMoveDirection = import("ERoleMoveDirection")
local Reactive = require("Core.Reactive")
local direction_mapping = {
[0] = ERoleMoveDirection.Move_Right,
[1] = ERoleMoveDirection.Move_Left,
}
local function GetAnimationIndex(direction, N)
-- 使用自定义 atan2 计算角度
local angle = math.atan(direction.Y, direction.X)
-- 转换为 [0, 2π) 范围
if angle < 0 then angle = angle + 2 * math.pi end
-- 调整角度:使 Y 轴负方向 (0,-1) 成为 0°第一份的中心
local adjusted_angle = (angle + math.pi / N) % (2 * math.pi)
-- local adjusted_angle = (angle + math.pi / 2 + math.pi / N) % (2 * math.pi)
-- 计算每份的角度大小
local theta = 2 * math.pi / N
-- -- 计算所属区间的索引1-based
local index = math.floor(adjusted_angle / theta)
-- 处理边界情况adjusted_angle = 2π 时归到第 1 份)
if index > N then index = 0 end
return index
end
function Animation:ReceiveLuaBeginPlay()
self.prev_direction = nil
self.watcher = Reactive.Watcher(function() self:UpdateMoveAnimation() end)
end
function Animation:UpdateMoveAnimation()
local owner = self:GetOwner()
local movement_proxy = owner.Movement.proxy
local index = 0
if owner.proxy.state == ERoleState.Picking then
return
end
if movement_proxy.isIdle then
if self.prev_direction ~= nil then
index = GetAnimationIndex(self.prev_direction, ERoleMoveDirection.Move_All_Cnt)
end
self:SetIdleAnimation(direction_mapping[index])
else
local direction = movement_proxy.direction
if direction.X ~= 0 and direction.Y ~= 0 then
index = GetAnimationIndex(direction, ERoleMoveDirection.Move_All_Cnt)
end
self:SetMoveAnimation(direction_mapping[index])
self.prev_direction = {X = direction.X, Y = direction.Y}
end
end
function Animation:GetMoveDirection()
local index = GetAnimationIndex(self.prev_direction, ERoleMoveDirection.Move_All_Cnt)
return direction_mapping[index]
end
return Class(nil, nil, Animation)

View File

@ -0,0 +1,78 @@
local FVector = import "Vector"
local FVector2D = import "Vector2D"
local Reactive = require "Core.Reactive"
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem")
local Movement = {
proxy = {},
}
function Movement:ReceiveComponentBeginPlay()
self.proxy = Reactive.ReactiveProperty({
isIdle = true,
direction = {X = 0, Y = 0},
destination = {X = 0, Y = 0}
})
end
function Movement:ReceiveComponentTick(delta_time)
local proxy = self.proxy
if proxy.isIdle then return end
local new_pos = FVector()
local owner = self:GetOwner()
local curr_pos = owner:K2_GetActorLocation()
new_pos.Z = curr_pos.Z
local move_distance = delta_time * owner:GetSpeed()
local distance_x = proxy.destination.X - curr_pos.X
local distance_y = proxy.destination.Y - curr_pos.Y
if move_distance^2 >= distance_x^2 + distance_y^2 then
proxy.isIdle = true
new_pos.X = proxy.destination.X
new_pos.Y = proxy.destination.Y
proxy.direction = FVector2D()
else
new_pos.X = curr_pos.X + proxy.direction.X * move_distance
new_pos.Y = curr_pos.Y + proxy.direction.Y * move_distance
end
owner:K2_SetActorLocation(new_pos, true, nil, false)
end
function Movement:SetDestination(x, y)
local direction = FVector2D()
local destination = FVector2D()
local owner = self:GetOwner()
local curr_pos = owner:K2_GetActorLocation()
local delta_x = x - curr_pos.X
local delta_y = y - curr_pos.Y
-- 计算方向向量
local length = math.sqrt(delta_x ^ 2 + delta_y ^ 2)
if length > 0 then
direction.X, direction.Y = delta_x / length, delta_y / length
else
direction.X, direction.Y = 0, 0
end
destination.X , destination.Y = x, y
self.proxy.isIdle = false
self.proxy.direction = direction
self.proxy.destination = destination
end
function Movement:Stop()
self.proxy.isIdle = true
end
function Movement:BackBonfire()
local sub_system = BusyActorManagerSubSystem.Get(self)
local bonfire = sub_system:GetNearestBonfire()
local position = bonfire:K2_GetActorLocation()
self:SetDestination(position.X, position.Y)
end
return Class(nil, nil, Movement)

View File

@ -0,0 +1,15 @@
local InventoryComponent = {}
function InventoryComponent:ReceiveBeginPlay()
print(self, "InventoryComponent:ReceiveBeginPlay")
end
function InventoryComponent:InitItemGrid(grid)
grid.MaxCount = 1
grid.CurrentCount = 0
grid.Priority = 1
return grid
end
return Class(nil, nil, InventoryComponent)

View File

@ -0,0 +1,59 @@
local Movement = {}
local RoleUtils = require("GamePlay.Utils.RoleUtils")
local Vector2D = require("Utils.Vector2D")
function Movement:ctor()
self.speed = 300.0
self.accelerate = 300.0
self.rate = 0.0
self.direction = Vector2D.New()
end
function Movement:ReceiveBeginPlay()
self.rate = 0.0
self.direction = Vector2D.Normalize(self.direction)
end
function Movement:SetMoveOriginDirection(vector)
self.direction = Vector2D.Normalize(vector)
end
function Movement:SetMoveOriginSpeed(speed, accelerate)
self.speed = speed
self.accelerate = accelerate
end
function Movement:ReceiveTick(DeltaSeconds)
local owner = self:GetOwner()
local role = RoleUtils.GetRole(self)
local role_location = role:K2_GetActorLocation()
local curr_location = owner:K2_GetActorLocation()
local accelerate_vector = Vector2D.New(
role_location.X - curr_location.X,
role_location.Y - curr_location.Y
)
accelerate_vector = Vector2D.Normalize(accelerate_vector)
self.rate = self.rate + DeltaSeconds * 0.1
local velocity_vector = Vector2D.Mul(self.direction, self.speed)
local direction_vector= Vector2D.Mul(accelerate_vector, self.speed * self.rate)
self.direction = Vector2D.Normalize(Vector2D.Add(velocity_vector, direction_vector))
local new_velocity = Vector2D.Mul(self.direction, self.speed)
local new_location = Vector2D.New(
curr_location.X + new_velocity.X * DeltaSeconds,
curr_location.Y + new_velocity.Y * DeltaSeconds
)
self.speed = self.speed + self.accelerate * DeltaSeconds
owner:K2_SetActorLocation(
Vector2D.ToUnrealEngine3D(new_location, curr_location.Z),
true, nil, false
)
end
function Movement:ReceiveEndPlay()
print("Movement:ReceiveEndPlay 123")
end
return Class(nil, nil, Movement)

View 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)

View 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

View 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)

View File

@ -0,0 +1,125 @@
--- @class BusyLevelItem
local LevelItem = {}
local Reactive = require("Core.Reactive")
local RoleUtils = require("GamePlay.Utils.RoleUtils")
local GameplayUtils = require("GamePlay.Utils")
local KismetSystemLibrary = import("KismetSystemLibrary")
--[[
Begin Object Class=/Script/BlueprintGraph.K2Node_CallFunction Name="K2Node_CallFunction_0" ExportPath="/Script/BlueprintGraph.K2Node_CallFunction'/Game/Blueprint/Bp_BusyCharacter.Bp_BusyCharacter:EventGraph.K2Node_CallFunction_0'"
bIsPureFunc=True
FunctionReference=(MemberParent="/Script/CoreUObject.Class'/Script/Engine.KismetSystemLibrary'",MemberName="IsValid")
NodePosX=416
NodePosY=576
NodeGuid=FAEC35AE4921EA704624228C12C6567F
CustomProperties Pin (PinId=560B26AF426C21B8AC88EDB90990EDF1,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target"),PinToolTip="Target\nKismet System Library Object Reference",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject="/Script/CoreUObject.Class'/Script/Engine.KismetSystemLibrary'",PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PinType.bSerializeAsSinglePrecisionFloat=False,DefaultObject="/Script/Engine.Default__KismetSystemLibrary",PersistentGuid=00000000000000000000000000000000,bHidden=True,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
CustomProperties Pin (PinId=5F3C3BC8429FA25D9B78099F2107C098,PinName="Object",PinToolTip="Object\nObject Reference",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject="/Script/CoreUObject.Class'/Script/CoreUObject.Object'",PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=True,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PinType.bSerializeAsSinglePrecisionFloat=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
CustomProperties Pin (PinId=5C7188354FCB6B61DE0AC8A14D6E3EEC,PinName="ReturnValue",PinToolTip="Return Value\nBoolean\n\nReturn true if the object is usable : non-null and not pending kill",Direction="EGPD_Output",PinType.PinCategory="bool",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PinType.bSerializeAsSinglePrecisionFloat=False,DefaultValue="false",AutogeneratedDefaultValue="false",PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
]]
function LevelItem:ReceiveBeginPlay()
self.Super:ReceiveBeginPlay()
self:SetLevelItemID(self.CurrentItemID)
self.world = self:GetWorld()
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:ReceiveDamage(value)
-- local remain = self.proxy.RemainProcess - value
-- if remain > 0 then
-- self.proxy.RemainProcess = remain
-- return true
-- else
-- self.proxy.RemainProcess = 0
-- self:SetLifeSpan(0.3)
-- return false
-- 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)

View File

@ -0,0 +1,6 @@
local GameMode = {}
function GameMode:ReceiveBeginPlay()
require("Debugger.LuaPanda").start("127.0.0.1",8818)
self.Super:ReceiveBeginPlay()
end
return Class(nil, nil, GameMode)

View File

@ -0,0 +1,24 @@
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)

View File

@ -0,0 +1,203 @@
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)

View File

@ -0,0 +1,37 @@
local _M = {}
local GameplayTag = import("GameplayTag")
local BusyGamePlayLibrary = import("BusyGamePlayLibrary")
local function GetConfig(func_name, config_id)
local state, config = BusyGamePlayLibrary[func_name](config_id, nil)
if state == true then
return config
else
return nil
end
end
function _M.GetItemConfigByID(item_id)
return GetConfig("GetLevelItemConfig", item_id)
end
function _M.GetItemResourceConfig(item_id)
return GetConfig("GetItemResourceConfig", item_id)
end
function _M.GetItemDescConfig(item_id)
return GetConfig("GetLevelItemDescription", item_id)
end
function _M.GetRoleConfigByID(role_id)
return GetConfig("GetRoleConfig", role_id)
end
function _M.GetGameplayTag(name)
local tag = GameplayTag(name)
tag.TagName = name
return tag
end
return _M

View File

@ -0,0 +1,29 @@
local BuildUtils = {}
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem")
local function BuildBonfire(wco)
local sub_system = BusyActorManagerSubSystem.Get(wco)
local role = sub_system.current_role
local bonfire = sub_system:GetNearestBonfire()
local role_pos = role:K2_GetActorLocation()
local bonfire_pos = bonfire:K2_GetActorLocation()
local distance = (role_pos.X - bonfire_pos.X)^2 + (role_pos.Y - bonfire_pos.Y)^2
if distance >= 90000 then
sub_system:SpawnBonfire(role_pos)
return true
end
return false
end
local build_mapping = {
[200001] = BuildBonfire
}
function BuildUtils.Build(wco, item_id)
local build_function = build_mapping[item_id]
return build_function and build_function(wco) or false
end
return BuildUtils

View File

@ -0,0 +1,58 @@
local _M = {}
local GameplayEventData = import("GameplayEventData")
local GetGameplayTag = require("GamePlay.Utils").GetGameplayTag
local BusyGamePlayLibrary = import("BusyGamePlayLibrary")
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem")
local AbilitySystemBlueprintLibrary = import("AbilitySystemBlueprintLibrary")
function _M.ChangeHealth(role, value)
local asc = AbilitySystemBlueprintLibrary.GetAbilitySystemComponent(role)
local ge = asc.AbilityEffectConfigs:Get("ChangeHealth")
local cost_handle = asc:MakeOutgoingSpec(ge, 1, asc:MakeEffectContext())
AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
cost_handle, GetGameplayTag("Change.Role.Health"),
role:CalcRealChangeByHealth(value)
)
asc:BP_ApplyGameplayEffectSpecToSelf(cost_handle)
end
function _M.ChangeHunger(role, value)
local asc = AbilitySystemBlueprintLibrary.GetAbilitySystemComponent(role)
local ge = asc.AbilityEffectConfigs:Get("ChangeHunger")
local hunger_cost, health_cost = role:CalcRealChangeByHunger(value)
local cost_handle = asc:MakeOutgoingSpec(ge, 1, asc:MakeEffectContext())
AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
cost_handle, GetGameplayTag("Change.Role.Health"), health_cost
)
AbilitySystemBlueprintLibrary.AssignTagSetByCallerMagnitude(
cost_handle, GetGameplayTag("Change.Role.Hunger"), hunger_cost
)
asc:BP_ApplyGameplayEffectSpecToSelf(cost_handle)
end
function _M.GetRole(wco)
local mgr = BusyActorManagerSubSystem.Get(wco)
return mgr.current_role
end
function _M.EatFood(wco, item_id)
local role = _M.GetRole(wco)
local EventData = GameplayEventData()
EventData.EventMagnitude = item_id
role:TryActiveAbility("Ability.Role.EatFood", EventData)
end
function _M.GetRoleConfig(role_id)
local data_table = BusyGamePlayLibrary.GetGameDataTable("RoleConfig")
local row_data = data_table:FindRow(role_id, "error in here")
print(row_data)
end
return _M

View File

@ -0,0 +1,130 @@
local BagGridWidget = {}
local UIUtils = require("UI.Utils")
local GamePlayUtils = require("GamePlay.Utils")
local RoleUtils = require("GamePlay.Utils.RoleUtils")
local BuildUtils = require("GamePlay.Utils.BuildUtils")
local ESlateVisibility = import("ESlateVisibility")
local BlueprintGameplayTagLibrary = import("BlueprintGameplayTagLibrary")
local function SetIsSelected(check_box, is_selected)
if is_selected == nil then
check_box:SetVisibility(ESlateVisibility.Collapsed)
else
check_box:SetVisibility(ESlateVisibility.Visible)
check_box:SetIsChecked(is_selected)
end
end
local function SetItemAndCnt(entry, item_id, item_cnt)
if item_id ~= nil then
entry.Icon:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
local config = GamePlayUtils.GetItemDescConfig(item_id)
local x = slua.loadObject(config.IconResource:ToString())
entry.Icon:SetBrushResourceObject(x)
else
entry.Icon:SetVisibility(ESlateVisibility.Collapsed)
end
item_cnt = item_cnt or 0
if item_cnt > 0 then
entry.Icon:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
if item_cnt > 1 then
entry.TxtCnt:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
else
entry.TxtCnt:SetVisibility(ESlateVisibility.Collapsed)
end
else
entry.TxtCnt:SetVisibility(ESlateVisibility.Collapsed)
entry.Icon:SetVisibility(ESlateVisibility.Collapsed)
end
entry.item_id = item_id
end
local function GetItemMenuContent(item, item_id)
local config = GamePlayUtils.GetItemConfigByID(item_id)
if config == nil then return {} end
local contents = {}
local consume_function = function()
local inventory = item.inventory
inventory:ConsumeItems(item.index, 1)
local grid = inventory:GetGridWithIndex(item.index)
item:SetData(grid)
end
local is_food = BlueprintGameplayTagLibrary.HasTag(
config.TypeTagContainer,
GamePlayUtils.GetGameplayTag("GameItem.Food"),
false
)
local is_building = BlueprintGameplayTagLibrary.HasTag(
config.TypeTagContainer,
GamePlayUtils.GetGameplayTag("GameItem.Building"),
false
)
if is_food then
table.insert(contents, {"使用", function()
consume_function()
RoleUtils.EatFood(item, item_id)
end})
end
if is_building then
table.insert(contents, {"建造", function()
if BuildUtils.Build(item, item_id) == true then
consume_function()
end
-- RoleUtils.EatFood(item, item_id)
end})
end
table.insert(contents, {"丢弃", function()
consume_function()
end})
return contents
end
function BagGridWidget:OnInitialized()
self.BtnMain.OnClicked:Add(function() self:OnGridClicked() end)
self.CheckBox.OnCheckStateChanged:Add(function(is_selected)
if self.item == nil then return end
self.item.selected = is_selected
end)
end
function BagGridWidget:SetData(grid)
if grid == nil then grid = {} end
SetIsSelected(self.CheckBox, grid.selected)
SetItemAndCnt(self, grid.ItemID, grid.CurrentCount)
end
function BagGridWidget:SetInventoryInfo(inventory, index)
self.index = index
self.inventory = inventory
end
function BagGridWidget:OnDestroy()
end
function BagGridWidget:OnGridClicked()
if not self.item_id then return end
local FVector2D = import("Vector2D")
local SlateBlueprintLibrary = import("SlateBlueprintLibrary")
local geometry = self:GetCachedGeometry()
local size = SlateBlueprintLibrary.GetLocalSize(geometry)
local center = FVector2D()
center.X, center.Y = size.X * 0.5, size.Y * 0.5
local _, viewport_pos = SlateBlueprintLibrary.LocalToViewport(self, geometry, center, nil, nil)
UIUtils.ShowWidget(self, "MenuPanel", {
viewport_pos,
GetItemMenuContent(self, self.item_id)
})
end
return Class(nil, nil, BagGridWidget)

View File

@ -0,0 +1,57 @@
local BagPanel = {}
local UIUtils = require("UI.Utils")
local GameplayStatics = import("GameplayStatics")
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem")
function BagPanel:ctor()
self.widgets = {}
end
function BagPanel:OnInitialized()
print("BagPanel:OnInitialized")
self.BtnClose.OnClicked:Add(function() self:Close() end)
end
function BagPanel:Construct()
self["WBP_TableSwitcher"]:SetSelectedSwitcher("RoleInventory")
end
function BagPanel:GetInventory(name)
if name == "Bonfire" then
local sub_system = BusyActorManagerSubSystem.Get(self)
local bonfire = sub_system:GetNearestBonfire()
return bonfire.Inventory
end
end
function BagPanel:Close()
GameplayStatics.SetGamePaused(self, false)
UIUtils.CloseWidget(self)
end
function BagPanel:Refresh()
GameplayStatics.SetGamePaused(self, true)
-- self:SetVisibility(ESlateVisibility.Visible)
-- local sub_system = BusyActorManagerSubSystem.Get(self)
-- local bonfire = sub_system:GetNearestBonfire()
-- bonfire.Inventory:ForEach(slua.createDelegate(function(idx, grid)
-- local widget = self.widgets[idx+1]
-- widget:SetData(grid)
-- widget:SetInventoryInfo(bonfire.Inventory, idx)
-- end))
-- local drop_visible = ESlateVisibility.Collapsed
-- self.Overlay_Confim:SetVisibility(drop_visible)
end
function BagPanel:Destruct()
end
function BagPanel:OnDestroy()
end
return Class(nil, nil, BagPanel)

View File

@ -0,0 +1,58 @@
local InventoryArea = {}
local RoleUtils = require("GamePlay.Utils.RoleUtils")
local GameplayStatics = import("GameplayStatics")
local WidgetBlueprintLibrary = import("WidgetBlueprintLibrary")
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem")
function InventoryArea:ctor()
self.widgets = {}
end
function InventoryArea:PreConstruct(bIsDesignTime)
if not bIsDesignTime then return end
end
function InventoryArea:OnInitialized()
self:InitInventoryLayout(self.RowGridCnt, self.ColGridCnt, self.GridClass)
end
function InventoryArea:InitInventoryLayout(row_cnt, col_cnt, cls)
self.widgets = {}
local pc = GameplayStatics.GetPlayerController(self, 0)
for i=1, row_cnt do
for j=1, col_cnt do
local widget = WidgetBlueprintLibrary.Create(self, cls, pc)
self.GridPanel:AddChildToGrid(widget, i-1, j-1)
widget:SetData(nil)
table.insert(self.widgets, widget)
end
end
end
function InventoryArea:OnSwitchIn(inventory_name)
self:SetVisible(true)
local inventory = nil
if inventory_name == "BonfireInventory" then
local sub_system = BusyActorManagerSubSystem.Get(self)
local bonfire = sub_system:GetNearestBonfire()
inventory = bonfire.Inventory
elseif inventory_name == "RoleInventory" then
local role = RoleUtils.GetRole(self)
inventory = role.Inventory
end
if inventory == nil then return end
inventory:ForEach(slua.createDelegate(function(idx, grid)
local widget = self.widgets[idx+1]
widget:SetData(grid)
widget:SetInventoryInfo(inventory, idx)
end))
end
function InventoryArea:OnSwitchOut(inventory_name)
self:SetVisible(false)
end
return Class(nil, nil, InventoryArea)

View File

@ -0,0 +1,54 @@
local PopupMenuItem = {}
local UIUtils = require("UI.Utils")
function PopupMenuItem:ctor()
self.on_click_callback = nil
end
function PopupMenuItem:PreConstruct(IsDesignTime)
if not IsDesignTime then return end
self.TxtMenuName:SetText(self.MenuText)
end
function PopupMenuItem:OnInitialized()
self:BindEvent("OnClicked", function() self:OnMenuItemClicked() end)
self:BindEvent("OnHovered", function() self:OnHoverStateChange(true) end)
self:BindEvent("OnUnhovered", function() self:OnHoverStateChange(false) end)
end
function PopupMenuItem:Construct()
self.TxtMenuName:SetText(self.MenuText)
end
function PopupMenuItem:OnDestroy()
print(self, "PopupMenuItem:OnDestroy")
end
function PopupMenuItem:SetContent(name, callback)
self.TxtMenuName:SetText(name)
self.on_click_callback = callback
print(self.TxtMenuName:GetText())
end
function PopupMenuItem:BindEvent(event_name, callback)
self.BtnMain[event_name]:Add(callback)
end
function PopupMenuItem:OnHoverStateChange(is_hoverd)
if is_hoverd then
self.ImgBackground.Brush.TintColor = self.ItemHoverdColor
else
self.ImgBackground.Brush.TintColor = self.ItemNormalColor
end
end
function PopupMenuItem:OnMenuItemClicked()
print("OnMenuItemClicked")
if self.on_click_callback ~= nil then
self.on_click_callback()
end
UIUtils.HideWidgetByName(self, "MenuPanel")
end
return Class(nil, nil, PopupMenuItem)

View File

@ -0,0 +1,81 @@
local PopupMenuPanel = {}
local UIUtils = require("UI.Utils")
local GameplayStatics = import("GameplayStatics")
local WidgetBlueprintLibrary = import("WidgetBlueprintLibrary")
local KismetSystemLibrary = import("KismetSystemLibrary")
local function delay_adjust_content(menu_panel)
local post_callback = function()
local timer = KismetSystemLibrary.K2_SetTimerForNextTickDelegate(
slua.createDelegate(function ()
menu_panel:AdjustMenuContentSize()
menu_panel.adjust_content_timer = nil
end)
)
menu_panel.adjust_content_timer = timer
end
local timer = KismetSystemLibrary.K2_SetTimerForNextTickDelegate(
slua.createDelegate(function () post_callback() end)
)
menu_panel.adjust_content_timer = timer
end
local function CreateMenuItem(panel)
local pc = GameplayStatics.GetPlayerController(panel, 0)
local widget = WidgetBlueprintLibrary.Create(panel, panel.MenuItemClass, pc)
return widget
end
function PopupMenuPanel:ctor()
self.adjust_content_timer = nil
end
function PopupMenuPanel:OnInitialized()
self.BtnBackground.OnClicked:Add(function()
UIUtils.CloseWidget(self)
end)
end
function PopupMenuPanel:OnDestroy()
print(self, "PopupMenuPanel:OnDestroy")
end
function PopupMenuPanel:PreConstruct(IsDesignTime)
if not IsDesignTime then return end
delay_adjust_content(self)
end
function PopupMenuPanel:Construct()
delay_adjust_content(self)
end
function PopupMenuPanel:AdjustMenuContentSize()
local all_child_height = 0
for _, child in pairs(self.MenuItemContainer:GetAllChildren()) do
local design_size = child:GetDesiredSize()
all_child_height = all_child_height + design_size.Y
end
self.ImgBackground.Brush.ImageSize.Y = all_child_height + 20
end
function PopupMenuPanel:Refresh(args)
self.MainOverlay.Slot:SetPosition(args[1])
self:SetMenuContents(args[2])
end
function PopupMenuPanel:SetMenuContents(contents)
self.MenuItemContainer:ClearChildren()
for _, content in pairs(contents) do
local widget = CreateMenuItem(self)
self.MenuItemContainer:AddChildToVerticalBox(widget)
widget:SetContent(content[1], content[2])
end
self:AdjustMenuContentSize()
end
return Class(nil, nil,PopupMenuPanel)

View File

@ -0,0 +1,28 @@
local SwitcherWidget = {}
local ESlateVisibility = import("ESlateVisibility")
function SwitcherWidget:Construct()
self:Reset()
self["ImageNormal"]:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
end
function SwitcherWidget:Reset()
self["ImageHovered"]:SetVisibility(ESlateVisibility.Collapsed)
self["ImageSelected"]:SetVisibility(ESlateVisibility.Collapsed)
self["ImageNormal"]:SetVisibility(ESlateVisibility.Collapsed)
end
function SwitcherWidget:OnWidgetStateChange(bIsWidgetHovered, bIsWidgetSelected)
self:Reset()
if bIsWidgetSelected then
self["ImageSelected"]:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
else
if bIsWidgetHovered then
self["ImageHovered"]:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
else
self["ImageNormal"]:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
end
end
end
return Class(nil, nil, SwitcherWidget)

View File

@ -0,0 +1,77 @@
local Hud = {}
local ESlateVisibility = import("ESlateVisibility")
local WidgetBlueprintLibrary = import("WidgetBlueprintLibrary")
local GameplayStatics = import("GameplayStatics")
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem")
local function ProcessSuspendShowRequests(hud)
for _, request in pairs(hud.suspend_show_requests) do
hud:CreateAndShowWidget(request[1], request[2])
end
end
function Hud:ctor()
self.layer = nil
self.suspend_show_requests = {}
self.widget_pool = {}
end
function Hud:ReceiveBeginPlay()
print("Hud:ReceiveBeginPlay")
if self.layer == nil then
self.layer = self:GetOrCreateWidget("UILayer")
end
if self.layer ~= nil then
self.layer:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
self.layer:AddToViewport(0)
self:CreateAndShowWidget("MainUI", {})
ProcessSuspendShowRequests(self)
end
end
function Hud:ReceiveEndPlay()
print("Hud:ReceiveEndPlay")
end
function Hud:GetOrCreateWidget(widget_name)
local exist_widget = self.widget_pool[widget_name]
if exist_widget ~= nil and exist_widget.bSingletonInstance then
return exist_widget
end
local cls = self.UIClassMapping:Get(widget_name)
local pc = GameplayStatics.GetPlayerController(self, 0)
local widget = WidgetBlueprintLibrary.Create(self, cls, pc)
self.widget_pool[widget_name] = widget
return widget -- TODO 这里如果非单例widget会被覆盖
end
function Hud:GetFirstCachedWidget(widget_name)
return self.widget_pool[widget_name]
end
function Hud:CreateAndShowWidget(widget_name, args)
if not self.layer then
table.insert(self.suspend_show_requests, {widget_name, args})
return
end
local widget = self:GetOrCreateWidget(widget_name)
if not widget then return end
self.layer:ShowWidget(widget, args)
end
function Hud:CloseWidget(widget)
self.layer:CloseWidget(widget)
end
function Hud:HideWidgetByName(widget_name)
self.layer:HideWidget(self.widget_pool[widget_name])
end
return Class(nil, nil, Hud)

32
Content/Lua/UI/MainUI.lua Normal file
View File

@ -0,0 +1,32 @@
local MainUI = {}
local UIUtils = require("UI.Utils")
-- local GameplayStatics = import("GameplayStatics")
function MainUI:OnInitialized()
print("OnInitialized MainUI")
self.BtnSetting.OnClicked:Add(function() self:OpenSettingPanel() end)
self.BtnBag.OnClicked:Add(function() self:OpenBagPanel() end)
self.BtnRoll.OnClicked:Add(function() self:OnUseRoll() end)
end
function MainUI:OnDestroy()
end
function MainUI:OpenSettingPanel()
-- GameplayStatics.SetGamePaused(self, true)
UIUtils.ShowWidget(self, "SettingMenu", {})
end
function MainUI:OpenBagPanel()
UIUtils.ShowWidget(self, "BagPanel", {})
end
function MainUI:OnUseRoll()
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem")
local mgr = BusyActorManagerSubSystem.Get(self)
local role = mgr.current_role
role:UseRollSkill()
end
return Class(nil, nil, MainUI)

View File

@ -0,0 +1,68 @@
local PickBar = {}
local Reactive = require("Core.Reactive")
local ESlateVisibility = import("ESlateVisibility")
local function ResetWatcher(Bar)
if Bar.watcher then
Bar.watcher:Destroy()
Bar.watcher = nil
end
end
function PickBar:ctor()
self.watcher = nil
self.level_item = nil
end
function PickBar:OnInitialized()
self.ProcessBar:SetVisibility(ESlateVisibility.Collapsed)
print("PickBar:OnInitialized")
end
function PickBar:BindLevelItem(LevelItem)
ResetWatcher(self)
self.level_item = LevelItem
-- self.watcher = Reactive.Watcher(function()
-- self:UpdateState()
-- end)
self.watcher = Reactive.Watcher(function()
local process = LevelItem:GetPickProcess()
if process < 1.0 then
self.ProcessBar:SetPercent(process)
self.ProcessBar:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
else
self.ProcessBar:SetVisibility(ESlateVisibility.Collapsed)
self.ProcessBar:SetPercent(1.0)
end
end)
end
-- function PickBar:UpdateState()
-- local process = self.level_item:GetPickProcess()
-- if process < 1.0 then
-- self.ProcessBar:SetVisibility(ESlateVisibility.SelfHitTestInvisible)
-- self.ProcessBar:SetPercent(process)
-- else
-- self.ProcessBar:SetVisibility(ESlateVisibility.Collapsed)
-- self.ProcessBar:SetPercent(1.0)
-- end
-- end
function PickBar:OnDestroy()
ResetWatcher(self)
end
function PickBar:Construct()
print("PickBar:Construct")
end
function PickBar:Destruct()
print("PickBar:Destruct")
end
return Class(nil, nil, PickBar)

View File

@ -0,0 +1,38 @@
local Widget = {}
local Reactive = require("Core.Reactive")
local function ResetWatcher(widget)
if widget.health_watcher then
widget.health_watcher:Destroy()
widget.health_watcher = nil
end
if widget.hunger_watcher then
widget.hunger_watcher:Destroy()
widget.hunger_watcher = nil
end
end
function Widget:OnDestroy()
end
function Widget:Refresh(args)
local role = args.role
if role == nil then return end
self:BindRole(role)
end
function Widget:BindRole(role)
ResetWatcher(self)
self.health_watcher = Reactive.Watcher(function()
self.HealthBar:SetPercent(role:GetHealthPercent())
end)
self.hunger_watcher = Reactive.Watcher(function()
self.HungerBar:SetPercent(role:GetHungerPercent())
end)
end
return Class(nil, nil, Widget)

View File

@ -0,0 +1,28 @@
local SettingPanel = {}
local UIUtils = require("UI.Utils")
local GameplayStatics = import("GameplayStatics")
function SettingPanel:OnInitialized()
self.BtnContinue.OnClicked:Add(function() self:BackToGame() end)
self.BtnExitLevel.OnClicked:Add(function() end)
self.BtnExitGame.OnClicked:Add(function() self:ExitGame() end)
self.BtnClose.OnClicked:Add(function() self:BackToGame() end)
end
function SettingPanel:OnDestroy()
end
function SettingPanel:BackToGame()
GameplayStatics.SetGamePaused(self, false)
UIUtils.CloseWidget(self)
end
function SettingPanel:ExitGame()
local pc = GameplayStatics.GetPlayerController(self, 0)
pc:QuitGame()
end
return Class(nil, nil, SettingPanel)

View File

@ -0,0 +1,41 @@
local UILayerManager = {}
local EWidgetLayoutType = import("EWidgetLayoutType")
function UILayerManager:ctor()
self.layer_mapping = {}
end
function UILayerManager:OnInitialized()
self.layer_mapping = {
[EWidgetLayoutType.MainLayer] = self.MainLayer,
[EWidgetLayoutType.PopupLayer] = self.PopupLayer,
[EWidgetLayoutType.FloatLayer] = self.FloatLayer,
[EWidgetLayoutType.TopLayer] = self.TopLayer,
}
end
function UILayerManager:ShowWidget(widget, args)
local layer = self.layer_mapping[widget.LayoutType]
if layer == nil then
return
end
layer:AddChild(widget)
if widget.Refresh then
widget:Refresh(args)
end
widget.Slot:SetVerticalAlignment(0)
widget.Slot:SetHorizontalAlignment(0)
widget:SetVisible(true)
end
function UILayerManager:HideWidget(widget)
widget:SetVisible(false)
end
function UILayerManager:CloseWidget(widget)
widget:SetVisible(false)
end
return Class(nil, nil, UILayerManager)

35
Content/Lua/UI/Utils.lua Normal file
View File

@ -0,0 +1,35 @@
local _M = {}
local GameplayStatics = import("GameplayStatics")
function _M.GetGameUIHud(wco)
local pc = GameplayStatics.GetPlayerController(wco, 0)
if pc == nil then return nil end
return pc:GetHud()
end
function _M.ShowWidget(wco, widget_name, args)
local hud = _M.GetGameUIHud(wco)
if hud == nil then return end
hud:CreateAndShowWidget(widget_name, args)
end
function _M.GetShowedWidget(wco, widget_name)
local hud = _M.GetGameUIHud(wco)
if hud == nil then return end
hud:GetFirstCachedWidget(widget_name)
end
function _M.HideWidgetByName(wco, widget_name)
local hud = _M.GetGameUIHud(wco)
if hud == nil then return end
hud:HideWidgetByName(widget_name)
end
function _M.CloseWidget(widget)
local hud = _M.GetGameUIHud(widget)
if hud == nil then return end
hud:CloseWidget(widget)
end
return _M

View File

@ -0,0 +1,50 @@
local Vector2D = {}
function Vector2D.New(x, y)
return {X = x or 0, Y = y or 0}
end
function Vector2D.Add(a, b)
return Vector2D.New(a.X + b.X, a.Y + b.Y)
end
function Vector2D.Sub(a, b)
return Vector2D.New(a.X - b.X, a.Y - b.Y)
end
function Vector2D.Mul(v, s)
return Vector2D.New(v.X * s, v.Y * s)
end
function Vector2D.Div(v, s)
return Vector2D.New(v.X / s, v.Y / s)
end
function Vector2D.Magnitude(v)
return math.sqrt(v.X * v.X + v.Y * v.Y)
end
function Vector2D.Normalize(v)
local mag = Vector2D.Magnitude(v)
return mag > 0 and Vector2D.Div(v, mag) or Vector2D.New()
end
function Vector2D.Dot(a, b)
return a.X * b.X + a.Y * b.Y
end
-- 2D 叉积(返回标量)
function Vector2D.Cross(a, b)
return a.X * b.Y - a.Y * b.X
end
function Vector2D.ToUnrealEngine3D(vector, z)
local FVector = import("Vector")
local new_vector = FVector()
new_vector.Z = z
new_vector.X = vector.X
new_vector.Y = vector.Y
return new_vector
end
return Vector2D

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More