UE4常见问题汇总

UE4 VS 系统找不到指定的文件

可以解决方案右键设置启动项Set as Startup Project

UE4输出中文乱码

VS卸载中文语言包安装英文语言包

UE4C++项目打包弹出网页

因为安装了VS2022,需要卸载重新安装VS2019

UE4编译太卡

可以把UE4和VS安装在固态硬盘,以及工程。这样速度能快好几倍

UE4找不到Interfaces/IPluginManager.h

需要在下面增加“Projects”

PublicDependencyModuleNames.AddRange(
    new string[]
    {
        "Core",
        // ... add other public dependencies that you statically link with here ...
        "Projects"
    }
);

UE4C++多线程

1、新建UChessAIAsyncNode类继承自UBlueprintAsyncActionBase

说明:蓝图节点带时钟图标叫异步节点,需要继承自上面这个类才可以

2、声明动态多播委托

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FChessAIMuitDynamicDele, FBestMove, chessBest);

说明:在类外面进行声明,这个宏有三个参数(需要绑定的委托,返回值类型,返回值名)

详情查看:UE4委托

3、创建需要绑定的委托

public:
	UPROPERTY(BlueprintAssignable)
	FChessAIMuitDynamicDele Complete;

说明:这玩意要加公有public 否则默认私有之后其他地方无法调用

说明2:BlueprintAssignable就是表示专门的委托节点

说明3:FChessAIMuitDynamicDele可以自定义但要与上面第2步相同

说明4:Complete名字随便取,其实就是节点的输出参数

4、声明异步节点

UFUNCTION(BlueprintCallable, Category = "ChessAI")
static UChessAIAsyncNode* ChessAIAlphaBeta(AChessAIBase *chess, const int max_depth);

说明:跟普通节点类似,其实没必要返回值,直接void就行,主要是注意需要使用的参数

5、实现异步节点

UChessAIAsyncNode* UChessAIAsyncNode::ChessAIAlphaBeta(AChessAIBase *chess, const int max_depth)
{
	UChessAIAsyncNode* BlueprintNode = NewObject<UChessAIAsyncNode>();
	(new FAutoDeleteAsyncTask<MyAsyncTask>(BlueprintNode, chess, max_depth))->StartBackgroundTask();
	return BlueprintNode;
}

说明:BlueprintNode就是刚刚那个类实例,主要用于以后调用绑定委托Complete,所以才需要传递给多线程

说明2:new FAutoDeleteAsyncTask<MyAsyncTask>表示创建一个多线程,其中MyAsyncTask是我们自己定义的,待会说。里面的参数都是需要用到的,也可以不传

说明3:StartBackgroundTask函数表示开始线程运行

说明4:FAutoDeleteAsyncTask是一个能自动销毁的可用线程,会自动从线程池中分配,也可以使用其 他的参考视频

6、创建线程类

先在头文件中引入相关头文件

#include "Async/AsyncWork.h"

然后如下图写一个类

 说明:1声明一个友元类,不知道啥意思

说明2:下面几个变量都可以自定义,需要的加

说明3:MyAsyncTask构造函数,并给成员变量初始化值,看上方步骤5会传进来一些参数

说明4:2需要重载这个DoWork函数,表示线程运行时调用

说明5:3就这么写,不知道啥意思,注意MyAsyncTask替换成自己的

7、实现线程运行函数DoWork

说明:前两行都是计算,需要的时间比较久所以需要多线程

说明2:ENamedThreads::GameThread表示里面的语句在游戏线程中调用

说明3:Node就是上面的UChessAIAsyncNode实例,之前通过构造函数传进来的

说明4:Complete就是刚刚的需要绑定的委托,也就是蓝图节点的输出部分

说明5:Broadcast函数应该就是调用委托了,此时蓝图节点会输出计算结果

8、总结

委托代理、多线程、异步节点

 h

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

#pragma once

#include "CoreMinimal.h"
#include "ChessAIBase.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Async/AsyncWork.h"
#include "ChessAIAsyncNode.generated.h"


//声明动态多播委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FChessAIMuitDynamicDele, FBestMove, chessBest);

/**
 * 
 */
UCLASS()
class CHESSAI_API UChessAIAsyncNode : public UBlueprintAsyncActionBase
{
	GENERATED_BODY()

public:
	UPROPERTY(BlueprintAssignable)
	FChessAIMuitDynamicDele Complete;

	UFUNCTION(BlueprintCallable, Category = "ChessAI")
	static UChessAIAsyncNode* ChessAIAlphaBeta(AChessAIBase *chess, const int max_depth);
	
};

class MyAsyncTask : public  FNonAbandonableTask
{
	// 1
	friend class FAutoDeleteAsyncTask<MyAsyncTask>;
	UChessAIAsyncNode *Node;
	AChessAIBase *chess;
	const int max_depth;
	MyAsyncTask(UChessAIAsyncNode *WaitNode,AChessAIBase *WaitChess,const int Waitmax_depth)
	: Node(WaitNode), chess(WaitChess), max_depth(Waitmax_depth){}

	// 2
	void DoWork();
	// 3
	FORCEINLINE TStatId GetStatId() const
	{
		RETURN_QUICK_DECLARE_CYCLE_STAT(MyAsyncTask, STATGROUP_ThreadPoolAsyncTasks);
	}
};

cpp

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


#include "ChessAIAsyncNode.h"

UChessAIAsyncNode* UChessAIAsyncNode::ChessAIAlphaBeta(AChessAIBase *chess, const int max_depth)
{
	UChessAIAsyncNode* BlueprintNode = NewObject<UChessAIAsyncNode>();
	(new FAutoDeleteAsyncTask<MyAsyncTask>(BlueprintNode, chess, max_depth))->StartBackgroundTask();
	return BlueprintNode;
}

void MyAsyncTask::DoWork()
{
	FBestMove chessBest;
	chessBest = chess->AlphaBeta(max_depth);
	AsyncTask(ENamedThreads::GameThread, [=]()
	{
		Node->Complete.Broadcast(chessBest);
	});
}

UE4C++多线程打包后崩溃

编辑器运行正常,打包以后运行崩溃

上述多线程方法的后续(只是为了解决问题并不是最好方法):

1、不要在多线程里用动态多播,无论是带参数的还是不带参数的

 2、不要在DoWork函数里使用

// AsyncTask(ENamedThreads::GameThread, [=]()
// {
// 	Node->Complete.Broadcast();
// });

具体不清楚,总之加上以后就会崩溃

那么问题来了,如何返回值呢?我采用了蓝图计时器,等待计算结束,使用一个类的布尔成员变量来判断是否结束。

补充:

跟多播没啥关系,主要是不能这样写

表示在游戏线程运行,这样打包以后就不会崩溃了 

UE4C++打包以后调用DLL找不到路径

FPlatformProcess::PushDllDirectory()函数可以告诉程序所需dll的路径
FPlatformProcess::PushDllDirectory(*(FPaths::ProjectDir() / TEXT("Plugins/ChessAI/Source/ThirdParty/ChessAIDLL/x64/Release/")));
FPlatformProcess::PushDllDirectory(*(FPaths::ProjectDir() / TEXT("Plugins/ChessAI/Binaries/ThirdParty/ChessAIDLL/Win64/")));

注意这两行,路径不同,第二条路径才是打包以后的插件目录,第一条路径在打包之后将会失效

比如

 这三条路径都是上方第一行输出的,1为编辑器状态,2为编辑器构建运行状态,3为打包后状态

如果没有双方第二行代码,则需要手动把相关dll复制到exe同级目录,比较麻烦,网上也有自动拷贝dll到指定路径的代码,这里不做讨论。

如果崩溃注意dll的依赖项。

猜你喜欢

转载自blog.csdn.net/u012863565/article/details/125057580