• ShooterGame 学习笔记1 PlayerPawn的两个Mesh的可见性


    GameMode Override 为 ShooterGame_TeamDeathMatch

    GameMode中设置的Default Pawn Class 为 PlayerPawn , PlayerPawn为蓝图类,其父类为ShooterGame.ShooterCharacter

    而ShooterCharacter类中做了按键绑定,一旦使用瞄准键,则会置isTargeting = true,具体这个值将会产生的动作,应该是在动画蓝图中反应的

    具体来说PlayerPawn这个蓝图类配置了相应的动画蓝图:

    可以看到这个蓝图类配置了两个动画蓝图,实际上这样的效果是打开编辑器可以看到两套手臂,至于两套手臂的可见性问题,我看配置里默认的都是可见的,单代码里有SetOwnerNoSee(bFirstPerson);这样的函数,这函数内容如下:

    void UPrimitiveComponent::SetOwnerNoSee(bool bNewOwnerNoSee)
    {
        if(bOwnerNoSee != bNewOwnerNoSee)
        {
            bOwnerNoSee = bNewOwnerNoSee;
            MarkRenderStateDirty();
        }
    }

    而bOwnerNoSee这个变量我一看定义,居然定义在PrimitiveComponent.h中,定义是这样写的,注释翻来过来就是:  如果bOwnerNoSee为True,则当观察者和物体的拥有者相同时,该component是不可见的

    /** If this is True, this component won't be visible when the view actor is the component's owner, directly or indirectly. */
        UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadOnly, Category = Rendering)
        uint32 bOwnerNoSee:1;

    实际上控制Mesh可见性的一共有两个变量,他们都出现在了构造函数中:

        //只有自己能看见
        Mesh1P->bOnlyOwnerSee = false;
        //自己看不见
        Mesh1P->bOwnerNoSee = false;

    然后构造函数的值在程序中实际上一开始就会被UpdatePawnMeshes函数覆盖,所以修改构造函数中的值并不会起到效果,以下是UpdatePawnMeshes函数的定义:

    /** handle mesh visibility and updates */
    void
    AShooterCharacter::UpdatePawnMeshes() { bool const bFirstPerson = IsFirstPerson(); Mesh1P->MeshComponentUpdateFlag = !bFirstPerson ? EMeshComponentUpdateFlag::OnlyTickPoseWhenRendered : EMeshComponentUpdateFlag::AlwaysTickPoseAndRefreshBones; Mesh1P->SetOwnerNoSee(!bFirstPerson); GetMesh()->MeshComponentUpdateFlag = bFirstPerson ? EMeshComponentUpdateFlag::OnlyTickPoseWhenRendered : EMeshComponentUpdateFlag::AlwaysTickPoseAndRefreshBones; GetMesh()->SetOwnerNoSee(bFirstPerson);
    //下面这句是我自己家的,为了测试自己预想的判断 GetMesh()
    ->SetOwnerNoSee(false); }

    那既然UpdatePawnMeshes不再构造函数中调用,那到底是什么机制保证了它的调用呢?

    1.它在这两个函数中被进行了调用,除了下面这个,还有一个死亡的时候切换到第三人称的我就略去了

    /** update mesh for first person view */
        virtual void PawnClientRestart() override;

    /** 2016.05.15 补上来的笔记,因为我发现还有一个非常重要的函数调用了UpdatePawnMeshes */
    void AShooterCharacter::PostInitializeComponents()

    并且PostInitializeComponents()这个方法我并没有发现在哪里有调用(Engine项目里面倒是有),后来我发现,AActor类里面定义了这个方法,也就是说,这个方法算是API吧,引擎来调用的

    但是这个函数又是谁调用的呢,这个方法是覆盖的父类的方法,而父类是引擎提供的类,显然是由Unreal Engine 4 来保证其调用的

    接着我又遇到了新的令我困惑的地方,

    bool const bFirstPerson = IsFirstPerson();
    bool AShooterCharacter::IsFirstPerson() const
    {
        return IsAlive() && Controller && Controller->IsLocalPlayerController();
    }
    bool AController::IsLocalPlayerController() const
    {
        return false;
    }

    看到了吗,IsLocalPlayerController()这个函数只能返回false,但是游戏运行的时候,我调试过了,bFirstPerson这个标志会赋值两次, 第二次真的就是true。我现在没搞懂这个true哪里来的。

    为什么我执着于知道它的来源(这个思路太长了,看到这里我自己都忘了),因为它决定了Mesh1P->SetOwnerNoSee(!bFirstPerson);

    Google了一下IsLocalPlayerController()这个函数存在于两个类中,一个父类一个子类(https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/GameFramework/AController/IsLocalPlayerController/index.html)

    分别是AController类和APlayerController类,他们的关系是

    class ENGINE_API APlayerController : public AController
    下面是从AShooterCharacter类开始的继承关系:
    class AShooterCharacter : public ACharacter
    class ENGINE_API ACharacter : public APawn
    class ENGINE_API APawn : public AActor, public INavAgentInterface

     所以上面这三个类中,至少应该有一个类,定义了Controller是什么,于是我在Pawn.h中找到了:

    /** Controller currently possessing this Actor */
      UPROPERTY(replicatedUsing=OnRep_Controller)
      AController* Controller;

     而这个AController中定义的IsLocalPlayerController方法总是返回false的

    bool AController::IsLocalPlayerController() const
    {
        return false;
    }

    那么我靠,返回的true是哪里来的呢

    -----------------------

    记录一下UE_LOG的使用方式以及官方文档地址:https://wiki.unrealengine.com/Logs,_Printing_Messages_To_Yourself_During_Runtime

    UE_LOG(LogTemp, Warning, TEXT("Your message: bFirstPerson %d"), bFirstPerson)

     为了调试我做了一些日志

    第一处: 在AShooterCharacter类里

    void AShooterCharacter::UpdatePawnMeshes()
    {
        bool const bFirstPerson = IsFirstPerson();
        UE_LOG(LogTemp, Warning, TEXT("Your message: bFirstPerson %d"), bFirstPerson)
        Mesh1P->MeshComponentUpdateFlag = !bFirstPerson ? EMeshComponentUpdateFlag::OnlyTickPoseWhenRendered : EMeshComponentUpdateFlag::AlwaysTickPoseAndRefreshBones;
        Mesh1P->SetOwnerNoSee(!bFirstPerson);
    
        GetMesh()->MeshComponentUpdateFlag = bFirstPerson ? EMeshComponentUpdateFlag::OnlyTickPoseWhenRendered : EMeshComponentUpdateFlag::AlwaysTickPoseAndRefreshBones;
        GetMesh()->SetOwnerNoSee(bFirstPerson);
        GetMesh()->SetOwnerNoSee(false);
    }

    第二处:也是在AShooterCharacter类里

    bool AShooterCharacter::IsFirstPerson() const
    {
        UE_LOG(LogTemp, Warning, TEXT("Your message: bool AShooterCharacter::IsFirstPerson() const"))
        return IsAlive() && Controller && Controller->IsLocalPlayerController();
    }

    但是很奇怪,运行之后日志是这样的:

    这说明大部分时候调用IsFirstPerson() 的并非void AShooterCharacter::UpdatePawnMeshes() 方法

    打了断点之后发现

    return IsAlive() && Controller && Controller->IsLocalPlayerController();

    这里的Controller,

    第一次是Controller = 0x0000000000000000 <NULL>,

    第二次是Controller = 0x000001cc0b2ed600 (Name=0x000001cbb7c2d830 "ShooterPlayerController"_6)

    好吧,现在两个思路

    1.看看还有哪些函数调用了 IsFirstPerson()

    2.看看是不是有地方替换了Controller的值

    那首先从第一点思路出发,找找找找,在ShootCharacter.cpp里,除了AShooterCharacter::UpdatePawnMeshes(),就只有这一个地方调用了IsFirstPerson(),

    那好吧,我可以在这里搞个日志输出,看看

    USkeletalMeshComponent* AShooterCharacter::GetPawnMesh() const
    {
        UE_LOG(LogTemp, Warning, TEXT("Your message: AShooterCharacter::GetPawnMesh()"))
        return IsFirstPerson() ? Mesh1P : GetMesh();
    }

    很遗憾根据日记看,也并不是这里。我想了想,这样一个一个去找IsFirstPerson()的调用关系并不科学,因为可能很多地方都调用了他。

  • 相关阅读:
    node异步转同步(循环)
    三级省市区PCASClass.js插件
    微信公众号基础总结(待更新)
    ES6详解
    webpack配置
    高性能 CSS3 动画
    github上传口令
    纯css3 实现3D轮播图
    优美的js代码,拿去玩~
    关于列举属性用点还是用【】
  • 原文地址:https://www.cnblogs.com/heben/p/5472753.html
Copyright © 2020-2023  润新知