案例中需注意的地方.个人笔记

VS错误编码

1.error C4002        宏引用过多,应该是宏里的语法错误

2.error C4458        重命名问题

3.error C2664        ConstructorHelpers里一定要引用模板的头文件

4.error C2143: 语法错误: 缺少“;”(在“*”的前面)
   error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int
   error C2238: 意外的标记位于“;”之前

       头文件互相引用的问题

如何加UE中的模块

在VS中项目里的.build.cs中

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });

这一行的“InputCore”里后面加你想要的UE引擎中自带的模块,例如"Paper2D"

Flipbook

凡是加了Component的都是为资源添加在场景中渲染的能力,否则看不见

UPaperSprite是单帧的精灵,是静止的平面物体的平面资源

UPaperSpriteComponent是渲染单帧精灵的组件

为UPaperSpriteComponent类型的指针->setsprite();

UPaperFlipbook翻译成快速翻书,是多帧的精灵形成的动画资源

UPaperFlipbookComponent是渲染多帧的精灵形成的动画资源的组件

为UPaperFlipbookComponent类型的指针->setflipbook();

碰撞组件

UBoxComponent盒体碰撞

USphereComponent圆形碰撞

UCapsuleComponent胶囊体碰撞

源码中的参数

Outer帮助我们进行搜索范围锁定,可以填入同目录资源,如不存在填入空

getworld()注意的地方

GetWorld是UWorld世界对象指针。对于每一个在场景中存在的对象,本身都具备获取UWorld指针的能力,我们只需要调用GetWorld函数即可获得UWorld对象指针

https://blog.csdn.net/yekong1225/article/details/120236717

VS中设置项目GamoMode的默认参数

在GameMode.h文件中写一个此GameMode的构造参数,定义中写Default啥啥对应上就好

注意:写的构造参数为        A文件名GameModeBase()

定义中的例子:

//已构建一个Pawn类为APawn,设置其为默认Pawn类

DefaultPawnClass = APawn::StaticClass();       

HUDClass=AHUD::StaticClass();        //设置AHUD为默认HUD

构建类中的组件或某个对象

引入组件名.h后

U组件名* 名字=CreateDefaultSubobject<组件名>(TEXT("命个名"));      //只能在构造函数中调用

一启动就崩溃检查所有类的构造函数里有没有空指针,编译完了再启动

不能在Gamemode的构造函数里写getworld()->spawnactor,因为Gamemode先生成

U组件名* 名字=NewObject<U组件名>(this);

【UE4】UE4中对象的创建和销毁 - 多思考多实践同等重要 - 博客园 (cnblogs.com)

设置根组件

在需要设置根组件的构造函数里

RootComponent=CreateDefaultSubobject<USceneComponent>(TEXT("RootComp"));

附加到根组件

在需要设置根组件的构造函数里

name->SetupAttachment(RootComponent);        //name是一个组件的对象指针的实例名称

摄像机相关

//构建相机

//弹簧吊臂
USpringArmComponent* ArmComp = CreateDefaultSubobject <USpringArmComponent>(TEXT("ArmComp"));
ArmComp->SetupAttachment(RootComponent);

//构建相机
UCameraComponent* MainCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("MainCamera"));
MainCamera->SetupAttachment(ArmComp);
MainCamera->ProjectionMode = ECameraProjectionMode::Orthographic;    //摄像机投射模式设置为正交模式
MainCamera->OrthoWidth = 800;    //相机视口大小

//调整相机吊臂旋转
ArmComp->SetRelativeRotation(FRotator(0, -90, 0));    //旋转相机
ArmComp->bDoCollisionTest = false;            //关闭摄像机吊臂的碰撞检测

//将相机的锁定权限设置到当前的Actor上,如果Actor上存在相机,则被激活

APlayerController* Pc = GetWorld()->GetFirstPlayerController();        //获取玩家0控制器
Pc->SetViewTarget(this); 

 //将屏幕坐标转为世界坐标

APlayerController* Pc = GetWorld()->GetFirstPlayerController();
    if (!Pc)
    {
        return;
    }
FVector Loc;
FVector Dir;
Pc->DeprojectScreenPositionToWorld(你想要获取的屏幕X轴值.f, 你想要获取的屏幕Y轴值.f, Loc, Dir);          //将屏幕坐标转换为3D坐标,这样可以获取屏幕边缘的位置以进行操作,如设置空气墙,屏幕左上角屏幕X,Y值为0,0

转换到        //CastTo的安全检查

相当于蓝图中的cast to 某某类

A某某类名* 名字 = Cast<A某某类名>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));

character类型上的一些自带函数

Jumping();

StopJumping();

GetVelocity().Size2D()        //获取2D角色的速率

VS中的实现        ConstructionScript蓝图构造函数

重写父类中的以下虚函数

virtual void OnConstruction(const FTransform& Transform) override;

在函数中记得写

Super::OnConstruction(Transform);

这用来干嘛?

BeginPlay是在游戏运行时才开始调用,而ConstructionScript在对象在编辑器中被实例化时就会被调用一次,C++中重写上述的虚函数即可实现其调用,目的是为了显式地调整某些属性,不用每次都运行后才能调整

碰撞的第一步:类AAA里写碰撞事件函数

!!!头文件函数前面一定要记得加UFUNCTION(),否则无法调用

这个函数的定义中写碰撞后会发生什么,碰撞事件函数的格式如下

在Engine源码的PrimitiveComponent.h文件里有定义

void OnComponentHitEvent(UPrimitiveComponent* HitComponent,AActor* OtherActor,UPrimitiveComponent* OtherComp,FVector NormalImpulse,const FHitResult& Hit);

void OnComponentBeginOverlapEvent(UPrimitiveComponent* OverlappedComponent,AActor* OtherActor,UPrimitiveComponent* OtherComp,int32 OtherBodyIndex,bool bFromSweep,const FHitResult& SweepResult);

void OnComponentEndOverlapEvent(UPrimitiveComponent* OverlappedComponent,AActor* OtherActor,UPrimitiveComponent* OtherComp,int32 OtherBodyIndex);

碰撞的第二步:在你需要撞上的物体上设置

SphereCollision->OnComponentBeginOverlap.AddDynamic(this, &ABullerActor::OnComponentBeginOverlapEvent);

//为某个组件在beginplay里绑定撞击时的回调事件,这个事件就是上面写的函数,然后开启物理通知,设置碰撞类型

某个组件->OnComponentHit.AddDynamic(this, &类AAA::OnComponentHitEvent); 
某个组件->GetBodyInstance()->bNotifyRigidBodyCollision = true;    //开启物理通知
某个组件->SetCollisionObjectType(ECC_某种预设类型);    //设置碰撞类型

某个组件->SetCollisionProfileName(TEXT("OverlapAll"));        //以碰撞文件格式设置碰撞类型

碰撞的网上的讲解例子:

https://blog.51cto.com/u_15458423/4807921

球形碰撞多目标的检测例子

FCollisionShape Shape;
Shape.ShapeType = ECollisionShape::Sphere;
Shape.Sphere.Radius = 300;
TArray<FHitResult> Hits;
if (OwnerComp.GetAIOwner()->GetWorld()->SweepMultiByChannel(Hits, RabbitPos, RabbitPos, FQuat(0, 0, 0, 0), ECC_Camera, Shape))

{

        for (auto Hit : Hits)

        {

        写球形检测逻辑的地方 

        }

}

设置物理锁定

不要产生除了我们想要的运动关系外的关系——例如排除XY位移,旋转
    FBodyInstance* Body = FlipBookComp->GetBodyInstance();
    if (Body)
    {
        Body->bLockXRotation = true;
        Body->bLockZRotation = true;

        Body->bLockXTranslation = true;
        Body->bLockYTranslation = true;

        Body->CreateDOFLock();    //不调用创建锁定,锁定无效
    }

加载一个资源

首先要知道资源需要组件才能渲染到游戏中,静态网格体需要静态网格体组件,骨骼网格体需要骨骼网格体组件,组件一般又需要依附关系,所以从上至下应该是由对象的依附关系到各个组件到设置各个组件的资源

读取资源到内存

在构造函数中使用,如果只需要构建一次资源那么前面加static

ConstructorHelpers::FObjectFinder<U资源类型名称> 起个名字(TEXT("资源引用地址"));

在其他地方中加载资源

资源类型* 资源名称=LoadObject<U资源类型名称>(nullptr, TEXT("资源引用地址"));

将资源设置到组件中

组件类型* 组件名称.Set组件类型(资源);

绑定输入事件

//在BeginPlay函数里可以直接写

PlayerInputComponent->BindAction(TEXT("你在UE4里加的操作的绑定的名字"), IE_Pressed, this, &绑定触发哪个函数);

AddMovementInput(FVector(Value, 0, 0));        //添加角色移动的输入轴值

动态设置摇杆

在PlayerController中ActivateTouchInterface函数可以设置摇杆资源

SetVirtualJoystickVisibility中可以设置隐藏或是显式摇杆

摇杆中image1为摇杆,image2为底图

VS中的存档

虚幻中使用的是对象类序列化的特性将属性信息序列化到磁盘中

构建一个USaveGame类,然后在头文件里面写东西

public域里写成员属性,记得加UPROPERTY()

不要尝试存地址,地址存了没有用,每次打开都是不一样的

只能存基本数据类型,自定义数据类型要转成基本数据类型

APlayerController* Pc = GetWorld()->GetFirstPlayerController();
    if (!Pc)
    {
        return;
    }

    if (Pc->WasInputKeyJustPressed(EKeys::Q))
    {
        //按Q构建存储数据类
        USnakeSaveGame* SaveGame = Cast<USnakeSaveGame>(UGameplayStatics::CreateSaveGameObject(USnakeSaveGame::StaticClass()));    //构建一个存档文件对象
        if (SaveGame)
        {
            SaveGame->Num = 110;
            SaveGame->Name = TEXT("OK");

            //进行存储
            UGameplayStatics::SaveGameToSlot(SaveGame, TEXT("Snake"), 0);    //第一个存档数据对象 第二个存档名称 第三个存档位置
        }
    }
    if (Pc->WasInputKeyJustPressed(EKeys::E))
    {
        USnakeSaveGame* LoadGame = Cast<USnakeSaveGame>(UGameplayStatics::LoadGameFromSlot(TEXT("Snake"), 0));    //第一个存档名称,第二个存档位置
        if (LoadGame)
        {
            UE_LOG(LogTemp, Log, TEXT("%d"),LoadGame->Num);
            UE_LOG(LogTemp, Log, TEXT("%s"), *LoadGame->Name);
        }

    }

虚函数重写

所有的虚函数重写的定义里都加上Super::函数名();,否则可能会出错

//调用的是GENERATE_BODY里的,是调用其父类的这个函数

绑定定时器

FTimerHandle Handle;        //先创建一个定时器的句柄,句柄可以拿来重置定时器
GetWorld()->GetTimerManager().SetTimer(Handle, this, &ABullerActor::TimeOutCallBack, 0.3f);

//延迟0.3秒后调用TimeOutCallBack事件

曲线超出时间的检查和值的调用

头文件中:

UPROPERTY()
class UCurveFloat* AnimCurve;

float AnimTime;

源文件中:

Anim Time+=DeltaTime;        //AnimTmie为0,为时间加上每帧调用次数

float Value = AnimCurve->GetFloatValue(AnimTime);        //获取曲线在该时间的曲线值,拿来调用

检查:

float MaxTime=0;

float MinTime=0;

AnimCurve->GetTimeRange(MinTime, MaxTime);        //获取曲线点的最小时间值和最大时间值

if (AnimTime>=MaxTime)
{
    写你要用曲线结束来做什么事的事件
}
 

HUD

绘制文字

方法1:在DrawHUD()里,        //virtual DrawHUD() override;

DrawText(TEXT("啊哈"), FLinearColor::Blue, 200, 200,Font,5,false);

方法2:用Canvas写            //屏幕宽度Canvas->ClipX;    //屏幕高度Canvas->ClipY;

FText msg = NSLOCTEXT("UE4", "k1", "OK");

Canvas->SetDrawColor(FColor::Red);

Canvas->DrawText(Font, msg, 200, 100);

不失真的文字绘制:还有和之前的对比

Slate需要在.build.cs中引用模块"Slate", "SlateCore"

//绘制文字
    if (Font)
    {
        DrawText(TEXT("啊哈"), FLinearColor::Blue, 200, 200,Font,5,false);
        FText msg = NSLOCTEXT("UE4", "k1", "哦呼");
        Canvas->SetDrawColor(FColor::Red);
        Canvas->DrawText(Font, msg, 200, 100,5,5);

        FSlateFontInfo Info(Font, 50, "Default");    //构建字体信息
        FCanvasTextItem Item(FVector2D(200, 300), msg, Info, FLinearColor::Green);    //构建canvas字体绘制item
        Canvas->DrawItem(Item);    //绘制不失真的文字
    }

绘制图片

if (Texture)
    {
        //DrawTextureSimple(Texture, 0, 0);
        DrawTexture(Texture, 0, 0, 300, 300, 0, 0, 1, 1);
    }

绘制材质球

void AHUD::DrawMaterial(UMaterialInterface* Material, float ScreenX, float ScreenY, float ScreenW, float ScreenH, float MaterialU, float MaterialV, float MaterialUWidth, float MaterialVHeight, float Scale, bool bScalePosition, float Rotation, FVector2D RotPivot)

绘制线

void AHUD::DrawLine(float StartScreenX, float StartScreenY, float EndScreenX, float EndScreenY, FLinearColor LineColor, float LineThickness)
 

void AHUD::Draw3DLine(FVector Start, FVector End, FColor LineColor)


绘制矩形

void AHUD::DrawRect(FLinearColor Color, float ScreenX, float ScreenY, float Width, float Height)

绘制线框

FCanvasBoxItem Item(FVector2D(0, 0), FVector2D(300, 300));
Item.SetColor(FLinearColor::Green);
Canvas->DrawItem(Item);

通过playercontroller获取键盘的输入事件、鼠标位置(产品中的控制键盘不要用这种方式,用设置里写)

先在beginplay里

pPlayerController = GetWorld()->GetFirstPlayerController();

然后Tick类型调用里

    if (pPlayerController->WasInputKeyJustPressed(EKeys::Q))
    {
        UE_LOG(LogTemp, Log, TEXT("DD"));
    }
    if (pPlayerController->WasInputKeyJustPressed(EKeys::RightMouseButton))
    {
        float MouseX = 0;
        float MouseY = 0;
        pPlayerController->bShowMouseCursor = true;
        pPlayerController->GetMousePosition(MouseX, MouseY);
        UE_LOG(LogTemp, Log, TEXT("%f,%f"),MouseX,MouseY);
    }

HUD命中框事件

HUD中为什么定义里要写Super::DrawHUD()

因为DrawHUD函数是每帧调用,所以比如添加命中框为什么不会一直加?因为写了Super::DrawHUD()就会调用下面的这个函数,其中,这里的Super是指调用父类的HUD里的DrawHUD(),也就是下面这个函数,其他函数定义里要不要加Super看你自己

void AHUD::DrawHUD()
{
    HitBoxMap.Reset();
    HitBoxHits.Reset();
    if (bShowOverlays && (PlayerOwner != nullptr))
    {
        FVector ViewPoint;
        FRotator ViewRotation;
        PlayerOwner->GetPlayerViewPoint(ViewPoint, ViewRotation);
        DrawActorOverlays(ViewPoint, ViewRotation);
    }

    // Blueprint draw
    ReceiveDrawHUD(Canvas->SizeX, Canvas->SizeY);
}

源码中的命中框事件

    void ReceiveHitBoxClick(const FName BoxName);

    virtual void NotifyHitBoxClick(FName BoxName);

    void ReceiveHitBoxRelease(const FName BoxName);

    virtual void NotifyHitBoxRelease(FName BoxName);

    void ReceiveHitBoxBeginCursorOver(const FName BoxName);

    virtual void NotifyHitBoxBeginCursorOver(FName BoxName);

    void ReceiveHitBoxEndCursorOver(const FName BoxName);

    virtual void NotifyHitBoxEndCursorOver(FName BoxName);
 

要使用的话必须先调用playercontroller里的bEnableClickEvents=true;

响应虚幻中设置的事件

EnableInput(APlayerController* PlayerController);

InputComponent->BindAction(TEXT("UE中操作事件的名称"),IE_Pressed,this,&A此类中::InputEventName);

导航模块

1.cs文件中添加以下模块

"NavigationSystem"

2.头文件引入"NavigationSystem.h"

3.相关API

UNavigationSystemV1::K2_GetRandomLocationInNavigableRadius(OwnerComp.GetAIOwner()->GetWorld(), OriginPos//黑板中的一个坐标信息, RandomLoc//声明一个随机坐标以存储变量, RandomRadius//随机的半径);

//以前版本用K2_GetRandomPointInNavigableRadius,现在要改

AIController

引擎版本4.22前可以重写Possess函数,现在都是重写OnPossess函数和OnUnPossess函数,如果行为树不激活,则看看是否是AI蓝图里的设置错误(1.AIController要用新建的AIController蓝图类不是C++类        2.以放置在场景中或已生成)

行为树

在OnPossess函数定义里

行为树组件.StartTree()

在OnUnPossess函数定义里

行为树组件.StopTree()

动画通知

帧通知重写这个函数

virtual void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;

状态通知重写以下三个函数

virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration) override;

    virtual void NotifyTick(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float FrameDeltaTime) override;

    virtual void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;

动画蓝图

重写以下函数,这些都可以在动画蓝图事件重载里找到

virtual void NativeUpdateAnimation(float DeltaTime) override;

virtual void NativeBeginPlay()override;

状态机里设置的响应动画通知的事件

UFUNCTION()        //别忘了
    void AnimNotify_ReloadOver();

CameraManager摄像机管理员

重写以下函数

virtual void UpdateCamera(float DeltaTime) override;

小技巧

//平滑过渡使用的函数,类似带时间轴的Lerp,第一个为输入值,需要调整的变量,第二个为想要变成的,第三个,第四个类似速度

FMath::FInterpTo(CurrentCameraPosOffsetZ, 0, DeltaTime, 10);

//摄像机拉远拉近

TargetFOV

HUD

自己去翻看前面的 记不清了

猜你喜欢

转载自blog.csdn.net/hoppingg/article/details/126706440