[17] C++ 虚幻引擎网络系统开发

Day1

加载UserWidget

//HUD.cpp
Super::BeginPlay();
//显示UMG
//1.加载类
//参数outer:职责用来管理关系链,用来方便做内存管理
//outer如果填nullptr,则表明加载的数据为临时数据,使用声明周期不是持久的,将被放置在临时数据空间,随着内存回收会被第一批回收
//destroy:用来标记actor消亡(挂载在actor身上的组件呢?)
//TEXT("")和""有什么区别?TEXT宏创建的是与平台无关(不强制以来任何平台特性,方便跨平台)的数据字符串,直接双引号创建的是c++的字符串
//string:是不是就是字符串?他是字符串对象
//_c:用来告知加载器,加载的是蓝图类
TSubclassOf<UMainMenuUserWidget> MyClass = LoadClass<UMainMenuUserWidget>(
   nullptr, TEXT("/Script/UMGEditor.WidgetBlueprint'/Game/Lego/UMG/MainMenu/UMG_MainMenu.UMG_MainMenu_C'"));
//TSubclassOf<>:虚幻中添加的类的类型模板,用来方便我们拾取操作类
//2.创建实例
if (MyClass)
{
   //第一个参数填玩家控制器
   UMainMenuUserWidget* MyMainMenuUI = CreateWidget<UMainMenuUserWidget>(GetOwningPlayerController(), MyClass);
   //3.添加到视口
   MyMainMenuUI->AddToViewport();
   //显示鼠标光标
   GetOwningPlayerController()->SetShowMouseCursor(true);
}

C++ 调用 蓝图的办法

使用GetWidgetFromName获取蓝图对象

NativeOnInitialized中函数调用时机

思维导图

Day2

程序的状态

类型转换 : dynamic_cast和static_cast区别是 , dynamic会查虚函数表

蓝图绑定控件 : 

//强制让子类蓝图绑定一个控件
UPROPERTY(meta=(BindWidgetAnim))

C++ 绑定蓝图的单击事件 多播代理

注意点 :

1、绑定函数的绑定原型是多播代理声明时候的原型

2、绑定的函数要加UFUNCTION

3、最大最用是可以在蓝图中事件绑定

说明 : 从而实现在C++ 父类强制子类绑定按钮指针、

命名 :  全屏UMG***** 子控件Widget_****

项目制作 : 

材质是像素 运算的过程

C++调用蓝图动画

umg里面 : Get Owning Player 和其他蓝图获取playercontroller一样

C++控制蓝图显示UI

Widget Switcher 选项卡控件

 Spacer控件

FString、FText、FName

国际化语言

选中文本路径

添加新语言 -> 收集文本 -> 编辑此语言的翻译 -> 计算字数 -> 编译文本

蓝图设置

控制台运行C++函数

void AMainMenuGameMode::CallFunc()
{
   FText t1 = NSLOCTEXT("s1", "k1", "二狗");
   GEngine->AddOnScreenDebugMessage(0, 10, FColor::Green, t1.ToString());
}

Day3

分辨率更改和全屏

播放声音

创建 :

加载文件什么情况需要加_C

按键拾取 :

拾取用户输入的按键用作自定义按键

增强输入

 

 TMap同质容器

TMap<int32, FString> Map;

Map.Add(1, "123");
Map.Add(2, "234");
Map.Add(3, "345");
Map.Add(4, "567");

 if (Map.Contains(1))
// {
     UE_LOG(LogTemp, Log, TEXT("ok"))
 }
 else
 {
     UE_LOG(LogTemp, Log, TEXT("no"))
 }

 UE_LOG(LogTemp, Log, TEXT("读取 %s"), *Map[1]);

for (auto Kv : Map)
{
   UE_LOG(LogTemp, Log, TEXT("%d"),Kv.Key)
   UE_LOG(LogTemp, Log, TEXT("%s"),*Kv.Value)
   
}

UE_LOG(LogTemp, Log, TEXT("检查容器大小 = %d"), Map.Num())

 Map.Remove(1);

 Map.Reset();

自定义结构体生成数据报表

报错查找 : 无法解析外部符号 , 有声明没定义

CastTo : Cast只能在U类使用

自定义数据类型不需要加UPROPERTY()

Tips : 新代码运行前先保存

Day4

封装创建Widget代码块

//定义
#define MAKEUSERWIDGETOBJECT(TClass, ObjectPtr, BPClassPath) if (!ObjectPtr)\
   {\
      TSubclassOf<TClass> UIClass = LoadClass<TClass>(nullptr, BPClassPath);\
      ObjectPtr = CreateWidget<TClass>(GetOwningPlayerController(), UIClass);\
   }
//使用
MAKEUSERWIDGETOBJECT(USettingUserWidget, SettingUserWidget, TEXT("/Script/UMGEditor.WidgetBlueprint'/Game/Lego/UMG/MainMenu/UMG_Setting.UMG_Setting_C'"));

//卸载
#undef MAKEUSERWIDGETOBJECT

泛型 or 模板

//定义
template <typename T>
void AMainMenuHUD::MakeUserWidgetObject(T*& ObjectPtr, const TCHAR* Path)//T*& ObjectPtr 对一个泛型指针进行引用
{
   if (!ObjectPtr)
   {
      TSubclassOf<T> UIClass = LoadClass<T>(nullptr, Path);
      if (!UIClass)
      {
         UE_LOG(LogTemp, Log, TEXT("LoadClass Path is invaild!"));
      }
      ObjectPtr = CreateWidget<T>(GetOwningPlayerController(), UIClass);
   }
}
//使用
MakeUserWidgetObject<URegisterUserWidget>(RegisterUserWidget, TEXT("蓝图类文件路径"));
//MakeUserWidgetObject 函数名 <URegisterUserWidget> 编程泛型 T (Widget指针, TEXT("蓝图类文件路径"));
//泛型 : 做出功能但不考虑其类型 , 但会在编译阶段判断是否正确比如 ↓↓↓↓ 泛型编程处理的是逻辑

 

UMG_API

HUD : GetOwningPlayerController() //拿到HUD拥有者
GetOwningPlayer(); //拿到UMG拥有者
GetParent(); // 查找父节点
GetChildrenCount(); //查找子控件数量
GetChildAt(**); //获取子控件

UUserWidget的构造函数

UserWidget没有无参构造 : 如果父类只有带参构造函数没有无参构造 , 子类需要传递带参构造

Day5

正则表达式

//校验邮箱地址是否合规
FRegexPattern Pattern(TEXT("^(\\w|\\.){1,10}@[a-zA-Z0-9]{1,10}\\.[a-zA-Z]{2,6}$")); //*****@***.** 
FRegexMatcher Matcher(Pattern, MainTextBox->GetText().ToString());
if (!Matcher.FindNext())
{
   UE_LOG(LogTemp, Log, TEXT("邮箱地址非法!"));
   return;
}

增强输入

新建输入

IA_Move

IM_Player

挂载增强输入组件

UPROPERTY(EditAnywhere)
UInputAction* IA_Jump;
UPROPERTY(EditAnywhere)
UInputMappingContext* InputMappingContext;

 按键映射到对应的输入操作

操作映射

if (DTKeyMap.Contains(TEXT("Jump")))
{
   FKeyInfoHeader* KeyInfoHeader = reinterpret_cast<FKeyInfoHeader*>(DTKeyMap[TEXT("Jump")]);
   //装载按键和InputAction
   FKey Key = GetUserCustomKey(TEXT("Jump"));
   if (!Key.IsValid())//如果用户没有自定义过按键,则使用默认的
   {
      Key = KeyInfoHeader->DefaultKey;
   }
   MappingContext->MapKey(KeyInfoHeader->InputAction, Key); //按键映射到对应的输入操作
}

使用宏的方式

#define ADDMAPKEY_DIGITALACTION(KeyEventName) if (DTKeyMap.Contains(KeyEventName))\
         {\
            FKeyInfoHeader* KeyInfoHeader = reinterpret_cast<FKeyInfoHeader*>(DTKeyMap[KeyEventName]);\
            FKey Key = GetUserCustomKey(KeyEventName);\
            if (!Key.IsValid())\
            {\
               Key = KeyInfoHeader->DefaultKey;\
            }\
            MappingContext->MapKey(KeyInfoHeader->InputAction, Key);\
         }
#undef ADDMAPKEY_DIGITALACTION

轴映射 

if (DTKeyMap.Contains(TEXT("MoveForward")))
{
   FKeyInfoHeader* KeyInfoHeader = reinterpret_cast<FKeyInfoHeader*>(DTKeyMap[TEXT("MoveForward")]);
   //装载按键和InputAction
   FKey Key = GetUserCustomKey(TEXT("MoveForward"));
   if (!Key.IsValid()) //如果用户没有自定义过按键,则使用默认的
   {
      Key = KeyInfoHeader->DefaultKey;
   }
   MappingContext->MapKey(KeyInfoHeader->InputAction, Key);
}

if (DTKeyMap.Contains(TEXT("MoveBack")))
{
	FKeyInfoHeader* KeyInfoHeader = reinterpret_cast<FKeyInfoHeader*>(DTKeyMap[TEXT("MoveBack")]);
	//装载按键和InputAction
	FKey Key = GetUserCustomKey(TEXT("MoveBack"));
	if (!Key.IsValid()) //如果用户没有自定义过按键,则使用默认的
	{
		Key = KeyInfoHeader->DefaultKey;
	}
	FEnhancedActionKeyMapping& KeyMapping = MappingContext->MapKey(KeyInfoHeader->InputAction, Key);
    
	//添加值反转
	UInputModifierNegate* Negate = NewObject<UInputModifierNegate>(MappingContext); //翻转
	KeyMapping.Modifiers.Add(Negate);
}

//获取是否有自定义按键
FKey ALGPlayerCharacter::GetUserCustomKey(FName KeyEventName)
{
	FKey Key;
	//检查有没有存档
	if (!KeyMappingSaveGame && UGameplayStatics::DoesSaveGameExist(TEXT("userkey"), 0))
	{
		KeyMappingSaveGame = Cast<UKeyMappingSaveGame>(UGameplayStatics::LoadGameFromSlot(TEXT("userkey"), 0));
	}
	if (KeyMappingSaveGame && KeyMappingSaveGame->CustomKeys.Contains(KeyEventName))
	{
		Key = KeyMappingSaveGame->CustomKeys[KeyEventName];
	}
	return Key;
}

装载增强输入系统

//删掉读档内存
KeyMappingSaveGame = nullptr; //释放SaveGame内存 ; 会进入虚幻 内存回收机制
//获取增强输入系统 
UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<
   UEnhancedInputLocalPlayerSubsystem>(Pc->GetLocalPlayer());
//装载Mapping
Subsystem->AddMappingContext(MappingContext, 0);

绑定按键事件

// Called to bind functionality to input
void ALGPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
   Super::SetupPlayerInputComponent(PlayerInputComponent);
   //绑定按键的事件Action
   if (UEnhancedInputComponent* MyInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent))
   {
      if (UInputAction* MyInputAction = GetInputAction(TEXT("Jump")))
      {
         MyInputComponent->BindAction(MyInputAction, ETriggerEvent::Started, this, &ALGPlayerCharacter::DoJump);
      }
      if (UInputAction* MyInputAction = GetInputAction(TEXT("Crouch")))
      {    //                        绑的事件 , 方式 , 对象 , 触发事件
         MyInputComponent->BindAction(MyInputAction, ETriggerEvent::Started, this, &ALGPlayerCharacter::DoCrouch);
      }
      if (UInputAction* MyInputAction = GetInputAction(TEXT("MoveForward")))
      {
         MyInputComponent->BindAction(MyInputAction, ETriggerEvent::Triggered, this, &ALGPlayerCharacter::Move);
      }
   }
}
//数据表中检索并返回与特定事件相关联的输入动作对象
UInputAction* ALGPlayerCharacter::GetInputAction(FName KeyEventName)
{
	if (!KeyDataTable)
	{
		KeyDataTable = LoadObject<UDataTable>(
			nullptr, TEXT("/Script/Engine.DataTable'/Game/Lego/Data/UI/DT_KeyInfo.DT_KeyInfo'"));
	}

	if (KeyDataTable)
	{
		TMap<FName, uint8*> DTKeyMap = KeyDataTable->GetRowMap();
		if (DTKeyMap.Contains(KeyEventName))
		{
			FKeyInfoHeader* KeyInfoHeader = reinterpret_cast<FKeyInfoHeader*>(DTKeyMap[KeyEventName]);
			return KeyInfoHeader->InputAction;
		}
	}
	return nullptr;
}

思维导图

posted @ 2024-04-22 18:44  啊賢  阅读(66)  评论(0编辑  收藏  举报