UE4 Unlua的快速使用

目录

  • Unlua的使用
    • 前言
    • 下载Unlua插件
    • 插件安装
    • 快速入门
    • 语法汇总
      • 模块导入
      • 多行字符串
      • 官方静态方法调用
      • 蓝图方法调用
      • 重载蓝图中的方法
      • 主动调用被重载的蓝图方法
      • 输入绑定
      • 动态绑定Lua脚本
      • 委托
      • 容器使用
    • 延迟与协程的使用
      • C++ 调用Lua
    • 静态导出自定义类型到Lua使用
      • 网络
      • UMG资源释放
      • 自定义加载器
      • 动画通知

Unlua的使用

前言

整理一下Unlua的整个学习流程

下载Unlua插件

我们此处使用的是腾讯的Unlua插件,打开官方的Github链接,下载对应的版本
官方链接GitHub
Wiki文档

插件安装

把下载好的插件放在自己新建项目的Plugins文件夹下,编译启动

快速入门

萌新看的图文教学
老手看的文档

点击Create的时候,会根据填写的模块名字生成路径
在这里插入图片描述
在这里插入图片描述

语法汇总

模块导入

与路径对应即可

local Common = require "Core.Common"

在这里插入图片描述

多行字符串

在这里插入图片描述

官方静态方法调用

UE.类名.静态方法名字

nil代表无效值空值未定义的值
在这里插入图片描述

蓝图方法调用

self:XXXFunction() 

在这里插入图片描述
在这里插入图片描述
输出结果:这是我的蓝图测试

重载蓝图中的方法

function M:XXXFunction())
end

在这里插入图片描述

输出结果:M:TestFunction

主动调用被重载的蓝图方法

self.Overridden.XXXFunction()

在这里插入图片描述

输出结果:
这是我的蓝图测试
M:TestFunction

输入绑定

function M:LeftMouseButton_Pressed()
end

实例:绑定按键并打印它的名字

local M = UnLua.Class()

local PrintString = UE.UKismetSystemLibrary.PrintString

local function Print(text)
    PrintString(nil, text, true, false, UE.FLinearColor(1, 1, 1, 1), 100)
end

function M:ReceiveBeginPlay()
    local msg =
        [[
    来试试以下输入吧:
    字母、数字、小键盘、方向键、鼠标
    ]]
    Print(msg)
end

local function SetupKeyBindings()
    local key_names = 
    {
        -- 字母
        "A", "B", --[["C",]] "D", "E","F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", --[["V", ]] "W", "X", "Y", "Z",
        -- 数字
        "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine",
        -- 小键盘
        "NumPadOne", "NumPadTwo", "NumPadThree", "NumPadFour", "NumPadFive", "NumPadSix", "NumPadSeven", "NumPadEight", "NumPadNine",
        -- 方向键
        "Up", "Down", "Left", "Right",
        -- ProjectSettings -> Engine - Input -> Action Mappings
        "Fire", "Aim",
    }
    
    for _, key_name in ipairs(key_names) do
        M[key_name .. "_Pressed"] = function(self, key)
            Print(string.format("按下了%s", key.KeyName))
        end
    end
end

local function SetupAxisBindings()
    local axis_names = {
        "MoveForward", "MoveRight", "Turn", "LookUp", "LookUpRate", "TurnRate"
    }
    for _, axis_name in ipairs(axis_names) do
        M[axis_name] = function(self, value)
            if value ~= 0 then
                Print(string.format("%s(%f)", axis_name, value))
            end
        end
    end
end

SetupKeyBindings() -- 在require的时候会执行
SetupAxisBindings()

local BindKey = UnLua.Input.BindKey

BindKey(M, "C", "Pressed", function(self, Key)
    Print("按下了C")
end)

BindKey(M, "C", "Pressed", function(self, Key)
    Print("复制")
end, { Ctrl = true })

BindKey(M, "V", "Pressed", function(self, Key)
    Print("按下了V")
end)

BindKey(M, "V", "Pressed", function(self, Key)
    Print("粘贴")
end, { Ctrl = true })

return M

动态绑定Lua脚本

Actor:

    local World = self:GetWorld()
    local SpawnClass = self.SpawnClass
    local Transform = self.SpawnPointActor:GetTransform()
    local AlwaysSpawn = UE.ESpawnActorCollisionHandlingMethod.AlwaysSpawn
    World:SpawnActor(SpawnClass, Transform, AlwaysSpawn, self, self, "XXX.XXX")

Object:

local WidgetClass = self.WidgetClass
local img = NewObject(WidgetClass, self, nil, "XXX.XXX")
img:AddToViewport()
img:RandomPosition()

委托

local FLinearColor = UE.FLinearColor

local M = UnLua.Class()

function M:Construct()
	-- Bind
    self.ClickMeButton.OnClicked:Add(self, self.OnButtonClicked)
    self.ClickMeCheckBox.OnCheckStateChanged:Add(self, self.OnCheckBoxToggled)
    -- SetTimerByEvent
    self.TimerHandle = UE.UKismetSystemLibrary.K2_SetTimerDelegate({ self, self.OnTimer }, 1, true)
end

function M:OnButtonClicked()
    local r = math.random()
    local g = math.random()
    local b = math.random()

    self.ClickMeButton:SetBackgroundColor(FLinearColor(r, g, b, 1))
end

function M:OnCheckBoxToggled(on)
    if on then
        self.CheckBoxText:SetText("已选中")
    else
        self.CheckBoxText:SetText("未选中")
    end
end

function M:OnTimer())
end

function M:Destruct()
    -- Unbind
    self.ClickMeButton.OnClicked:Remove(self, self.OnButtonClicked)
    self.ClickMeCheckBox.OnCheckStateChanged:Remove(self, self.OnCheckBoxToggled)
    -- ClearTimer
    UE.UKismetSystemLibrary.K2_ClearAndInvalidateTimerHandle(self, self.TimerHandle)
end

return M

容器使用

创建原生容器时通常需要指定参数类型,来确定容器内存放的数据类型

参数类型示例实际类型
booleantrueBoolean
number0Interge
string“”String
tableFVectorVector
userdataFVector(1,1,1)Vector

例:

local array = TArray({ElementType})
local set = TSet({ElementType})
local map = TMap({KeyType}, {ValueType})
local array = UE.TArray(0)
local set = UE.TSet(0)
local map = UE.TMap(0, true)

延迟与协程的使用

local M = UnLua.Class()

local Latent = UE.UKismetSystemLibrary.XXXLatentFunction 

-- 定义一个协程函数
function M:StartCoroutine()
    local co = coroutine.create(function()
        print("开始等待...")
        Latent.Wait(2.0) 
        print("等待结束")
    end)
    coroutine.resume(co)
end

function M:ReceiveBeginPlay()
    self:StartCoroutine()
end

return M
local M = UnLua.Class()

local PrintString = UE.UKismetSystemLibrary.PrintString

local function Print(text)
    PrintString(nil, text, true, false, UE.FLinearColor(1, 1, 1, 1), 100)
end

local function run(self, name)
   Print(string.format("协程%s:启动", name))
    for i = 1, 5 do
        UE.UKismetSystemLibrary.Delay(self, 1)
       Print(string.format("协程%s:%d", name, i))
    end
   Print(string.format("协程%s:结束", name))
end

function M:ReceiveBeginPlay()
    local msg = [[
    —— ReceiveBeginPlay"
    ]]
    Print(msg)

    coroutine.resume(coroutine.create(run), self, "A")
    coroutine.resume(coroutine.create(run), self, "B")
end

return M

C++ 调用Lua

C++部分

void UTutorialBlueprintFunctionLibrary::CallLuaByFLuaTable()
{
    PrintScreen(TEXT("[C++]CallLuaByFLuaTable 开始"));
    UnLua::FLuaEnv Env;

    const auto Require = UnLua::FLuaFunction(&Env, "_G", "require");
    const auto RetValues1 = Require.Call("Tutorials.08_CppCallLua");
    check(RetValues1.Num() == 2);

    const auto RetValue = RetValues1[0];
    const auto LuaTable = UnLua::FLuaTable(&Env, RetValue);
    const auto RetValues2 = LuaTable.Call("CallMe", 3.3f, 4.4f);
    check(RetValues2.Num() == 1);

    const auto Msg = FString::Printf(TEXT("[C++]收到来自Lua的返回,结果=%f"), RetValues2[0].Value<float>());
    PrintScreen(Msg);
    PrintScreen(TEXT("[C++]CallLuaByFLuaTable 结束"));
}

void UTutorialBlueprintFunctionLibrary::CallLuaByGlobalTable()
{
    PrintScreen(TEXT("[C++]CallLuaByGlobalTable 开始"));

    UnLua::FLuaEnv Env;
    const auto bSuccess = Env.DoString("G_08_CppCallLua = require 'Tutorials.08_CppCallLua'");
    check(bSuccess);

    const auto RetValues = UnLua::CallTableFunc(Env.GetMainState(), "G_08_CppCallLua", "CallMe", 1.1f, 2.2f);
    check(RetValues.Num() == 1);

    const auto Msg = FString::Printf(TEXT("[C++]收到来自Lua的返回,结果=%f"), RetValues[0].Value<float>());
    PrintScreen(Msg);
    PrintScreen(TEXT("[C++]CallLuaByGlobalTable 结束"));
}

static void PrintScreen(const FString& Msg)
{
    UKismetSystemLibrary::PrintString(nullptr, Msg, true, false, FLinearColor(0, 0.66, 1), 100);
}

lua 部分

local M = UnLua.Class()

local PrintString = UE.UKismetSystemLibrary.PrintString

local function Print(text)
    PrintString(nil, text, true, false, UE.FLinearColor(1, 1, 1, 1), 100)
end

function M:ReceiveBeginPlay()
    local msg =
        [[
    —— ReceiveBeginPlay
    ]]
    Print(msg)
    UE.UTutorialBlueprintFunctionLibrary.CallLuaByGlobalTable()
    Print("=================")
    UE.UTutorialBlueprintFunctionLibrary.CallLuaByFLuaTable()
end

function M.CallMe(a, b)
    local ret = a + b
    local msg = string.format("[Lua]收到来自C++的调用,a=%f b=%f,返回%f", a, b, ret)
    Print(msg)
    return ret
end

return M

静态导出自定义类型到Lua使用

C++.h

#pragma once

#include "CoreMinimal.h"

struct FTutorialObject
{
protected:
	FString Name;

public:
	FTutorialObject();

	explicit FTutorialObject(const FString& Name)
		:Name(Name)
	{
	}

	FString GetTitle() const
	{
		return FString::Printf(TEXT("《%s》"), *Name);
	}

	FString ToString() const
	{
		return GetTitle();
	}
};

c++ cpp

#include "TutorialObject.h"

#include "LuaCore.h"
#include "UnLua.h"
#include "UnLuaEx.h"

FTutorialObject::FTutorialObject()
{
}

static int32 FTutorialObject_New(lua_State* L)
{
	const auto NumParams = lua_gettop(L);
    if (NumParams != 2)
    {
        UNLUA_LOGERROR(L, LogUnLua, Log, TEXT("%s: Invalid parameters!"), ANSI_TO_TCHAR(__FUNCTION__));
        return 0;
    }

    const char* NameChars = lua_tostring(L, 2);
    if (!NameChars)
    {
        UE_LOG(LogUnLua, Log, TEXT("%s: Invalid tutorial name!"), ANSI_TO_TCHAR(__FUNCTION__));
        return 0;
    }

    const auto UserData = NewUserdataWithPadding(L, sizeof(FTutorialObject), "FTutorialObject");
	new(UserData) FTutorialObject(UTF8_TO_TCHAR(NameChars));
    return 1;
}

static const luaL_Reg FTutorialObjectLib[] =
{
    { "__call", FTutorialObject_New },
    { nullptr, nullptr }
};

BEGIN_EXPORT_CLASS(FTutorialObject)
ADD_FUNCTION(GetTitle)
ADD_LIB(FTutorialObjectLib)
END_EXPORT_CLASS()
IMPLEMENT_EXPORTED_CLASS(FTutorialObject)

lua部分

local M = UnLua.Class()
local PrintString = UE.UKismetSystemLibrary.PrintString

local function Print(text)
    PrintString(nil, text, true, false, UE.FLinearColor(1, 1, 1, 1), 100)
end

function M:ReceiveBeginPlay()
    local msg =
        [[
    -- ReceiveBeginPlay
    ]]
    Print(msg)
    
    local tutorial = UE.FTutorialObject("教程")
    msg = string.format("tutorial -> %s\n\ntutorial:GetTitle() -> %s", tostring(tutorial), tutorial:GetTitle())
   Print(msg)
end

网络

使用 {函数名}RPC 可以覆盖蓝图中RPC函数的实现
使用 OnRep
{变量名} 可以覆盖蓝图中变量同步消息的处理

蓝图里面添加多人联机复制广播之类的
在这里插入图片描述
lua里写真正调用的方法
在这里插入图片描述

UMG资源释放

这部分直接附着官方内容
UMG:

---@type ReleaseUMG_Root_C
local M = UnLua.Class()

function M:Construct()
    print("Root Construct")
    self.Button_AddNew.OnClicked:Add(self, self.OnAddNew)
    self.Button_ReleaseAll.OnClicked:Add(self, self.OnReleaseAll)
end

function M:OnAddNew()
    print("Root Add New")
    local widget_class = UE.UClass.Load("/Game/Tutorials/11_ReleaseUMG/ReleaseUMG_ItemParent.ReleaseUMG_ItemParent_C")
    local widget = NewObject(widget_class, self)
    self.VerticalBox_Panel:AddChildToVerticalBox(widget)
end

function M:OnReleaseAll()
    self:RemoveFromViewport()
end

function M:Destruct()
    print("Root Destruct")
    self:Release()
end

return M

测试部分:

--[[
    说明:

    UMG对象的释放流程:
    1、调用self:Release(),解除LuaTable在C++侧的引用
    2、确保LuaTable在Lua侧没有其他引用,触发LuaGC
    3、C++侧收到UObject_Delete回调,解除UMG在C++侧的引用
    4、确保UMG在C++侧没有其他引用,触发UEGC

    小提示:

    使用控制台命令查看对象和类的引用情况:
    
    查看指定类的引用列表:Obj List Class=ReleaseUMG_Root_C
    查看指定对象的引用链:Obj Refs Name=ReleaseUMG_Root_C_0
]] --

local Screen = require "Tutorials.Screen"

local M = UnLua.Class()

local function print_intro()
    local msg =
        [[
使用以下按键进行一次强制垃圾回收:

C:强制 C++ GC
L:强制 Lua GC

—— 本示例来自 "Content/Script/Tutorials.11_ReleaseUMG.lua"
]]
    Screen.Print(msg)
end

function M:ReceiveBeginPlay()
    local widget_class = UE.UClass.Load("/Game/Tutorials/11_ReleaseUMG/ReleaseUMG_Root.ReleaseUMG_Root_C")
    local widget_root = NewObject(widget_class, self)
    widget_root:AddToViewport()

    print_intro()
end

function M:L_Pressed()
    collectgarbage("collect")
    Screen.Print('collectgarbage("collect")')
end

function M:C_Pressed()
    UE.UKismetSystemLibrary.CollectGarbage()
    Screen.Print("UKismetSystemLibrary.CollectGarbage()")
end

return M

自定义加载器

说明:通过绑定 FUnLuaDelegates::CustomLoadLuaFile 可以实现自定义Lua加载器
方式1:查找路径固定,性能更好
方式2:通过package.path查找,更加灵活

lua部分:

UE.UTutorialBlueprintFunctionLibrary.SetupCustomLoader(1)
Screen.Print(string.format("FromCustomLoader1:%s", require("Tutorials")))

package.loaded["Tutorials"] = nil

package.path = package.path .. ";./?/Index.lua"
UE.UTutorialBlueprintFunctionLibrary.SetupCustomLoader(2)
Screen.Print(string.format("FromCustomLoader2:%s", require("Tutorials")))

UE.UTutorialBlueprintFunctionLibrary.SetupCustomLoader(0)

C++部分

bool CustomLoader1(UnLua::FLuaEnv& Env, const FString& RelativePath, TArray<uint8>& Data, FString& FullPath)
{
    const auto SlashedRelativePath = RelativePath.Replace(TEXT("."), TEXT("/"));
    FullPath = FString::Printf(TEXT("%s%s.lua"), *GLuaSrcFullPath, *SlashedRelativePath);

    if (FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
        return true;

    FullPath.ReplaceInline(TEXT(".lua"), TEXT("/Index.lua"));
    if (FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
        return true;

    return false;
}
bool CustomLoader2(UnLua::FLuaEnv& Env, const FString& RelativePath, TArray<uint8>& Data, FString& FullPath)
{
    const auto SlashedRelativePath = RelativePath.Replace(TEXT("."), TEXT("/"));
    const auto L = Env.GetMainState();
    lua_getglobal(L, "package");
    lua_getfield(L, -1, "path");
    const char* Path = lua_tostring(L, -1);
    lua_pop(L, 2);
    if (!Path)
        return false;

    TArray<FString> Parts;
    FString(Path).ParseIntoArray(Parts, TEXT(";"), false);
    for (auto& Part : Parts)
    {
        Part.ReplaceInline(TEXT("?"), *SlashedRelativePath);
        FPaths::CollapseRelativeDirectories(Part);
        
        if (FPaths::IsRelative(Part))
            FullPath = FPaths::ConvertRelativePathToFull(GLuaSrcFullPath, Part);
        else
            FullPath = Part;

        if (FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
            return true;
    }

    return false;
}

动画通知

local M = UnLua.Class()

function M:Received_Notify(MeshComp, Animation)
    return true
end

return M

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/750326.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何寻找强势货币和弱势货币?

外汇交易的独特之处在于&#xff0c;它融合了两种货币的价值&#xff0c;其中一种货币的价值通过另一种货币来体现。举例来说&#xff0c;USDJPY外汇反映了美元与日元之间的价值关系&#xff0c;而EURUSD则代表了欧元与美元的价值对比。 通过开仓操作&#xff0c;我们预测一种…

继续捡钱,每天几百块!

每日操作计划&#xff1a; 标普信息科技(161128)&#xff0c;溢价8.5%&#xff0c;限购100&#xff0c;一拖七&#xff0c;单户每天700*8.5%59元 印度基金LOF(164824)&#xff0c;溢价2.6%&#xff0c;限购100&#xff0c;一拖七&#xff0c;单户每天700*2.6%18元 美元债LOF(…

如何解决Oracle中PL Developer过期

如果长时间不使用PL Deveploer&#xff0c;再次打开有可能会出现以下页面&#xff1a; 上方页面说明此软件已经过期&#xff0c;有两种方法可以解决上述问题&#xff0c;第一种&#xff1a; 操作注册表&#xff1a; WinR 输入指令“regedit”打开注册表&#xff0c;出现下方页…

List常用操作比for循环更优雅的写法

private String name; //姓名 private Integer age; //年龄 private Integer departId; //所属部门id } List list new ArrayList<>(); 复制代码 简单遍历 使用lamada表达式之前&#xff0c;如果需要遍历list时&#xff0c;一般使用增强for循环&#xff0c;代码如…

利用圆上两点和圆半径求解圆心坐标

已知圆上两点P1&#xff0c;P2&#xff0c;坐标依次为 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x_1,y_1),(x_2,y_2) (x1​,y1​),(x2​,y2​)&#xff0c;圆的半径为 r r r&#xff0c;求圆心的坐标。 假定P1&#xff0c;P2为任意两点&#xff0c;则两点连成线段的中点坐标是 x m i …

Python学习笔记24:进阶篇(十三)常见标准库使用之数据压缩功能模块zlib,gzip,bz2,lzma的学习使用

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 数据压缩…

活动|华院计算受邀参加2024全球人工智能技术大会(GAITC),探讨法律大模型如何赋能社会治理

6月22至23日&#xff0c;备受瞩目的2024全球人工智能技术大会&#xff08;GAITC&#xff09;在杭州市余杭区未来科技城隆重举行。本届大会以“交叉、融合、相生、共赢”为主题&#xff0c;集“会、展、赛”为一体&#xff0c;聚“产、学、研”于一堂。值得一提的是&#xff0c;…

如何在线上快速定位bug(干货)

想必有许多人都想我刚进公司一样不会快速定位线上bug吧&#xff0c;不会快速定位bug会大大降低我们的开发效率&#xff0c;随之而来的就是工作质量下降、业绩下滑。 我总结了一些我常用的线上定位技巧&#xff0c;希望能帮助到大家&#xff01; 我这里以使用阿里云日志分析作…

【电路笔记】-MOSFET放大器

MOSFET放大器 文章目录 MOSFET放大器1、概述2、电路图3、电气特性3.1 ** I D = F ( V G S ) I_D=F(V_{GS}) ID​=F(VGS​)**特性3.2 I D = F ( V D S ) I_D=F(V_{DS}) ID​=F(VDS​)特性4、MOSFET放大器5、输入和输出电压6、电压增益7、总结1、概述 在前面的文章中,我们已经…

ThreadLocal 源码浅析

前言 多线程在访问同一个共享变量时很可能会出现并发问题&#xff0c;特别是在多线程对共享变量进行写入时&#xff0c;那么除了加锁还有其他方法避免并发问题吗&#xff1f;本文将详细讲解 ThreadLocal 的使用及其源码。 一、什么是 ThreadLocal&#xff1f; ThreadLocal 是 …

多电商账户为什么要用指纹浏览器?

随着电子商务的蓬勃发展&#xff0c;越来越多的商家选择开设多店来扩大经营规模。然而多店运营也带来了一系列的挑战&#xff0c;其中之一就是账号安全。 1. 了解反检测浏览器和代理服务器 在我们开始讨论如何有效地使用反检测浏览器之前&#xff0c;我们首先需要了解这两个工…

第三十四篇——幸存者偏差:如何避免被已知信息误导?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 人类顶层智慧的总结&#xff0c;一定会让我们在做事的过程中产生降维打击…

测试用例设计方法-流程分析法

一、引言 在软件开发过程中&#xff0c;测试是确保软件质量的关键环节之一。而测试用例设计作为测试过程中的重要组成部分&#xff0c;其质量和完备性直接影响到测试效果和软件的最终交付质量。 测试用例设计的目标是通过设计一组有效的测试用例来检查软件系统的各种功能和行为…

正点原子rk3588烧录linux和安卓镜像

1、烧录 Linux buildroot 系统镜像 1.1 进入 Loader 模式&#xff1a; 按住开发板上的 V&#xff08;音量&#xff09;按键不松&#xff0c;给开发板 上电或复位&#xff0c;此时烧录工具会提示&#xff1a;发现一个 LOADER 设备&#xff0c;表示开发板此时已经处于 Loader 模…

华为昇腾310B1芯片DVPP模块VENC视频编码接口调用流程以及视频编码代码梳理

目录 1 接口调用流程 2 代码流程梳理 1 接口调用流程 在CANN 8.0.RC1 AscendCL应用软件开发指南 (C&C, 推理) 01.pdf 文档中有接口调用流程 2 代码流程梳理 代码在samples: CANN Samples - Gitee.com 然后我把这个代码完整的看了一遍&#xff0c;然后梳理了详细的代码…

Transformers 安装及 google-t5/t5-small 机器翻译示例

文章目录 Github文档推荐文章简介安装官方示例google-t5/t5-small使用脚本进行训练Pytorch 机器翻译数据集下载数据集格式转换 Github https://github.com/huggingface/transformers 文档 https://huggingface.co/docs/transformers/indexhttps://github.com/huggingface/tr…

第一后裔The First Descendant开服时间、配置要求一览

第一后裔是一款采用虚幻5引擎打造的第三人称合作射击动作RPG&#xff0c;玩家将化身为一名继承者&#xff0c;通过各种任务和故事不断成长&#xff0c;为守护人类与对抗侵略者战斗。该作即将上线&#xff0c;为了不让玩家们错过这款精彩的游戏&#xff0c;本文整理了第一后裔上…

今天不看文章,明天变垃圾(明天收费)-----字节数据分析发展过程中所遭遇的挑战

字节数据分析发展过程中所遭遇的挑战 三个核心议题&#xff1a; 海量数据分析性能&#xff1a;会议指出Spark分析性能不足成为了一个显著问题&#xff0c;尤其是在需要毫秒级响应的业务场景中。实时导入与查询能力&#xff1a;目前Kylin只能以T1的形式提供分析服务&#xff0…

第十节 动态面板实现推动和拉动效果

在原型设计中我们经常会遇到元件使用显示更多或者收起效果,下面以面板元件推动与拉动效果做案件说明。 一、设置原有内容 我这里添加一个表格内容,添加“显示更多”文本超链接 二、设置在更多显示面板内容 添加一个动态面板,设置有内容、无内容两个状态 在有内容面板中添…

秋招突击——6/26~6/27——复习{二维背包问题——宠物小精灵之收服}——新作{串联所有单词的字串}

文章目录 引言复习二维背包问题——宠物小精灵之收服个人实现重大问题 滚动数组优化实现 新作串联所有单词的字串个人实现参考实现 总结 引言 今天应该是舟车劳顿的一天&#xff0c;头一次在机场刷题&#xff0c;不学习新的东西了&#xff0c;就复习一些之前学习的算法了。 复…