当前位置: 首页 > article >正文

【UE5 C++课程系列笔记】10——动态单播/多播的基本使用

目录

概念

申明动态委托

一、DECLARE_DYNAMIC_DELEGATE 

二、DECLARE_DYNAMIC_MULTICAST_DELEGATE

绑定动态委托

一、BindDynamic

二、AddDynamic

三、RemoveDynamic

执行动态委托

​一、Execute 

二、ExecuteIfBound 

三、IsBound

四、Broadcast

动态单播使用示例

一、两个输入参数无返回值 

二、一个输入参数一个返回值 

动态多播使用示例


上一篇:【UE5 C++课程系列笔记】09——多播委托的基本使用-CSDN博客

概念

        动态单播/多播委托基于虚幻的反射系统,可以在蓝图中进行绑定等操作,这使得它在蓝图与 C++ 交互方面非常有用。动态单播只绑定一个函数,而动态多播可以绑定多个函数,与非动态的单播/多播相比,动态单播/多播提供了蓝图可访问性,使其能在蓝图中进行添加绑定、移除绑定以及调用等操作。与动态单播不同的是动态多播委托通常没有返回值。这是因为动态多播委托的主要目的是实现事件广播机制,它会依次调用所有绑定的函数。

申明动态委托

一、DECLARE_DYNAMIC_DELEGATE 

        DECLARE_DYNAMIC_DELEGATE 是虚幻引擎中用于声明动态单播委托类型的宏。动态委托允许在运行时更灵活地绑定函数,并且支持蓝图(UE 的可视化脚本系统)与 C++ 之间的交互。与普通委托相比,动态委托提供了一种更动态的方式来处理事件响应和函数回调,这在构建复杂的游戏系统,尤其是需要在蓝图中方便地配置和处理事件的场景下非常有用。

无参数的动态委托声明:DECLARE_DYNAMIC_DELEGATE (FDelegateName)。

带一个参数的动态委托声明:DECLARE_DYNAMIC_DELEGATE_OneParam (FDelegateName, ParamType, ParamName)。其中 ParamType 是参数类型,ParamName 是参数名称,用于在蓝图等环境中更清晰地标识参数。例如,声明一个带有一个 int 类型参数的动态委托:DECLARE_DYNAMIC_DELEGATE_OneParam (FMyDynamicDelegate, int, MyIntParam)。

二、DECLARE_DYNAMIC_MULTICAST_DELEGATE

        DECLARE_DYNAMIC_MULTICAST_DELEGATE 用于声明动态多播委托类型的宏。动态多播委托同样支持蓝图和 C++ 的交互,并且可以绑定多个函数。当触发这个委托时,所有绑定的函数都会被依次调用,这对于实现事件广播机制,特别是在需要多个对象或函数对同一事件做出响应,且这些响应可能需要在蓝图中灵活配置的场景下非常有用。

无参数的动态多播委托声明:DECLARE_DYNAMIC_MULTICAST_DELEGATE (FDelegateName)。

带一个参数的动态多播委托声明:DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam (FDelegateName, ParamType, ParamName)。例如,声明一个带有一个 float 类型参数的动态多播委托:DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam (FMyDynamicMulticastDelegate, float, MyFloatParam)。

绑定动态委托

一、BindDynamic

   BindDynamic是虚幻引擎(UE)中用于将函数绑定到动态单播委托上的方法,主要用于动态委托。这种绑定方式支持蓝图(UE 的可视化脚本系统)和 C++ 之间的交互,使得在运行时可以灵活地设置委托所关联的函数,并且能够让蓝图方便地对委托事件进行响应。

语法一般为:DelegateInstance.BindDynamic(ObjectPtr, &FunctionPointer)。其中DelegateInstance是委托实例,ObjectPtr是指向包含函数的对象的指针(通常是UObject指针),&FunctionPointer是要绑定的函数的地址。

在如下示例代码中,当玩家与一个物体交互时,触发一个动态委托。

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyInteractable.generated.h"

// 声明一个带有一个FString参数(表示交互物体名称)的动态委托
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnInteract, FString, InteractableName);

UCLASS()
class MYGAME_API AMyInteractable : public AActor
{
    GENERATED_BODY()
public:
    // 定义动态委托实例
    FOnInteract OnInteract;

    void Interact(FString Name)
    {
        // 触发动态委托(如果已经绑定函数)
        OnInteract.ExecuteIfBound(Name);
    }
};

class UMyInteractUI : public UUserWidget
{
public:
    void BindToInteractable(AMyInteractable* Interactable)
    {
        if (Interactable)
        {
            // 将本对象的函数动态绑定到交互物体的委托上
            Interactable->OnInteract.BindDynamic(this, &UMyInteractUI::OnInteractHandler);
        }
    }

    UFUNCTION(BlueprintImplementableEvent)
    void OnInteractHandler(FString InteractableName)
    {
        // 这个函数可以在蓝图中实现具体的UI更新逻辑,比如显示交互物体的名称
        UE_LOG(LogTemp, Warning, TEXT("Interacted with: %s"), *InteractableName);
    }
};

二、AddDynamic

  AddDynamic主要用于将函数绑定到动态多播委托上。它和BindDynamic类似,都是用于动态地将函数关联到委托,但AddDynamic更侧重于多播委托的操作,用于在已经存在的动态多播委托基础上添加新的函数绑定,使得多个函数可以订阅(绑定)到这个委托,当委托被触发(调用Broadcast)时,所有绑定的函数都会被依次调用。

语法为:DynamicMulticastDelegateInstance.AddDynamic(ObjectPtr, &FunctionPointer)。其中DynamicMulticastDelegateInstance是动态多播委托实例,ObjectPtr是指向包含函数的对象的指针(通常是UObject指针),&FunctionPointer是要添加绑定的函数的地址。

在如下示例代码中,当角色释放技能时,通过动态多播委托通知多个系统进行响应。

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyCharacter.generated.h"

// 声明一个带有一个int参数(表示技能ID)的动态多播委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnSkillCast, int, SkillID);

UCLASS()
class MYGAME_API AMyCharacter : public AActor
{
    GENERATED_BODY()
public:
    // 定义动态多播委托实例,并使用UPROPERTY(BlueprintAssignable)使其可在蓝图中绑定
    UPROPERTY(BlueprintAssignable)
    FOnSkillCast OnSkillCast;

    void CastSkill(int SkillId)
    {
        // 触发动态多播委托
        OnSkillCast.Broadcast(SkillId);
    }
};

class USkillEffectUI : public UUserWidget
{
public:
    void BindToCharacter(AMyCharacter* Character)
    {
        if (Character)
        {
            // 将本对象的函数动态绑定到角色的技能释放委托上
            Character->OnSkillCast.AddDynamic(this, &USkillEffectUI::OnSkillCastHandler);
        }
    }

    UFUNCTION(BlueprintImplementableEvent)
    void OnSkillCastHandler(int SkillId)
    {
        // 在这里可以在蓝图中实现显示技能特效等相关逻辑
        UE_LOG(LogTemp, Warning, TEXT("Skill %d cast. Displaying effect..."), SkillId);
    }
};

三、RemoveDynamic

  RemoveDynamic用于从动态委托中移除之前通过BindDynamicAddDynamic绑定的函数。这在对象生命周期结束或者不再需要某个函数对委托事件做出响应时非常重要,可以避免委托在触发时调用已不存在或不需要的函数,从而防止程序出现错误或意外行为。

语法为:DelegateInstance.RemoveDynamic(ObjectPtr, &FunctionPointer)。其中DelegateInstance是委托实例,ObjectPtr是指向包含函数的对象的指针(通常是UObject指针),&FunctionPointer是要移除绑定的函数的地址。

在如下示例代码中,当一个 UI 对象被销毁时,需要从任务进度更新委托中移除它绑定的函数

#include "CoreMinimal.h"
#include "UObject/ObjectPtr.h"
#include "MyQuestSystem.h"
#include "QuestUI.h"

void UQuestUI::UnbindFromQuestSystem(AMyQuestSystem* QuestSystem)
{
    if (QuestSystem)
    {
        // 从任务系统的进度更新委托中移除本对象绑定的函数
        QuestSystem->OnQuestProgressUpdate.RemoveDynamic(this, &UQuestUI::OnQuestProgressUpdateHandler);
    }
}

执行动态委托

一、Execute 

        对于动态委托,Execute用于触发委托所绑定的函数执行。与普通委托类似,它会直接调用绑定的函数。不过在动态委托的语境下,它主要用于触发单播动态委托(通过DECLARE_DYNAMIC_DELEGATE声明的委托),并且要求委托必须已经绑定了函数,否则会导致程序崩溃,因为它不会检查委托是否绑定函数就尝试调用。

        对于无参数的动态委托实例DynamicDelegateInstance,使用DynamicDelegateInstance.Execute()。如果动态委托带有参数,比如声明了一个带有一个int类型参数的动态委托FMyDynamicDelegate,并且已经绑定了函数,在执行时语法为DynamicDelegateInstance.Execute(ParamValue),其中ParamValue是符合委托参数要求的int类型的值。

示例代码:

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyInteractableObject.generated.h"

// 声明一个带有一个FString参数(表示交互提示信息)的动态委托
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnInteract, FString, InteractionPrompt);

UCLASS()
class MYGAME_API AMyInteractableObject : public AActor
{
    GENERATED_BODY()
public:
    // 定义动态委托实例
    FOnInteract OnInteract;

    void Interact()
    {
        FString Prompt = "Interact with this object";
        // 假设委托已经绑定了函数,直接执行委托
        OnInteract.Execute(Prompt);
    }
};

class UMyInteractUI : public UUserWidget
{
public:
    void BindToInteractable(AMyInteractableObject* Interactable)
    {
        if (Interactable)
        {
            // 将本对象的函数动态绑定到交互物体的委托上
            Interactable->OnInteract.BindDynamic(this, &UMyInteractUI::OnInteractHandler);
        }
    }

    UFUNCTION(BlueprintImplementableEvent)
    void OnInteractHandler(FString InteractionPrompt)
    {
        // 在蓝图中实现显示交互提示信息的逻辑
        UE_LOG(LogTemp, Warning, TEXT("Interaction prompt: %s"), *InteractionPrompt);
    }
};

二、ExecuteIfBound 

        ExecuteIfBound是一种更安全的执行动态委托的方式,主要用于执行单播动态委托。它会先检查动态委托是否已经绑定了函数,如果已绑定,则执行该函数;如果未绑定,则不执行任何操作,这样可以避免因空指针引用而导致的程序错误。这种方法在不确定委托是否已经绑定函数的情况下非常实用,能够增强程序的健壮性。

        与Execute类似,对于无参数的动态委托实例DynamicDelegateInstance,使用DynamicDelegateInstance.ExecuteIfBound()。如果动态委托带有参数,例如一个带有一个float类型参数的动态委托,语法为DynamicDelegateInstance.ExecuteIfBound(ParamValue),其中ParamValue是符合委托参数要求的float类型的值。

示例代码:

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MySkill.generated.h"

// 声明一个带有一个int参数(表示升级后的技能等级)的动态委托
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnSkillLevelUp, int, NewLevel);

UCLASS()
class MYGAME_API AMySkill : public AActor
{
    GENERATED_BODY()
public:
    FOnSkillLevelUp OnSkillLevelUp;

    void LevelUp(int NewLevel)
    {
        // 检查委托是否绑定函数,如果绑定则执行,否则不做任何事
        OnSkillLevelUp.ExecuteIfBound(NewLevel);
    }
};

三、IsBound

   IsBound用于检查动态委托是否已经绑定了函数。它返回一个布尔值,true表示动态委托已经绑定了函数,false表示没有绑定函数。这个方法在需要根据委托的绑定状态来执行不同逻辑的场景中非常有用,比如在触发委托之前先检查是否有函数可供执行,或者在动态配置委托绑定关系后检查绑定是否成功等。

        对于动态委托实例DynamicDelegateInstance,语法为bool IsBound = DynamicDelegateInstance.IsBound();

示例代码:

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyEventSystem.generated.h"

// 声明一个无参数的动态委托
DECLARE_DYNAMIC_DELEGATE(FOnGameEvent);

UCLASS()
class MYGAME_API AMyEventSystem : public AActor
{
    GENERATED_BODY()
public:
    FOnGameEvent OnGameEvent;

    void TriggerEventIfBound()
    {
        if (OnGameEvent.IsBound())
        {
            // 如果委托已经绑定函数,则触发委托
            OnGameEvent.ExecuteIfBound();
        }
        else
        {
            UE_LOG(LogTemp, Warning, TEXT("Event not bound, no function to execute."));
        }
    }
};

四、Broadcast

        对于多播动态委托,应该使用Broadcast方法来触发委托。Broadcast会按照函数绑定的顺序依次调用所有绑定的函数,从而实现事件广播的功能,让多个对象或函数对同一个事件做出响应。

示例代码:

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyEventSystem.generated.h"

// 声明一个带有一个int参数(表示事件相关的数值)的多播动态委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMultiEvent, int, EventValue);

UCLASS()
class MYGAME_API AMyEventSystem : public AActor
{
    GENERATED_BODY()
public:
    FOnMultiEvent OnMultiEvent;

    void TriggerEventCorrect(int Value)
    {
        // 正确的用法,使用Broadcast触发多播委托
        OnMultiEvent.Broadcast(Value);
    }
};

动态单播使用示例

一、两个输入参数无返回值 

        在如下代码中,定义了一个名为 ADynamicSingleDelegateActor 的类,用于处理动态单播委托相关的功能。类中提供了初始化委托、调用委托以及释放委托的函数,分别是InitDynamicTwoParamsDelegate、CallDynamicTwoParamsDelegate、ReleaseDynamicTwoParamsDelegate。

头文件:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "DynamicSingleDelegateActor.generated.h"

DECLARE_DYNAMIC_DELEGATE_TwoParams(FDynamicDelegate, FString, InName, int32, InMoney);

UCLASS()
class STUDY_API ADynamicSingleDelegateActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ADynamicSingleDelegateActor();

	UFUNCTION(BlueprintCallable)
	void InitDynamicTwoParamsDelegate(FDynamicDelegate InDelegate);

	UFUNCTION(BlueprintCallable)
	void CallDynamicTwoParamsDelegate(FString InStr, int32 InMoney);

	UFUNCTION(BlueprintCallable)
	void ReleaseDynamicTwoParamsDelegate();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

protected:
	FDynamicDelegate DynamicTwoParamsDelegate;
};

源文件:

// Fill out your copyright notice in the Description page of Project Settings.


#include "Delegate/DynamicSingleDelegateActor.h"

// Sets default values
ADynamicSingleDelegateActor::ADynamicSingleDelegateActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

void ADynamicSingleDelegateActor::InitDynamicTwoParamsDelegate(FDynamicDelegate InDelegate)
{
	DynamicTwoParamsDelegate = InDelegate;
}

void ADynamicSingleDelegateActor::CallDynamicTwoParamsDelegate(FString InStr, int32 InMoney)
{
	DynamicTwoParamsDelegate.ExecuteIfBound(InStr, InMoney);
}

void ADynamicSingleDelegateActor::ReleaseDynamicTwoParamsDelegate()
{
	DynamicTwoParamsDelegate.Clear();
}

// Called when the game starts or when spawned
void ADynamicSingleDelegateActor::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void ADynamicSingleDelegateActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

编译后,在UEEditor中先创建派生自DynamicSingleDelegateActor的蓝图类,这里命名为“BP_DynamicSingleDelegateActor”

将“BP_DynamicSingleDelegateActor”拖入视口

在关卡蓝图中,设置运行开始时执行InitDynamicTwoParamsDelegate来绑定一个委托事件,然后当按下1键时,执行委托事件。

执行效果如下,当按下1键时成功触发绑定的自定义事件

二、一个输入参数一个返回值 

        在如下代码中,初始化委托、调用委托以及释放委托的函数,分别是 InitDynamicTwoParamsOneRetDelegate、CallDynamicTwoParamsOneRetDelegate、ReleaseDynamicTwoParamsOneRetDelegate

头文件

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "DynamicSingleDelegateActor.generated.h"

DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(int32, FDynamicDelegateRetOne, FString, InName);

UCLASS()
class STUDY_API ADynamicSingleDelegateActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ADynamicSingleDelegateActor();

	UFUNCTION(BlueprintCallable)
	void InitDynamicTwoParamsOneRetDelegate(FDynamicDelegateRetOne InDelegate);

	UFUNCTION(BlueprintCallable)
	void CallDynamicTwoParamsOneRetDelegate(FString InStr);

	UFUNCTION(BlueprintCallable)
	void ReleaseDynamicTwoParamsOneRetDelegate();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

protected:
	FDynamicDelegateRetOne DynamicOneParamsOneRetDelegate;
};

源文件

// Fill out your copyright notice in the Description page of Project Settings.


#include "Delegate/DynamicSingleDelegateActor.h"

// Sets default values
ADynamicSingleDelegateActor::ADynamicSingleDelegateActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;
}

void ADynamicSingleDelegateActor::InitDynamicTwoParamsOneRetDelegate(FDynamicDelegateRetOne InDelegate)
{
	DynamicOneParamsOneRetDelegate = InDelegate;
}

void ADynamicSingleDelegateActor::CallDynamicTwoParamsOneRetDelegate(FString InStr)
{
	int32 returnVal = DynamicOneParamsOneRetDelegate.Execute(InStr);
	UE_LOG(LogTemp, Warning, TEXT("return Value: %d"), returnVal);
}

void ADynamicSingleDelegateActor::ReleaseDynamicTwoParamsOneRetDelegate()
{
	DynamicOneParamsOneRetDelegate.Clear();
}

// Called when the game starts or when spawned
void ADynamicSingleDelegateActor::BeginPlay()
{
	Super::BeginPlay();
}

// Called every frame
void ADynamicSingleDelegateActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

 编译后,在UEEditor中先创建派生自DynamicSingleDelegateActor的蓝图类,这里命名为“BP_DynamicSingleDelegateActor”

打开“BP_DynamicSingleDelegateActor”,在事件开始后调用InitDynamicTwoParamsOneRetDelegate,由于委托有返回值,这里用“Create Event”节点

创建一个匹配函数,在匹配函数内只打印一下传入的参数,并固定返回100

将蓝图“BP_DynamicSingleDelegateActor”拖入视口

在关卡蓝图中,通过按键1调用函数CallDynamicTwoParamsOneRetDelegate,从而执行委托事件

执行效果如下,可以看到成功打印委托的输入输出参数。

动态多播使用示例

        在如下代码中,定义了一个名为 ADynamicMultiDelegateActor 的类,用于处理动态多播委托相关的功能。类中提供了初始化委托、调用委托的函数,分别是InitDynamicMultiThree、CallDynamicMultiThree。 动态多播委托 FDynamicMultiThree带有三个不同类型的参数,用于传递参数信息。

 头文件

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "DynamicMultiDelegateActor.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FDynamicMultiThree, FString, InName, int32, InHealth, int32, InMana);

UCLASS()
class STUDY_API ADynamicMultiDelegateActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ADynamicMultiDelegateActor();

	void InitDynamicMultiThree(FDynamicMultiThree InDelegate);

	UFUNCTION(BlueprintCallable)
	void CallDynamicMultiThree(FString InName, int32 InHealth, int32 InMana);

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	UPROPERTY(BLUEprintAssignable)
	FDynamicMultiThree DynamicMultiThree;
};

源文件

// Fill out your copyright notice in the Description page of Project Settings.


#include "DynamicMultiDelegateActor.h"

// Sets default values
ADynamicMultiDelegateActor::ADynamicMultiDelegateActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;
}

void ADynamicMultiDelegateActor::InitDynamicMultiThree(FDynamicMultiThree InDelegate)
{
	DynamicMultiThree = InDelegate;
}

void ADynamicMultiDelegateActor::CallDynamicMultiThree(FString InName, int32 InHealth, int32 InMana)
{
	DynamicMultiThree.Broadcast(InName, InHealth, InMana);
}

// Called when the game starts or when spawned
void ADynamicMultiDelegateActor::BeginPlay()
{
	Super::BeginPlay();
}

// Called every frame
void ADynamicMultiDelegateActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

创建派生自“DynamicMultiDelegateActor”的蓝图类“BP_DynamicMultiDelegateActor”

打开“BP_DynamicMultiDelegateActor”,在事件开始运行时绑定委托事件

在关卡蓝图中,再次绑定委托。通过按键1调用CallDynamicMultiThree函数,从而调用所有绑定到动态多播委托的函数。

可以看到执行效果如下,按一次按键打印了两次“Test”,表示两个绑定的委托事件都成功触发。


http://www.kler.cn/a/442733.html

相关文章:

  • Oracle Dataguard(主库为双节点集群)配置详解(5):将主库复制到备库并启动同步
  • Unreal Engine 5 C++ Advanced Action RPG 八章笔记
  • FPGA的 基本结构(Xilinx 公司Virtex-II 系列FPGA )
  • 数据存储与信息技术领域 - 磁带技术:企业用磁带与音乐磁带
  • 基于当前最前沿的前端(Vue3 + Vite + Antdv)和后台(Spring boot)实现的低代码开发平台
  • 前端开发:表格、列表、表单
  • [面试题]--索引用了什么数据结构?有什么特点?
  • 【代码随想录day62】【C++复健】 97. 小明逛公园(Floyd 算法精讲);127. 骑士的攻击(A * 算法精讲)
  • Qt调用adb对嵌入式设备的配置文件进行修改,写入多行内容
  • 决策树的生成与剪枝
  • 【Liunx】Liunx之Ubuntu入门篇
  • 画图,matlab,
  • 搭建MongoDB
  • 渗透测试实战—利用防火墙突破网络隔离
  • vue3的element的日期组件添加prefix
  • 【MySQL】数据库必考知识点:查询操作全面详解与深度解剖
  • Halcon中split_skeleton_lines(Operator)算子原理及应用详解
  • Springboot 启动 Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required
  • DC-6笔记
  • Mysql学习笔记之SQL-2
  • 剑指Offer|LCR 007. 三数之和
  • sunset: midnight
  • Elasticsearch Kibana (windows版本) 安装和启动
  • vue3-tp8-Element:对话框实现
  • TCP Analysis Flags 之 TCP Fast Retransmission
  • 【Unity功能集】TextureShop纹理工坊(二)图层(下)