丧心病狂虚幻C++
- 天 地 玄 黄 宇 宙 洪 荒
- 虚幻C++绝对难得毫无廉耻
🔥虚幻物体类型结构
- 虚幻
C++类
是一个代码预置,没有外部调整界面,一切设置都由代码完成,是不可视化的
- 通过虚幻
C++类
派生的蓝图类
,其中的蓝图成员
仍然能接收其虚幻C++类
修改或变动
- 通过这样生成的
蓝图类
,属于虚幻C++类
的变种,在变种中可以可视化地分别设置其组件及成员的数据
- 自定义类物体拥有三种类型:
代码原型
:通过C++写成的类,需要在里面定义好其拥有的组件及其父子关系,以及定义默认参数,以及写好功能函数与所有“一般化”
功能
蓝图类
:通过C++类派生出来的预制体
类型,可以派生多个,拥有所有其C++原型对其暴露的参数与函数,拥有为其单个预制体
而服务的蓝图脚本区
(必须继承自UObject
或其派生)以及可视化三维视口区
(必须继承自AActor或其派生),拥有“特殊化”
的配置能力
实例物体
:通过代码原型
或蓝图类
在关卡中实例化出的单个物体
(必须继承自AActor
或其派生),能够在游戏进程中运行线程周期函数
🔥新建代码原型
🚩头文件介绍
GENERATED_BODY() UE默认代码
BeginPlay() 初始化函数
Tick(DeltaTime) 运行函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #pragma once
#include "CoreMinimal.h" #include "GameFramework/Actor.h"
#include "Actor_1.generated.h"
UCLASS()
class HOW2PLAYWITHUE4_1_API AActor_1 : public AActor { GENERATED_BODY() public: AActor_1();
protected: virtual void BeginPlay() override;
public: virtual void Tick(float DeltaTime) override;
};
|
🚩源文件介绍
PrimaryActorTick.bCanEverTick 是否每帧调用运行函数标识符
Super::BeginPlay() / Tick(DeltaTime) 父类初始化与运行函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include "Actor_1.h"
AActor_1::AActor_1() { PrimaryActorTick.bCanEverTick = true; }
void AActor_1::BeginPlay() { Super::BeginPlay(); }
void AActor_1::Tick(float DeltaTime) { Super::Tick(DeltaTime); }
|
🚩类命名规则
- 继承或派生自
Actor
首字母为A
,如APawn
- 继承或派生自
Object
首字母为U
,如USceneComponent
- 继承或派生自
SWidget
首字母为S
,如SButton
- 继承或派生自
Enums
首字母为E
,如EInputEvent
- 继承或派生自
Template
首字母为T
,如TArray
- 其他闲散类首字母均为
F
,如FVector
🔥参数属性说明符
🚩宏UCLASS()
1 2 3
| UCLASS() class 项目名 类名 : public 基类名{}
|
🚩宏UFUNCTION()
UFUNCTION(BlueprintCallable) 函数:蓝图可调用
1 2 3 4 5 6 7 8 9 10 11 12 13
| public: UFUNCTION() void 函数名(); UFUNCTION(BlueprintCallable) void 函数名(); UFUNCTION(BlueprintNativeEvent) void 函数名(); void 函数名_Implementation();
|
🚩宏UPROPERTY()
UPROPERTY(VisibleAnywhere) 属性:所有环境可见
UPROPERTY(EditAnywhere) 属性:所有环境可编辑
UPROPERTY(VisibleDefaultsOnly) 属性:仅蓝图类可见
UPROPERTY(EditDefaultsOnly) 属性:仅蓝图类可编辑
UPROPERTY(VisibleInstanceOnly) 属性:仅实例可见
UPROPERTY(EditInstanceOnly) 属性:仅实例可编辑
UPROPERTY(BlueprintReadOnly) 属性:蓝图类与蓝图只读
UPROPERTY(BlueprintReadWrite) 属性:蓝图类与蓝图可读写
UPROPERTY(EditAnywhere, Category=”Category_1|SubCategory”) 属性:设置组件内分栏
UPROPERTY(EditAnywhere, Meta=(Bitmask, BitmaskEnum=”EColorType”)) 属性:枚举下拉菜单
UPROPERTY(EditAnywhere, Meta=(ClampMin = -1, ClampMax = 1, UIMin = -1, UIMax = 1)) 属性:钳制数值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public: UPROPERTY(VisibleAnywhere) int32 num1 = 0; UPROPERTY(EditAnywhere) int32 num2 = 0; UPROPERTY(EditAnywhere, Category="Category_1|SubCategory") int32 num3 = 0; UPROPERTY(VisibleDefaultsOnly) int32 num4 = 0; UPROPERTY(EditDefaultsOnly) int32 num4 = 0; UPROPERTY(EditInstanceOnly) int32 num4 = 0; UPROPERTY(EditAnywhere) UStaticMeshComponent* mesh; UPROPERTY(EditAnywhere, Meta=(Bitmask, BitmaskEnum="EColorType")) EColorType color = EColorType::RED; UPROPERTY(EditAnywhere, Meta=(ClampMin = -500, ClampMax = 500, UIMin = -500, UIMax = 500)) FVector vect = FVector(0, 0, 0);
|
🔥组件
- 在虚幻里,任何可以拖入场景里的物件都是
Actor
,并且继承自AActor
类
- 组件
Component
只能依附于Actor
才能存在
Actor
都是以A开头的,Component
都是以U开头的
Actor
的方位矩阵信息记录在AActor
里的RootComponent
根组件上,默认Nullptr
🚩物体类添加组件
USceneComponent 场景组件类,是所有可放入场景的组件的基类
UStaticMeshComponent 静态网格组件类
UObject::CreateDefaultSubobject<>() 物体添加组件
RootComponent 物体的根组件
USceneComponent::SetupAttachment() 将组件作为其他组件的子集
FindComponentByClass<class …>() 通过组件类名获取物体内组件的模板类
1 2 3 4 5 6 7 8 9 10 11 12 13
| public: UPROPERTY(VisibleAnywhere, Category = "OBJScene") USceneComponent* objScene; UPROPERTY(VisibleAnywhere, Category = "MyMesh") UStaticMeshComponent* mesh1;
objScene = CreateDefaultSubobject<USceneComponent>(TEXT("objScene")); RootComponent = objScene; mesh1 = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("myMesh1")); mesh1->SetupAttachment(objScene);
|
🚩组件类
1 2 3 4 5
|
GetOwner()->SetActorLocation(0, 0, 0);
SetupAttachment(...);
|
🔥测试
🚩打印
GEngine->AddOnScreenDebugMessage()
1 2
| GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("HelloWorld!"));
|
UE_LOG()
1 2 3 4 5 6 7
| UE_LOG(LogTemp, Log, TEXT("HelloWorld")); UE_LOG(LogTemp, Warning, TEXT("HelloWorld")); UE_LOG(LogTemp, Error, TEXT("HelloWorld")); int num = 10; UE_LOG(LogTemp, Log, TEXT("HelloWorld %i"), *num);
|
🚩绘图
DrawDebugLine 画线
DrawDebugPoint 画点
DrawDebugDirectionalArrow 画箭头
DrawDebugBox/Frustum/SolidBox/SolidPlane 画方
DrawDebugSphere/Capsule/Cylinder/Cone 画球
DrawDebugCircle/2DDonut 画面
DrawDebugCoordinateSystem 画坐标系
DrawDebugString 写字
DrawDebugCamera 摄像机
DrawDebugMesh 网格
1 2
| #include "DrawDebugHelpers.h"
|
🔥基本数值类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int32 int64 float double bool TArray Set Map FVector FVector2D FRotator FQuat FTransform FColor FString FName FText
|
🔥类型转换
🚩转字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
int32 i32 = 0; int64 i64 = 0; FString s = FString::FromInt(i32); FString s = FString::FromInt(i64);
FString s = TEXT(""); int32 i = FCString::Atoi(s); int64 i = FCString::Atoi64(s);
float f = 0.0f; double d = 0.0; FString s = FString::SanitizeFloat(f); FString s = FString::SanitizeFloat(d);
FString s = TEXT(""); float f = FCString::Atof(f); double f = FCString::Atod(f);
FName n = TEXT(""); FText t = TEXT(""); FString s = n.ToString(); FString s = t.ToString();
FString s = TEXT(""); FName n = FName(*s); FText t = FText::FromString(s);
FName n = TEXT(""); FText t = FText::FromName(n);
|
🚩整型与浮点
1 2 3 4 5 6 7
|
int32 i = 0; float f = float(i);
int32 i = 0; float f = (float)i;
|
🚩保留小数
1 2 3
| float f = 3.14159; FString s = FString::SanitizeFloat(int(f * 100 + 0.5) / 100.0);
|
🔥实例化
🚩ConstructorHelpers类
ConstructorHelpers类
用于在C++中获取资源文件
FClassFinder寻找类
1 2 3 4 5 6 7 8 9 10 11 12 13
|
#include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h" TSubclassOf<AActor> actorToSpawn;
static ConstructorHelpers::FClassFinder<AActor> actorResource(TEXT("/Game/类地址_C")); if (actorResource.Succeeded()) { actorToSpawn = actorResource.Class; }
|
FObjectFinder寻找资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
#include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h" public: UPROPERTY(VisibleAnywhere) UStaticMeshComponent* mesh;
static ConstructorHelpers::FObjectFinder<UStaticMesh> meshResource(TEXT("/Game/资源地址")); if (meshResource.Succeeded()) { mesh->SetStaticMesh(meshResource.Object); }
|
🚩类实例化
UWorld 场景类
TSubclassOf<class …>() 表示UClass类型的模板类(强制选择该类下的派生)
FActorSpawnParameters 物体生成参数类型
UWorld->SpawnActor<>() 生成实例模板函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| TSubclassOf<class AActor> ActorClass; FActorSpawnParameters SpawnParams;
AActor* actor = World->SpawnActor<AActor>( ActorClass, FVector(0, 0, 0), FRotator(0, 0, 0), SpawnParams);
UPROPERTY(EditDefaultsOnly) TSubclassOf<class AActor> ActorClass;
AActor* actor = GetWorld()->SpawnActor<AActor>( TSubclassOf<class AActor>(), FVector(0, 0, 0), FRotator(0, 0, 0));
|
🔥时间
🚩游戏时间
1
| float time = GetWorld()->GetTimeSeconds();
|
🔥数学
🚩数值映射
1 2 3 4 5 6
|
inline float Mapping(float val, float min1, float max1, float min2, float max2) { return ((val - min1) * (max2 - min2) + min2 * (max1 - min1)) / (max1 - min1); }
|
🚩UE坐标轴
- 虚幻采用的是左手坐标系
- X为前方向,Y为右方向,Z为上方向
- XYZ旋转对应欧拉角为
Roll
,Pitch
,Yaw
- 在此需要强调一下:
- SceneComponent提供的Detail面板中Rotation的顺序为
Roll(X)
、Pitch(Y)
、Yaw(Z)
- 而FRotator结构体的构造方法顺序为
Pitch(Y)
、Yaw(Z)
、Roll(X)
🚩FMath类常用函数
1 2 3 4 5 6 7 8 9 10 11
| FMath::Clamp() FMath::DegreesToRadians() FMath::RadiansToDegrees() FMath::DivideAndRoundUp() FMath::GetMappedRangeValue() FMath::Lerp/LerpStable() FMath::PointDistToLine/SphereDistToLine() FMath::SmoothStep() FMath::Square/Pow() FMath::Log2/Loge/LogX() FMath::Sin/Cos/Tan/ASin/ACos/ATan()
|
🔥C++通信
🚩C++与类实例通信
- 虚幻场景中一切实例都属于类(包括C++实例和蓝图实例)
- 与静态实例通信时:
- 与动态实例通信时:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include "Kismet/GameplayStatics.h" TArray<AActor*> Actors;
UGameplayStatics::GetAllActorsWithTag( GetWorld(), TEXT("myTag"), Actors);
UGameplayStatics::GetAllActorsOfClass( GetWorld(), TSubclassOf<AActor>(), Actors);
UGameplayStatics::GetAllActorsOfClassWithTag( GetWorld(), TSubclassOf<AActor>(), TEXT("myTag"), Actors);
for (AActor* Actor: Actors) { if (Cast<APawn>(Actor)) { } }
|
🚩C++与派生蓝图类通信
1 2
| UPROPERTY(BlueprintReadWrite, Category = "Props") float myFloat;
|
1 2
| UFUNCTION(BlueprintCallable, Category = "Functions") void MyFunc();
|
- 派生蓝图类重写C++类方法(C++调用其派生蓝图类的方法)
1 2 3 4 5 6 7 8 9 10 11
| UFUNCTION(BlueprintNativeEvent, Category = "Game") void MyEventFunction(); void MyEventFunction_Implementation();
void 类名::MyEventFunction_Implementation() {}
void 类名::BeginPlay() { MyEventFunction(); }
|
🚩C++与材质通信
🚩C++蓝图脚本库
- 创建C++类继承自
UBlueprintFunctionLibrary
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| UCLASS() class PROJECTFORBLUEPRINT_API UMyBPLib : public UBlueprintFunctionLibrary { GENERATED_BODY() UFUNCTION(BlueprintCallable, Category = "Functions") static void MyBPFunction(); };
void UMyBPLib::MyBPFunction() { GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, TEXT("Hello")); }
|
🔥GamePlay基础框架
🚩游戏模式GameMode
游戏模式GameMode
用于构建实现游戏和规则
游戏模式类AGameModeBase
的作用是存储一些与游戏规则相关的配置
- 项目设置中的游戏规则用于默认,世界设置中用于重载
🚩基础游戏框架
- 游戏模式GameMode
AGameModeBase
- 游戏状态GameState
AGameStateBase
- 玩家控制器playerController
APlayerController
- 玩家相机控制器playerCameraController
APlayerCameraManager
- 玩家状态PlayerState
APlayerState
- 用户界面HUD
AHUD
- 默认玩家DefaultPawn
APawn
🚩生成体Pawn
- Pawn是所有玩家与AI生成体的基类
- DefaultPawn指默认玩家
- 默认玩家需要通过控制器进行控制,才能接收输入
🚩GameplayStatics类
1 2 3 4
| #include "Kismet/GameplayStatics.h"
APlayerController* PlayerController = UGameplayStatics::GetPlayerController(GWorld, 0);
|
🔥界面UMG
🚩界面绘制
- 通常不使用代码的方式来添加游戏UI,而是使用编辑器
UTexture2D 2D贴图类
AHUD::DrawHUD() 绘制界面函数
FCanvasItem 界面物体基类
AHUD::Canvas.DrawItem() 将界面物体绘制到界面上函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| UPROPERTY(EditDefaultsOnly) UTexture2D* tex; virtual void DrawHUD() override;
void AFPSHUD::DrawHUD() { Super::DrawHUD(); if (tex) { FVector2D Center( Canvas->ClipX * 0.5f, Canvas->ClipY * 0.5f); FVector2D Pos( Center.X - (tex->GetSurfaceWidth() * 0.5f), Center.Y - (tex->GetSurfaceHeight() * 0.5f)); FCanvasTileItem TileItem( Pos, tex->Resource, FLinearColor::White); TileItem.BlendMode = SE_BLEND_Translucent; Canvas->DrawItem(TileItem); } }
|
🚩界面装配
- 界面装配使用蓝图
- 创建
UMG可视化UI生成器
并制作UI
- 在HUD类里使用节点
BeginPlay
->CreateWidget
->AddToViewport
进行装配
🚩界面绑定
- 使用蓝图来绑定
- 在UI绑定函数节点里使用GetAllActorsOfClass->Get(0)->CastTo->获取C++暴露的成员变量或方法
🔥标签Tag
🚩标签设置
- 标签有两种:
- 设置物体Actor标签:
- 所有
场景物体Actor
自身self
都有Actor模块
,在Actor模块
最下方设置标签
- 设置组件Component标签:
- 所有
组件Component
都有Tags模块
,可以直接设置标签
🚩标签判断
1 2 3 4 5 6 7 8
| AActor* act; for (FName tag : act->Tags) { if (tag == FName(TEXT("tagged"))) { UE_LOG(LogTemp, Warning, TEXT("is tagged")); } }
|
1 2 3 4 5 6 7 8
| USceneComponent* comp; for (FName tag : comp->ComponentTags) { if (tag == FName(TEXT("tagged"))) { UE_LOG(LogTemp, Warning, TEXT("is tagged")); } }
|
🔥输入映射
- 虚幻的输入系统由
ActionMapping
和AxisMapping
组成
ActionMapping
包含所有瞬间输入
AxisMapping
包含所有持续输入
SpeechMapping
是新加的语音识别映射
- 所有输入映射需要先在项目设置里设置好,并设置缩放权衡值(Scale)
- 依此输入系统,自定义类必须继承自
APawn
类,因为需要重写的绑定函数是APawn
类成员
工程设置Project Settings
的输入Input
中的第一栏是绑定Bindings
设置
🚩绑定函数
SetupPlayerInputComponent() 玩家输入绑定函数
UInputComponent::BindAxis() 轴输入绑定函数
UInputComponent::BindAction() 动作输入绑定函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
virtual void SetupPlayerInputComponent (class UInputComponent* InputCom) override; void MoveForward(float value);
void APlayerManager::SetupPlayerInputComponent(UInputComponent* InputCom) { Super::SetupPlayerInputComponent(InputCom); InputCom->BindAxis ("MoveForward", this, &APlayerManager::MoveForward); InputCom->BindAction ("Jump", EInputEvent::IE_Pressed, this, &APlayerManager::StartJump); } void APlayerManager::MoveForward(float value) { }
|
🚩输入绑定案例
头文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #pragma once
#include "CoreMinimal.h" #include "GameFramework/Character.h" #include "PlayerManager.generated.h"
UCLASS() class TESTFORUE5_1_API APlayerManager : public ACharacter { GENERATED_BODY() public: APlayerManager(); protected: virtual void BeginPlay() override; public: virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent (class UInputComponent* PlayerInputComponent) override; UFUNCTION() void MoveForward(float Value); UFUNCTION() void MoveRight(float Value); UFUNCTION() void StartJump(); UFUNCTION() void StopJump(); };
|
源文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| #include "PlayerManager.h"
APlayerManager::APlayerManager() { PrimaryActorTick.bCanEverTick = true; } void APlayerManager::BeginPlay() { Super::BeginPlay(); } void APlayerManager::Tick(float DeltaTime) { Super::Tick(DeltaTime); }
void APlayerManager::SetupPlayerInputComponent(UInputComponent* InputCom) { Super::SetupPlayerInputComponent(InputCom); InputCom->BindAxis ("MoveForward", this, &APlayerManager::MoveForward); InputCom->BindAxis ("MoveRight", this, &APlayerManager::MoveRight); InputCom->BindAxis ("Turn", this, &APlayerManager::AddControllerYawInput); InputCom->BindAxis ("LookUp", this, &APlayerManager::AddControllerPitchInput); InputCom->BindAction ("Jump", EInputEvent::IE_Pressed, this, &APlayerManager::StartJump); InputCom->BindAction ("Jump", EInputEvent::IE_Released, this, &APlayerManager::StopJump); }
void APlayerManager::MoveForward(float Value) { FVector Direction = \ FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X); AddMovementInput(Direction, Value); } void APlayerManager::MoveRight(float Value) { FVector Direction = \ FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y); AddMovementInput(Direction, Value); }
void APlayerManager::StartJump() { bPressedJump = true; } void APlayerManager::StopJump() { bPressedJump = false; }
|
🔥事件与委托
🚩常用蓝图交互事件
1 2 3 4 5 6 7 8 9 10 11 12 13
| DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMyEvent);
public: UPROPERTY(BlueprintAssignable) FMyEvent OnMyEvent_1; UPROPERTY(BlueprintAssignable) FMyEvent OnMyEvent_2;
OnMyEvent_1.Broadcast(); OnMyEvent_2.Broadcast();
|
🔥碰撞
🚩碰撞通道
工程设置Project Settings
的碰撞Collision
中的第一栏是物体通道Object Channels
设置
- 点击
New Object Channel
来新建物体通道
- 设置物体通道默认值为
无视Ignore
,在预设中有需要的情况下再做改动
🚩物体碰撞需求
要求一:物理模拟
- 至少有一方开启
物理模拟Simulate Physics
要求二:功能开关
- 在网格组件中的
碰撞模块Collision
里进行以下设置
- 当信息接收方
碰撞事件检测Simulate Generates Hit Events
开启时,若至少一方物理模拟开启,则能接收碰撞事件
- 当必须双方
覆盖事件检测Generates Overlap Events
开启时,才能接收覆盖事件
要求三:碰撞方法
碰撞方法Collision Enabled
:
- 此方法的
产生碰撞覆盖信息
仅对于该物体自身起作用,对于其他物体无效
碰撞方法 |
产生碰撞覆盖信息 |
产生物理效果 |
无碰撞 NoCollision |
否 |
否 |
仅信息 QueryOnly |
是 |
否 |
仅物理 PhysicsOnly |
否 |
是 |
有碰撞 CollisionEnable |
是 |
是 |
要求四:通道设置
碰撞响应Collision Responses
:
- 凡一方对另一方
碰撞通道
设置无视Ignore
,则双方相互穿过,双方不发生任何响应
- 以上条为基准,凡一方对另一方
碰撞通道
设置覆盖Overlap
,则双方相互穿过,双方发生覆盖
响应
- 只有双方对对方
碰撞通道
设置碰撞Block
,则双方相互碰撞,双方发生碰撞响应
- 在
物体类型Object Type
中为该物体赋予用户自定义类型,自定义类型会出现在物体响应Object Responses
下
碰撞响应 |
B_Ignore |
B_Overlap |
B_Block |
A_Ignore |
AB_Ignore |
AB_Ignore |
AB_Ignore |
A_Overlap |
AB_Ignore |
AB_Overlap |
AB_Overlap |
A_Block |
AB_Ignore |
AB_Overlap |
AB_Block |
🚩碰撞与覆盖检测
物体,函数重写
1 2 3 4 5 6 7 8 9 10 11 12 13
| void NotifyActorBeginOverlap(AActor* Other) override;
void 自定义类名::NotifyActorBeginOverlap(AActor* Other) { Super::NotifyActorBeginOverlap(Other); if (Cast<AActor>(Other)) { UE_LOG(LogTemp, Warning, TEXT("---begin %s"), *(Other->GetName())); } }
|
- 物体Actor离开覆盖:
AActor::NotifyActorEndOverlap
1 2 3 4 5 6 7 8 9 10 11 12 13
| void NotifyActorEndOverlap(AActor* Other) override;
void 自定义类名::NotifyActorEndOverlap(AActor* Other) { Super::NotifyActorEndOverlap(Other); if (Cast<AActor>(Other)) { UE_LOG(LogTemp, Warning, TEXT("---end %s"), *(Other->GetName())); } }
|
- 物体Actor碰撞:
AActor::NotifyHit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void NotifyHit(class UPrimitiveComponent* MyComp, AActor* Other, class UPrimitiveComponent* OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit) override;
void 自定义类名::NotifyHit(UPrimitiveComponent* MyComp, AActor* Other, UPrimitiveComponent* OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit) { Super::NotifyHit(MyComp, Other, OtherComp, bSelfMoved, HitLocation, HitNormal, NormalImpulse, Hit); if (Cast<AActor>(Other)) { UE_LOG(LogTemp, Warning, TEXT("---hit %s"), *(Other->GetName())); } }
|
组件与物体,委托
- 组件Component进入覆盖:
UPrimitiveComponent::OnComponentBeginOverlap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| UFUNCTION() void BoxOverlapBegin(class UPrimitiveComponent* HitComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
void 自定义类名::BeginPlay() { FScriptDelegate dele_Begin; dele_Begin.BindUFunction(this, "BoxOverlapBegin"); boxCollision->OnComponentBeginOverlap.Add(dele_Begin); boxCollision->OnComponentBeginOverlap.AddDynamic(this, &自定义类名::BoxOverlapBegin); }
void 自定义类名::BoxOverlapBegin(class UPrimitiveComponent* HitComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { if (OtherActor == nullptr) { return; } UE_LOG(LogTemp, Warning, TEXT("---begin %s"), *OtherActor->GetName()); }
|
- 组件Component离开覆盖:
UPrimitiveComponent::OnComponentEndOverlap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| UFUNCTION() void BoxOverlapEnd(class UPrimitiveComponent* HitComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
void 自定义类名::BeginPlay() { FScriptDelegate dele_End; dele_End.BindUFunction(this, "BoxOverlapEnd"); boxCollision->OnComponentEndOverlap.Add(dele_End); boxCollision->OnComponentEndOverlap.AddDynamic(this, &自定义类名::BoxOverlapEnd); }
void 自定义类名::BoxOverlapEnd(class UPrimitiveComponent* HitComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) { if (OtherActor == nullptr) { return; } UE_LOG(LogTemp, Warning, TEXT("---end %s"), *OtherActor->GetName()); }
|
- 组件Component碰撞:
UPrimitiveComponent::OnComponentHit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| UFUNCTION() void BoxHit(class UPrimitiveComponent* HitComponent, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
void 自定义类名::BeginPlay() { FScriptDelegate dele_Hit; dele_Hit.BindUFunction(this, "BoxHit"); boxCollision->OnComponentHit.Add(dele_Hit); boxCollision->OnComponentHit.AddDynamic(this, &自定义类名::BoxHit); }
void 自定义类名::BoxHit(class UPrimitiveComponent* HitComponent, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) { if (OtherActor == nullptr) { return; } UE_LOG(LogTemp, Warning, TEXT("---hit %s"), *OtherActor->GetName()); }
|
- 物体Actor进入覆盖:
AActor::OnActorBeginOverlap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| UFUNCTION() void BoxOverlapBegin(class AActor* OverlappedActor, class AActor* OtherActor);
void 自定义类名::BeginPlay() { FScriptDelegate dele_Begin; dele_Begin.BindUFunction(this, "BoxOverlapBegin"); boxCollision->OnActorBeginOverlap.Add(dele_Begin); boxCollision->OnActorBeginOverlap.AddDynamic(this, &自定义类名::BoxOverlapBegin); }
void 自定义类名::BoxOverlapBegin(class AActor* OverlappedActor, class AActor* OtherActor) { if (OtherActor == nullptr) { return; } UE_LOG(LogTemp, Warning, TEXT("---begin %s"), *OtherActor->GetName()); }
|
- 物体Actor离开覆盖:
AActor::OnActorEndOverlap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| UFUNCTION() void BoxOverlapEnd(class AActor* OverlappedActor, class AActor* OtherActor);
void 自定义类名::BeginPlay() { FScriptDelegate dele_End; dele_End.BindUFunction(this, "BoxOverlapEnd"); boxCollision->OnActorEndOverlap.Add(dele_End); boxCollision->OnActorEndOverlap.AddDynamic(this, &自定义类名::BoxOverlapEnd); }
void 自定义类名::BoxOverlapEnd(class AActor* OverlappedActor, class AActor* OtherActor) { if (OtherActor == nullptr) { return; } UE_LOG(LogTemp, Warning, TEXT("---end %s"), *OtherActor->GetName()); }
|
- 物体Actor碰撞:
AActor::OnActorHit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| UFUNCTION() void BoxHit(class AActor* SelfActor, class AActor* OtherActor, FVector NormalImpulse, const FHitResult& Hit);
void 自定义类名::BeginPlay() { FScriptDelegate dele_Hit; dele_Hit.BindUFunction(this, "BoxHit"); boxCollision->OnActorHit.Add(dele_Hit); boxCollision->OnActorHit.AddDynamic(this, &自定义类名::BoxHit); }
void 自定义类名::BoxHit(class AActor* OverlappedActor, class AActor* OtherActor) { if (OtherActor == nullptr) { return; } UE_LOG(LogTemp, Warning, TEXT("---hit %s"), *OtherActor->GetName()); }
|
🚩鼠标进入检测
- 使用鼠标检测功能,必须设置鼠标可视和允许检测
- 在创建的玩家控制器里
鼠标接口栏MouseInterface
中设置
UPrimitiveComponent::OnBeginCursorOver
UPrimitiveComponent::OnEndCursorOver
UPrimitiveComponent::OnClicked
UPrimitiveComponent::OnReleased
UPrimitiveComponent::OnInputTouchBegin
UPrimitiveComponent::OnInputTouchEnd
UPrimitiveComponent::OnInputTouchEnter
UPrimitiveComponent::OnInputTouchLeave
🔥射线检测
🚩射线通道
工程设置Project Settings
的碰撞Collision
中的第二栏是射线通道Trace Channels
设置
- 点击
New Trace Channel
来新建射线通道
- 设置射线通道默认值为
无视Ignore
,在预设中有需要的情况下再做改动
- 射线通道与物体通道一样无法直接赋给某个网格物体,需要新建预设,将预设赋给需要被射线检测到的网格体
- 如果实在不想新建预设,也可以在物体的碰撞预设里选
自定义Custom
- 这里演示如何创建预设:在
碰撞Collision
中的第三栏预设Preset
里新建碰撞预设
- 填入
预设名称
,设置允许碰撞
,设置物体类型
- 选中该物体预设允许检测到的射线通道,将其设置为
Block碰撞
,确认新建预设
- 将需要接受射线检测的物体网格中的
碰撞预设Collision Presets
设为刚新建的预设
🚩射线参数
- 在触发射线检测行为的物体或组件中设置触发事件
- 射线通道最多有18个(ECC_GameTraceChannel1~18)
FHitResult 碰撞信息接收器
DrawDebugLine 画线测试
GetWorld()->LineTraceSingleByChannel 单线通道射线检测
GetWorld()->LineTraceSingleByObjectType 单线物体类型射线检测
GetWorld()->LineTraceSingleByProfile 单线配置文件射线检测
GetWorld()->LineTraceMultiByChannel 多线通道射线检测
GetWorld()->LineTraceMultiByObjectType 多线物体类型射线检测
GetWorld()->LineTraceMultiByProfile 多线配置文件射线检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include "DrawDebugHelpers.h"
FHitResult hit; FVector startLocation; FRotator startRotation;
GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(startLocation, startRotation);
FVector endLocation = startLocation + startRotation.Vector() * 100;
DrawDebugLine(GetWorld(), startLocation, endLocation, FColor::Blue);
GetWorld()->LineTraceSingleByChannel( hit, startLocation, endLocation, ECollisionChannel::ECC_GameTraceChannel1, FCollisionQueryParams(FName(TEXT("")), false, GetOwner()), FCollisionResponseParams(ECollisionResponse::ECR_Block)); if (hit.GetActor() != nullptr) { GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Red, TEXT("hit")); }
|