初始化提交
This commit is contained in:
33
Content/Lua/.vscode/launch.json
vendored
Normal file
33
Content/Lua/.vscode/launch.json
vendored
Normal 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,
|
||||
}
|
||||
]
|
||||
}
|
||||
38
Content/Lua/@types/BusyEnum.d.lua
Normal file
38
Content/Lua/@types/BusyEnum.d.lua
Normal 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
|
||||
};
|
||||
24
Content/Lua/@types/UE.d.lua
Normal file
24
Content/Lua/@types/UE.d.lua
Normal 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
|
||||
}
|
||||
8
Content/Lua/@types/UEEnum.d.lua
Normal file
8
Content/Lua/@types/UEEnum.d.lua
Normal file
@ -0,0 +1,8 @@
|
||||
---@enum ESlateVisibility
|
||||
local ESlateVisibility = {
|
||||
Visible = 0,
|
||||
Collapsed = 1,
|
||||
Hidden = 2,
|
||||
HitTestInvisible = 3,
|
||||
SelfHitTestInvisible = 4
|
||||
}
|
||||
22
Content/Lua/Core/PWClass.lua
Normal file
22
Content/Lua/Core/PWClass.lua
Normal 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
|
||||
164
Content/Lua/Core/Reactive.lua
Normal file
164
Content/Lua/Core/Reactive.lua
Normal 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
|
||||
3626
Content/Lua/Debugger/LuaPanda.lua
Normal file
3626
Content/Lua/Debugger/LuaPanda.lua
Normal file
File diff suppressed because it is too large
Load Diff
1107
Content/Lua/Debugger/debugger_lib/libpdebug.cpp
Normal file
1107
Content/Lua/Debugger/debugger_lib/libpdebug.cpp
Normal file
File diff suppressed because it is too large
Load Diff
222
Content/Lua/Debugger/debugger_lib/libpdebug.h
Normal file
222
Content/Lua/Debugger/debugger_lib/libpdebug.h
Normal 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.
|
||||
******************************************************************************/
|
||||
10
Content/Lua/GameInstance.lua
Normal file
10
Content/Lua/GameInstance.lua
Normal file
@ -0,0 +1,10 @@
|
||||
local GameInstance = {}
|
||||
local Reactive = require("Core.Reactive")
|
||||
|
||||
function GameInstance.OnEndFrame()
|
||||
Reactive.Process()
|
||||
end
|
||||
|
||||
|
||||
|
||||
return GameInstance
|
||||
27
Content/Lua/GamePlay/Ability/Common/AbilityRoll.lua
Normal file
27
Content/Lua/GamePlay/Ability/Common/AbilityRoll.lua
Normal 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)
|
||||
29
Content/Lua/GamePlay/Ability/Common/EatFood.lua
Normal file
29
Content/Lua/GamePlay/Ability/Common/EatFood.lua
Normal 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)
|
||||
94
Content/Lua/GamePlay/Ability/Common/Pick.lua
Normal file
94
Content/Lua/GamePlay/Ability/Common/Pick.lua
Normal 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)
|
||||
26
Content/Lua/GamePlay/Ability/Common/Recover.lua
Normal file
26
Content/Lua/GamePlay/Ability/Common/Recover.lua
Normal 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)
|
||||
71
Content/Lua/GamePlay/Ability/Common/RoleConsume.lua
Normal file
71
Content/Lua/GamePlay/Ability/Common/RoleConsume.lua
Normal 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)
|
||||
21
Content/Lua/GamePlay/Bonefire/Bonfire.lua
Normal file
21
Content/Lua/GamePlay/Bonefire/Bonfire.lua
Normal 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)
|
||||
108
Content/Lua/GamePlay/Bonefire/Storage.lua
Normal file
108
Content/Lua/GamePlay/Bonefire/Storage.lua
Normal 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
|
||||
18
Content/Lua/GamePlay/BusyPlayerState.lua
Normal file
18
Content/Lua/GamePlay/BusyPlayerState.lua
Normal 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)
|
||||
68
Content/Lua/GamePlay/BusyRole/Animation.lua
Normal file
68
Content/Lua/GamePlay/BusyRole/Animation.lua
Normal 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)
|
||||
78
Content/Lua/GamePlay/BusyRole/Movement.lua
Normal file
78
Content/Lua/GamePlay/BusyRole/Movement.lua
Normal 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)
|
||||
15
Content/Lua/GamePlay/Components/InventoryComponent.lua
Normal file
15
Content/Lua/GamePlay/Components/InventoryComponent.lua
Normal 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)
|
||||
59
Content/Lua/GamePlay/Components/LevelItemRewardMovement.lua
Normal file
59
Content/Lua/GamePlay/Components/LevelItemRewardMovement.lua
Normal 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)
|
||||
112
Content/Lua/GamePlay/Level/BusyActorManagerSubSystem.lua
Normal file
112
Content/Lua/GamePlay/Level/BusyActorManagerSubSystem.lua
Normal file
@ -0,0 +1,112 @@
|
||||
local FVector = import "Vector"
|
||||
local Vector2D = require("Utils.Vector2D")
|
||||
local Library = import "BusyGamePlayLibrary"
|
||||
local GameplayStatics = import("GameplayStatics")
|
||||
|
||||
local SubSystem = {}
|
||||
|
||||
local function GetNearestBonfire(system, x, y)
|
||||
local selected_bonfire = nil
|
||||
local selected_distance = nil
|
||||
|
||||
for _, bonfire in ipairs(system.bonfire_list) do
|
||||
local pos = bonfire:K2_GetActorLocation()
|
||||
local distance = (x - pos.X) ^ 2 + (y - pos.Y) ^ 2
|
||||
if selected_distance == nil or distance < selected_distance then
|
||||
selected_distance = distance
|
||||
selected_bonfire = bonfire
|
||||
end
|
||||
end
|
||||
return selected_bonfire
|
||||
end
|
||||
|
||||
function SubSystem:ctor()
|
||||
self.current_role = nil
|
||||
self.bonfire_list = {} -- 所有的篝火列表
|
||||
end
|
||||
|
||||
function SubSystem:ReceiveSubSystemInitialize()
|
||||
self.current_role = nil
|
||||
self.bonfire_list = {}
|
||||
end
|
||||
|
||||
function SubSystem:GetNearestBonfire()
|
||||
if self.current_role then
|
||||
local cur_pos = self.current_role:K2_GetActorLocation()
|
||||
return GetNearestBonfire(self, cur_pos.X, cur_pos.Y)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function SubSystem:SpawnBonfire(position)
|
||||
local pos = FVector()
|
||||
local world = self:K2_GetWorld()
|
||||
local cls = Library.GetGameClass("Bonfire")
|
||||
pos.X, pos.Y, pos.Z = position.X, position.Y, 20
|
||||
local bonfire = world:SpawnActor(cls, pos, nil, nil)
|
||||
table.insert(self.bonfire_list, bonfire)
|
||||
return bonfire
|
||||
end
|
||||
|
||||
function SubSystem:SpawnRole(bonfire)
|
||||
local role_pos = FVector()
|
||||
local world = self:K2_GetWorld()
|
||||
local pos = bonfire:K2_GetActorLocation()
|
||||
local cls = Library.GetGameClass("BusyRole")
|
||||
role_pos.X, role_pos.Y, role_pos.Z = pos.X, pos.Y, pos.Z + 10
|
||||
self.current_role = world:SpawnActor(cls, role_pos, nil, nil)
|
||||
if self.current_role ~= nil then
|
||||
self.current_role:SetRole("Rabbit")
|
||||
return self.current_role
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function SubSystem:SpawnLevelItem(item_id)
|
||||
-- 随机在角色周围生成
|
||||
|
||||
local distance = math.random(128, 500)
|
||||
local angle = (math.random(0, 360) / 360) * 2 * 3.14;
|
||||
|
||||
local world = self:K2_GetWorld()
|
||||
local item_position = FVector()
|
||||
local center = self.current_role:K2_GetActorLocation()
|
||||
local cls = import("BusyLevelItem")
|
||||
|
||||
item_position.Z = center.Z - 1
|
||||
item_position.X = center.X + math.cos(angle) * distance
|
||||
item_position.Y = center.Y + math.sin(angle) * distance
|
||||
|
||||
local item = world:SpawnActor(cls, item_position, nil, nil)
|
||||
item:SetLevelItemID(item_id)
|
||||
return center
|
||||
end
|
||||
|
||||
function SubSystem:SpawnLevelItemReward(level_item)
|
||||
assert(self.current_role ~= nil)
|
||||
|
||||
local world = self:K2_GetWorld()
|
||||
local cls = Library.GetGameClass("LevelItemReward")
|
||||
|
||||
local random_angle = (math.random() - 0.5) * (math.pi / 2)
|
||||
local direction = Vector2D.Normalize(self.current_role:GetMoveDirection())
|
||||
|
||||
local sin, cos = math.sin(random_angle), math.cos(random_angle)
|
||||
|
||||
-- 应用旋转矩阵
|
||||
direction.X = direction.X * cos - direction.Y * sin
|
||||
direction.Y = direction.X * sin + direction.Y * cos
|
||||
|
||||
local item_location = level_item:K2_GetActorLocation()
|
||||
|
||||
local reward_location = Vector2D.Add(item_location, Vector2D.Mul(direction, 200))
|
||||
|
||||
local item = world:SpawnActor(cls,
|
||||
Vector2D.ToUnrealEngine3D(reward_location, item_location.Z),
|
||||
nil, nil
|
||||
)
|
||||
return item
|
||||
end
|
||||
|
||||
return Class(nil, nil, SubSystem)
|
||||
119
Content/Lua/GamePlay/Level/BusyLevelItemGenerator.lua
Normal file
119
Content/Lua/GamePlay/Level/BusyLevelItemGenerator.lua
Normal file
@ -0,0 +1,119 @@
|
||||
---@class ItemGenerator 物品生成器类
|
||||
local ItemGenerator = {
|
||||
item_data = {},
|
||||
period = 100,
|
||||
item_distributions = {}
|
||||
}
|
||||
ItemGenerator.__index = ItemGenerator
|
||||
|
||||
---数组洗牌函数(Fisher-Yates算法)
|
||||
---@param array any[] 需要打乱顺序的数组
|
||||
local function ShuffleArray(array)
|
||||
for i = #array, 2, -1 do -- 从后往前遍历
|
||||
local j = math.random(i) -- 生成1到i的随机数
|
||||
array[i], array[j] = array[j], array[i] -- 交换元素位置
|
||||
end
|
||||
end
|
||||
|
||||
---创建物品生成器实例
|
||||
---@param period number 生成周期次数
|
||||
---@param item_data table<number, number> 物品配置表 {物品ID = 总生成数量}
|
||||
---@return ItemGenerator 物品生成器实例
|
||||
local function CreateItemGenerator(period, item_data)
|
||||
local self = setmetatable({}, ItemGenerator)
|
||||
---@type number 存储生成周期
|
||||
self.period = period
|
||||
---@type table<number, number> 原始配置数据
|
||||
self.item_data = item_data
|
||||
---@type number 当前调用次数
|
||||
self.current_call = 0
|
||||
---@type table<number, number[]> 物品分布数据结构
|
||||
self.item_distributions = {}
|
||||
self:InitializeDistributions()
|
||||
return self
|
||||
end
|
||||
|
||||
---初始化物品分布数据
|
||||
function ItemGenerator:InitializeDistributions()
|
||||
-- 遍历所有物品配置
|
||||
for item_id, total in pairs(self.item_data) do
|
||||
-- 计算基础值和余数(保证总数 = 基础值*period + 余数)
|
||||
local base = math.floor(total / self.period)
|
||||
local remainder = total % self.period
|
||||
|
||||
-- 创建初始分布数组(全部填充基础值)
|
||||
local distribution = {}
|
||||
for i = 1, self.period do
|
||||
distribution[i] = base
|
||||
end
|
||||
|
||||
-- 生成索引数组并洗牌(用于随机分配余数)
|
||||
local indices = {}
|
||||
for i = 1, self.period do
|
||||
indices[i] = i
|
||||
end
|
||||
ShuffleArray(indices) -- 打乱索引顺序
|
||||
|
||||
-- 将余数随机分配到前remainder个位置
|
||||
for i = 1, remainder do
|
||||
distribution[indices[i]] = distribution[indices[i]] + 1
|
||||
end
|
||||
|
||||
-- 存储当前物品的分布数组
|
||||
self.item_distributions[item_id] = distribution
|
||||
end
|
||||
end
|
||||
|
||||
---重置生成器状态(当调用次数超过N时触发)
|
||||
function ItemGenerator:Reinitialize()
|
||||
self:InitializeDistributions() -- 重新生成分布数据
|
||||
self.current_call = 0 -- 重置调用计数器
|
||||
end
|
||||
|
||||
---生成物品列表(每次调用产生一个周期的结果)
|
||||
---@return number[] 包含物品ID的数组(结果经过随机排序)
|
||||
function ItemGenerator:Generate()
|
||||
-- 当超过周期次数时重置状态
|
||||
if self.current_call >= self.period then
|
||||
self:Reinitialize()
|
||||
end
|
||||
|
||||
local current_step = self.current_call + 1 -- 获取当前步骤(1-based)
|
||||
local result = {} -- 结果收集器
|
||||
|
||||
-- 遍历所有物品的分布数据
|
||||
for item_id, distribution in pairs(self.item_distributions) do
|
||||
local count = distribution[current_step] -- 获取当前步骤应生成数量
|
||||
for _ = 1, count do
|
||||
table.insert(result, item_id) -- 按数量添加物品ID到结果集
|
||||
end
|
||||
end
|
||||
|
||||
ShuffleArray(result) -- 打乱结果顺序保证随机性
|
||||
self.current_call = self.current_call + 1 -- 增加调用计数器
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
---获取当前未生成的物品剩余数量
|
||||
---@return table<number, number> 返回物品ID和剩余数量的映射表
|
||||
function ItemGenerator:GetRemainingItems()
|
||||
local remaining = {}
|
||||
local current_step = self.current_call -- 注意这里使用已调用次数(0-based)
|
||||
|
||||
-- 遍历所有物品的分布数据
|
||||
for item_id, distribution in pairs(self.item_distributions) do
|
||||
local total_remaining = 0
|
||||
|
||||
-- 计算从下一个步骤到周期结束的总数量
|
||||
for step = current_step + 1, self.period do
|
||||
total_remaining = total_remaining + distribution[step]
|
||||
end
|
||||
|
||||
remaining[item_id] = total_remaining
|
||||
end
|
||||
|
||||
return remaining
|
||||
end
|
||||
|
||||
return CreateItemGenerator
|
||||
69
Content/Lua/GamePlay/Level/BusyLevelLogicSubSystem.lua
Normal file
69
Content/Lua/GamePlay/Level/BusyLevelLogicSubSystem.lua
Normal file
@ -0,0 +1,69 @@
|
||||
local SubSystem = {}
|
||||
local Reactive = require("Core.Reactive")
|
||||
local Library = import("BusyGamePlayLibrary")
|
||||
local GameplayStatics = import("GameplayStatics")
|
||||
local BusyGamePlayLibrary = import("BusyGamePlayLibrary")
|
||||
|
||||
|
||||
local function CreateItemGenerator(level_config_data)
|
||||
local Generator = require("GamePlay.Level.BusyLevelItemGenerator")
|
||||
|
||||
local item_data = {}
|
||||
local period = level_config_data.Period
|
||||
for k, v in pairs(level_config_data.LevelItemIds) do
|
||||
item_data[k] = v.CountOfPeriod
|
||||
end
|
||||
return Generator(period, item_data)
|
||||
end
|
||||
|
||||
function SubSystem:ReceiveSubSystemInitialize()
|
||||
local world = BusyGamePlayLibrary.K2_GetWorld(self)
|
||||
self.start_time = GameplayStatics.GetTimeSeconds(world)
|
||||
|
||||
self.proxy = Reactive.ReactiveProperty({
|
||||
current_seconds = 0
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
function SubSystem:ReceiveWorldBeginPlay()
|
||||
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem").Get(self)
|
||||
|
||||
-- 读取关卡配置
|
||||
local is_suc, row_data = Library.GetLevelBaseConfig("Default", nil)
|
||||
assert(is_suc == true, "Can't find level base config")
|
||||
self.level_base_config = row_data
|
||||
|
||||
-- 创建物品生成器
|
||||
self.generator = CreateItemGenerator(row_data)
|
||||
|
||||
-- 创建初始篝火
|
||||
local bonfire = BusyActorManagerSubSystem:SpawnBonfire(row_data.FirstBonfirePosition)
|
||||
|
||||
-- 创建角色
|
||||
local role = BusyActorManagerSubSystem:SpawnRole(bonfire)
|
||||
GameplayStatics.GetPlayerController(self, 0):Possess(role)
|
||||
end
|
||||
|
||||
function SubSystem:ReceiveSubSystemTick(DeltaTime)
|
||||
-- local proxy = self.proxy
|
||||
-- local world = BusyGamePlayLibrary.K2_GetWorld(self)
|
||||
-- local current_time = GameplayStatics.GetTimeSeconds(world)
|
||||
-- local escapse_time = math.floor(current_time - self.start_time)
|
||||
-- if escapse_time > proxy.current_seconds then
|
||||
-- self:TrySpawnLevelItem()
|
||||
-- proxy.current_seconds = escapse_time
|
||||
-- print(proxy.current_seconds)
|
||||
-- end
|
||||
end
|
||||
|
||||
function SubSystem:TrySpawnLevelItem()
|
||||
local BusyActorManagerSubSystem = import("BusyActorManagerSubSystem").Get(self)
|
||||
local items = self.generator:Generate()
|
||||
for i, item_id in pairs(items) do
|
||||
BusyActorManagerSubSystem:SpawnLevelItem(item_id)
|
||||
print(i, item_id)
|
||||
end
|
||||
end
|
||||
|
||||
return Class(nil, nil, SubSystem)
|
||||
125
Content/Lua/GamePlay/LevelItem/LevelItem.lua
Normal file
125
Content/Lua/GamePlay/LevelItem/LevelItem.lua
Normal 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)
|
||||
6
Content/Lua/GamePlay/LuaBusyGameMode.lua
Normal file
6
Content/Lua/GamePlay/LuaBusyGameMode.lua
Normal 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)
|
||||
24
Content/Lua/GamePlay/LuaBusyPlayerController.lua
Normal file
24
Content/Lua/GamePlay/LuaBusyPlayerController.lua
Normal 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)
|
||||
203
Content/Lua/GamePlay/LuaBusyRole.lua
Normal file
203
Content/Lua/GamePlay/LuaBusyRole.lua
Normal 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)
|
||||
37
Content/Lua/GamePlay/Utils.lua
Normal file
37
Content/Lua/GamePlay/Utils.lua
Normal 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
|
||||
29
Content/Lua/GamePlay/Utils/BuildUtils.lua
Normal file
29
Content/Lua/GamePlay/Utils/BuildUtils.lua
Normal 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
|
||||
58
Content/Lua/GamePlay/Utils/RoleUtils.lua
Normal file
58
Content/Lua/GamePlay/Utils/RoleUtils.lua
Normal 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
|
||||
130
Content/Lua/UI/Bag/BagGridWidget.lua
Normal file
130
Content/Lua/UI/Bag/BagGridWidget.lua
Normal 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)
|
||||
57
Content/Lua/UI/Bag/BagPanel.lua
Normal file
57
Content/Lua/UI/Bag/BagPanel.lua
Normal 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)
|
||||
58
Content/Lua/UI/Bag/InventoryArea.lua
Normal file
58
Content/Lua/UI/Bag/InventoryArea.lua
Normal 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)
|
||||
54
Content/Lua/UI/Common/PopupMenu/PopupMenuItem.lua
Normal file
54
Content/Lua/UI/Common/PopupMenu/PopupMenuItem.lua
Normal 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)
|
||||
81
Content/Lua/UI/Common/PopupMenu/PopupMenuPanel.lua
Normal file
81
Content/Lua/UI/Common/PopupMenu/PopupMenuPanel.lua
Normal 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)
|
||||
28
Content/Lua/UI/Common/TableSwitcher/SwitcherWidget.lua
Normal file
28
Content/Lua/UI/Common/TableSwitcher/SwitcherWidget.lua
Normal 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)
|
||||
77
Content/Lua/UI/GameUIHud.lua
Normal file
77
Content/Lua/UI/GameUIHud.lua
Normal 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
32
Content/Lua/UI/MainUI.lua
Normal 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)
|
||||
68
Content/Lua/UI/PickBar.lua
Normal file
68
Content/Lua/UI/PickBar.lua
Normal 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)
|
||||
38
Content/Lua/UI/RoleStateWidget.lua
Normal file
38
Content/Lua/UI/RoleStateWidget.lua
Normal 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)
|
||||
28
Content/Lua/UI/SettingPanel.lua
Normal file
28
Content/Lua/UI/SettingPanel.lua
Normal 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)
|
||||
41
Content/Lua/UI/UILayerManager.lua
Normal file
41
Content/Lua/UI/UILayerManager.lua
Normal 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
35
Content/Lua/UI/Utils.lua
Normal 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
|
||||
50
Content/Lua/Utils/Vector2D.lua
Normal file
50
Content/Lua/Utils/Vector2D.lua
Normal 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
|
||||
Reference in New Issue
Block a user