第18章 UE5创建命令
在现代游戏中,命令系统是玩家与游戏交互的重要方式,特别是在RPG和MMO游戏中。本章将探讨如何在UE5.2中创建一个灵活、安全且用户友好的命令系统,让玩家能够通过文本输入执行各种游戏功能。
18.1 检测基本的命令
命令系统的核心是能够解析用户输入并将其转换为游戏动作。让我们从创建一个基本的命令解析器开始:
cpp
// CommandSystem.h
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "CommandSystem.generated.h"
// 命令执行委托
DECLARE_DYNAMIC_DELEGATE_RetVal_TwoParams(bool, FCommandExecuteDelegate, const TArray<FString>&, Arguments, FString&, ErrorMessage);
// 命令定义结构
USTRUCT(BlueprintType)
struct FCommandDefinition
{
GENERATED_BODY()
// 命令名称
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Command")
FString Name;
// 命令描述
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Command")
FString Description;
// 使用示例
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Command")
FString Usage;
// 所需权限级别
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Command")
int32 RequiredPermissionLevel;
// 是否需要目标
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Command")
bool bRequiresTarget;
// 是否在战斗中可用
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Command")
bool bAvailableInCombat;
// 命令别名
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Command")
TArray<FString> Aliases;
// 执行委托
FCommandExecuteDelegate ExecuteDelegate;
// 构造函数
FCommandDefinition()
: Name("")
, Description("")
, Usage("")
, RequiredPermissionLevel(0)
, bRequiresTarget(false)
, bAvailableInCombat(true)
{
}
};
// 命令执行结果
USTRUCT(BlueprintType)
struct FCommandResult
{
GENERATED_BODY()
// 是否成功执行
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Command")
bool bSuccess;
// 结果消息
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Command")
FString Message;
// 构造函数
FCommandResult()
: bSuccess(false)
, Message("")
{
}
// 带参数构造函数
FCommandResult(bool InSuccess, const FString& InMessage)
: bSuccess(InSuccess)
, Message(InMessage)
{
}
};
// 命令事件委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCommandExecuted, const FCommandResult&, Result);
/**
* 命令系统 - 处理游戏命令的解析和执行
*/
UCLASS()
class MYGAME_API UCommandSystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
// 初始化
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
// 注册命令
UFUNCTION(BlueprintCallable, Category = "Command System")
bool RegisterCommand(const FCommandDefinition& CommandDef);
// 注销命令
UFUNCTION(BlueprintCallable, Category = "Command System")
bool UnregisterCommand(const FString& CommandName);
// 执行命令
UFUNCTION(BlueprintCallable, Category = "Command System")
FCommandResult ExecuteCommand(const FString& CommandString, int32 UserPermissionLevel = 0, AActor* TargetActor = nullptr);
// 获取命令帮助
UFUNCTION(BlueprintCallable, Category = "Command System")
FString GetCommandHelp(const FString& CommandName);
// 获取所有命令列表
UFUNCTION(BlueprintCallable, Category = "Command System")
TArray<FString> GetAllCommands();
// 获取带有指定前缀的命令列表(用于自动完成)
UFUNCTION(BlueprintCallable, Category = "Command System")
TArray<FString> GetCommandsWithPrefix(const FString& Prefix);
// 检查命令是否存在
UFUNCTION(BlueprintCallable, Category = "Command System")
bool CommandExists(const FString& CommandName);
// 解析命令字符串
UFUNCTION(BlueprintCallable, Category = "Command System")
void ParseCommandString(const FString& CommandString, FString& OutCommandName, TArray<FString>& OutArguments);
// 命令执行事件
UPROPERTY(BlueprintAssignable, Category = "Command System")
FOnCommandExecuted OnCommandExecuted;
// 注册内置命令
UFUNCTION(BlueprintCallable, Category = "Command System")
void RegisterBuiltInCommands();
private:
// 命令映射
TMap<FString, FCommandDefinition> Commands;
// 命令前缀字符(例如:/,!等)
UPROPERTY()
FString CommandPrefix;
// 检查命令前缀
bool CheckCommandPrefix(FString& CommandString);
// 查找命令定义
bool FindCommandDefinition(const FString& CommandName, FCommandDefinition& OutCommandDef);
// 输出帮助信息
FCommandResult OutputHelpInfo(const TArray<FString>& Arguments);
// 输出系统信息
FCommandResult OutputSystemInfo(const TArray<FString>& Arguments);
};
// CommandSystem.cpp
#include "CommandSystem.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetSystemLibrary.h"
void UCommandSystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
// 设置命令前缀
CommandPrefix = TEXT("/");
// 注册内置命令
RegisterBuiltInCommands();
UE_LOG(LogTemp, Log, TEXT("Command System initialized"));
}
void UCommandSystem::Deinitialize()
{
// 清除所有命令
Commands.Empty();
Super::Deinitialize();
}
bool UCommandSystem::RegisterCommand(const FCommandDefinition& CommandDef)
{
// 检查命令名是否为空
if (CommandDef.Name.IsEmpty())
{
UE_LOG(LogTemp, Warning, TEXT("Cannot register command with empty name"));
return false;
}
// 检查命令名是否已存在
if (Commands.Contains(CommandDef.Name.ToLower()))
{
UE_LOG(LogTemp, Warning, TEXT("Command '%s' already registered"), *CommandDef.Name);
return false;
}
// 检查委托是否绑定
if (!CommandDef.ExecuteDelegate.IsBound())
{
UE_LOG(LogTemp, Warning, TEXT("Command '%s' has no execute delegate bound"), *CommandDef.Name);
return false;
}
// 添加命令
Commands.Add(CommandDef.Name.ToLower(), CommandDef);
// 添加别名
for (const FString& Alias : CommandDef.Aliases)
{
if (!Alias.IsEmpty() && !Commands.Contains(Alias.ToLower()))
{
FCommandDefinition AliasDef = CommandDef;
AliasDef.Name = Alias;
Commands.Add(Alias.ToLower(), AliasDef);
}
}
UE_LOG(LogTemp, Log, TEXT("Registered command: %s"), *CommandDef.Name);
return true;
}
bool UCommandSystem::UnregisterCommand(const FString& CommandName)
{
// 检查命令名是否为空
if (CommandName.IsEmpty())
{
return false;
}
// 尝试移除命令
bool bRemoved = false;
// 移除主命令
FCommandDefinition CommandDef;
if (FindCommandDefinition(CommandName, CommandDef))
{
Commands.Remove(CommandName.ToLower());
bRemoved = true;
// 移除别名
for (const FString& Alias : CommandDef.Aliases)
{
Commands.Remove(Alias.ToLower());
}
}
if (bRemoved)
{
UE_LOG(LogTemp, Log, TEXT("Unregistered command: %s"), *CommandName);
}
return bRemoved;
}
FCommandResult UCommandSystem::ExecuteCommand(const FString& CommandString, int32 UserPermissionLevel, AActor* TargetActor)
{
FString CommandName;
TArray<FString> Arguments;
// 检查命令前缀
FString ProcessedCommand = CommandString;
CheckCommandPrefix(ProcessedCommand);
// 解析命令字符串
ParseCommandString(ProcessedCommand, CommandName, Arguments);
// 检查命令是否为空
if (CommandName.IsEmpty())
{
return FCommandResult(false, TEXT("No command specified"));
}
// 查找命令定义
FCommandDefinition CommandDef;
if (!FindCommandDefinition(CommandName, CommandDef))
{
return FCommandResult(false, FString::Printf(TEXT("Unknown command: %s"), *CommandName));
}
// 检查权限
if (UserPermissionLevel < CommandDef.RequiredPermissionLevel)
{
return FCommandResult(false, TEXT("You don't have permission to use this command"));
}
// 检查是否需要目标
if (CommandDef.bRequiresTarget && !TargetActor)
{
return FCommandResult(false, TEXT("This command requires a target"));
}
// 检查是否在战斗中可用
// 在实际游戏中,您需要添加检查玩家是否在战斗中的逻辑
bool bInCombat = false; // 示例,假设玩家不在战斗中
if (bInCombat && !CommandDef.bAvailableInCombat)
{
return FCommandResult(false, TEXT("This command cannot be used in combat"));
}
// 执行命令
FString ErrorMessage;
bool bSuccess = CommandDef.ExecuteDelegate.Execute(Arguments, ErrorMessage);
// 创建结果
FCommandResult Result;
Result.bSuccess = bSuccess;
if (bSuccess)
{