Unreal Engine 小技巧

1.调试日志UE_LOG和打印输出GEngine->AddOnScreenDebugMessage

蓝图里的PrintString,这里可以用做

    if (GEngine)
    {
        GEngine->AddOnScreenDebugMessage(-1,200,FColor(23,233,4,255), OtherActor->GetName());
    }

如果要输出Log,可以用

UE_LOG(LogTemp, Warning, TEXT("Your message"));

参考更多: 如何使用UE_LOG


2.抓取PlayerState, 此处的PlayerState是 AFPSShooterPlayerState
    if (GEngine)
    {
        AFPSShooterPlayerState* curState = Cast<AFPSShooterPlayerState>(PlayerState);
        if (curState)
        {
            int a = curState->GetGold();
            GEngine->AddOnScreenDebugMessage(1, 1,FColor::Red,FString::FromInt(a));
        }
    }

参考更多: How to access custom PlayerState inside Character

参考更多: 如何配置android的adb环境变量


4.VR模式下镜像显示适配,重点看mode3和mode4
if (WindowMirrorMode == 1)
        {// Native mode: single eye
            // need to clear when rendering only one eye since the borders won't be touched by the DrawRect below
            RHICmdList.ClearColorTexture(BackBuffer, FLinearColor::Black, FIntRect());
            RendererModule->DrawRectangle(
                RHICmdList,
                ViewportWidth / 4, 0,
                ViewportWidth / 2, ViewportHeight,
                0.1f, 0.2f,
                0.3f, 0.6f,
                FIntPoint(ViewportWidth, ViewportHeight),
                FIntPoint(1, 1),
                *VertexShader,
                EDRF_Default);
        }
        else if (WindowMirrorMode == 2)
        {// Native mode: stereo
            RendererModule->DrawRectangle(
                RHICmdList,
                0, 0,
                ViewportWidth, ViewportHeight,
                0.0f, 0.0f,
                1.0f, 1.0f,
                FIntPoint(ViewportWidth, ViewportHeight),
                FIntPoint(1, 1),
                *VertexShader,
                EDRF_Default);
        }
        else if (WindowMirrorMode == 3)
        {// Self-defined Horizontal
            RendererModule->DrawRectangle(
                RHICmdList,
                0, 0,
                ViewportWidth, ViewportHeight,
                0.006f, 0.2825f,
                0.44f, 0.4425f,
                FIntPoint(ViewportWidth, ViewportHeight),
                FIntPoint(1, 1),
                *VertexShader,
                EDRF_Default);
        }
        else if (WindowMirrorMode == 4)
        {// Self-defined Vertical
            RendererModule->DrawRectangle(
                RHICmdList,
                0, 0,
                ViewportWidth, ViewportHeight,
                0.1f, 0.2f,
                0.3f, 0.6f,
                FIntPoint(ViewportWidth, ViewportHeight),
                FIntPoint(1, 1),
                *VertexShader,
                EDRF_Default);
        }

对应的配置文件修改位置
project folder -> Saved -> Config -> Windows -> Engine.ini
Change:
[SteamVR.Settings]
WindowMirrorMode=0 // 0可以换为1-4的整数
[补全 - 针对 Oculus CV1 和 HTC Vive的优化]
Vive用了以上代码以后,建议在Console里面用命令 “hmd mirror 3” 和 “hmd mirror 4”调用上述代码的修改结果;
Oculus需要使用 “hmd mirror mode 3”和“hmd mirror mode 4”达到某种神奇的效果。
参考更多: UE4 + HTC Vive Fullscreen VR Tutorial


5.用代码实现一次Timeline
代码实现这个功能

官方4.15编辑器,继承Actor Component便于添加到Actor中重用。代码如下,经测试可以使用。

//头文件
#include "Components/ActorComponent.h"
#include "Components/TimelineComponent.h"// for MyTimeline
#include "MyTimelineComp.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class MYLEARNING415_API UMyTimelineComp : public UActorComponent
{
    GENERATED_BODY()
public: 
    // Sets default values for this component's properties
    UMyTimelineComp();

protected:
    // Called when the game starts
    virtual void BeginPlay() override;
    
    FTimeline* MyTimeline;
    UCurveFloat* fCurve;
    UCurveVector* vCurve;

    /** Update时的float回调的函数变量 */
    FOnTimelineFloat MyTimelineFloatFunction;

    /** Update时的vector回调的函数变量 */
    FOnTimelineVector MyTimelineVectorFunction;

    /** Finish时回调的函数变量 */
    FOnTimelineEvent MyTimelineFinishedFunc;

    /** Update时的float回调的函数 */
    UFUNCTION()
    void TimelineFloatReturn(float value);

    /** Update时的vector回调的函数 */
    UFUNCTION()
    void TimelineVectorReturn(FVector vector);

    /** Finish时回调的函数 */
    UFUNCTION()
    void TimelineFinished();
public: 
    /** 启动这个方法 */
    void StartTimeline();

    // Called every frame
    virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
};
//实现文件,启动方法是 void UMyTimelineComp::StartTimeline()
#include "MyLearning415.h"
#include "Engine.h"
#include "MyTimelineComp.h"


// Sets default values for this component's properties
UMyTimelineComp::UMyTimelineComp()
{
    //确保更新方法能运行
    //更新方法: void UMyTimelineComp::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
    PrimaryComponentTick.bCanEverTick = true;

    //从Content Browers中获取curve float
    static ConstructorHelpers::FObjectFinder<UCurveFloat> CurveFloat(TEXT("CurveFloat'/Game/Misc/FC_Timeline.FC_Timeline'"));
    if (CurveFloat.Object) {
        fCurve = CurveFloat.Object;
    }

    //从Content Browers中获取curve vector
    static ConstructorHelpers::FObjectFinder<UCurveVector> CurveVector(TEXT("CurveVector'/Game/Misc/VC_Timeline.VC_Timeline'"));
    if (CurveVector.Object) {
        vCurve = CurveVector.Object;
    }

    //构造Timeline,并且设定时间长度
    MyTimeline = new FTimeline();
    MyTimeline->SetTimelineLength(1.0f);

    //绑定Update时的float回调的函数
    MyTimelineFloatFunction.BindUFunction(this, "TimelineFloatReturn");
    MyTimeline->AddInterpFloat(fCurve, MyTimelineFloatFunction);

    //绑定Update时的vector回调的函数
    MyTimelineVectorFunction.BindUFunction(this, "TimelineVectorReturn");
    MyTimeline->AddInterpVector(vCurve, MyTimelineVectorFunction);

    //绑定Finish时回调的函数
    MyTimelineFinishedFunc.BindUFunction(this, "TimelineFinished");
    MyTimeline->SetTimelineFinishedFunc(MyTimelineFinishedFunc);
}


// Called when the game starts
void UMyTimelineComp::BeginPlay()
{
    Super::BeginPlay();

}


void UMyTimelineComp::TimelineFloatReturn(float value)
{// 随Timeline每帧返回float
    GEngine->AddOnScreenDebugMessage(-3, 1, FColor::Cyan, FString::SanitizeFloat(value));
}

void UMyTimelineComp::TimelineVectorReturn(FVector vector)
{// 随Timeline每帧返回vector
    GEngine->AddOnScreenDebugMessage(-2, 1, FColor::Red, vector.ToString());
}

void UMyTimelineComp::TimelineFinished()
{// Timeline结束的时候调用
    GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Green, TEXT("Finished"));
}

void UMyTimelineComp::StartTimeline()
{// 这次我们用的方法是从头播放。
    if (MyTimeline != nullptr) {
        GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Green, TEXT("Started"));
        MyTimeline->PlayFromStart();
    }
}

// Called every frame
void UMyTimelineComp::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

    GEngine->AddOnScreenDebugMessage(0, 1, FColor::Yellow, TEXT("Tick"));

    if (MyTimeline != nullptr && MyTimeline->IsPlaying())
    {//每一帧更新这个Timeline
        MyTimeline->TickTimeline(DeltaTime);
    }
}

参考文章: [Unreal Engine : Timeline を C++ コードで作成・実行する]

6. 同步玩家的转向

方法一: 使用Pawn.h中的变量RemoteViewPitch同步玩家的Pitch

    // pawn.h
    /** Replicated so we can see where remote clients are looking. */
    UPROPERTY(replicated)
    uint8 RemoteViewPitch;
    // pawn.cpp
void APawn::SetRemoteViewPitch(float NewRemoteViewPitch)
{
    // Compress pitch to 1 byte
    NewRemoteViewPitch = FRotator::ClampAxis(NewRemoteViewPitch);
    RemoteViewPitch = (uint8)(NewRemoteViewPitch * 255.f/360.f);
}   
    // MyCharacter.cpp, the implementation
void MyCharacter::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    if (!IsLocallyControlled())
    {
        FRotator NewRot = CameraComponent->RelativeRotation;
        NewRot.Pitch = RemoteViewPitch * 360.0f / 255.0;

        CameraComponent->SetRelativeRotation(NewRot);
    }
    
}
7. 重定向人形动画骨骼

项目中使用的人形骨骼,有可能和Mannequin骨骼不一样;但是,我们从市场上买来人形的动作都是Mannequin骨骼的。下面,简单说下怎么导入Mannequin骨骼(Mannequin骨骼)的动作给项目中使用的骨骼(自定义骨骼)。


左边为Mannequin骨骼,右图为自定义骨骼.png
  1. 首先检查“骨骼编辑器”中的Regtarget Manager的设定是否对应正确。这个需要分别检查Mannequin骨骼和自定义骨骼的设定。


    检查并设定Target内容.png
  2. 在“骨骼编辑器”中,调整Mannequin骨骼至T-pose


    调整Mannequin骨骼至T-pose.png
  3. 在“骨骼编辑器”中,修改Mannequin骨骼Pose。注:修改后,按下“Hide Pose”按钮,姿势将复原;再次按下就又成了T-pose,请保持姿势为T-pose(其实这个T-pose不太标准)


    修改Mannequin骨骼Pose.png
  4. 重定向人形动画骨骼,即导入动作。注:可多选


    选中动作,准备重定向

    重定向动画骨骼,注意两个骨骼都是T-pose

参考视频: [Skeleton Assets: Anim Retargeting Different Skeletons | 03 | v4.8 Tutorial Series | Unreal Engine]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • 个人学习批处理的初衷来源于实际工作;在某个迭代版本有个BS(安卓手游模拟器)大需求,从而在测试过程中就重复涉及到...
    Luckykailiu阅读 4,702评论 0 11
  • 1 她只比他大三岁,她的爹娘都是极其普通但却勤劳质朴的标准式乡下人,整日里面朝黄土背朝天的劳作着。因出身贫寒,不识...
    我有一个梦想1025阅读 654评论 1 1
  • 昨日烟雨潆潆纷雪霰 双影立湖畔 成对倒影 令鱼羡 今朝春光乍暖韶光存 此后共携手 步入殿堂 后白头 201...
    沐芓阅读 317评论 0 2
  • 命运总是爱作弄人,就像失去的美好。有时很遥远,有时却很近很近。 这一跃墨无痕将开始前所未有,前所未见的第二次生活。...
    仙九天阅读 652评论 1 3
  • 我拥有的只有现在的生活,所以我绝不讨厌我现在拥有的一切。要么就喜欢现在的自己,要么就去变成喜欢的自己。 不需要安慰...
    若澤阅读 206评论 4 3