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:;

实际上控制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()的调用关系并不科学,因为可能很多地方都调用了他。

ShooterGame 学习笔记1 PlayerPawn的两个Mesh的可见性的更多相关文章

  1. Opencv学习笔记——release和debug两个模式的运行问题

    本文为原创作品,转载请注明出处 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和http://www.cnblogs.com/xujianqing/ 作者:晨凫 ...

  2. Android学习笔记(七)两个Fragment简单跳转示例

    在前两篇博文中分别介绍了Fragment得基础和Fragment的生命周期,然而说了这么多Fragment到底怎么用呢以及我们为什么要使用Fragment?本篇博文将主要探讨这两个问题,首先说下在AP ...

  3. Labview学习笔记-条件结构的两个问题

    数组:“创建数组控件“用于连接数组 输入端:数组+元素 或数组+数组 右键创建数组控件 在连接数组项上打钩或取消,改变连接的数组维度 簇:就是C语言中的结构体 簇和数组的转换 必须保证各元素数据类型一 ...

  4. VBA二次学习笔记(2)——两个Excel表内容比较

    说明(2018-9-3 22:38:58): 1. 就是之前问同事要来的作业,有两个格式一样的Excel文件,一个是正确答案,一个是员工作答的.通过代码将两个文件进行比对,把不同之处列出来. 正文: ...

  5. SQLite3学习笔记----创建数据库的两种方式

    今天研究学习SQLite,刚开始创建数据库,就遇到了一个坑,是自己粗心了,特记录一下. 实验环境: OS:Ubuntu18.04 创建数据库名称:test.db 实验步骤: 1.检查是否已经安装了SQ ...

  6. Android学习笔记(36):Android的两种事件处理方式

    Android提供了两种事件处理的方式:基于回调的事件处理 和 基于监听的事件处理. 我们来说的easy理解一点: (1)基于回调的事件处理就是继承GUI组件,并重写该组件的事件处理方法.除了一些特定 ...

  7. python 学习笔记(二)两种方式实现第一个python程序

    在交互模式下: 如果要让Python打印出指定的文字,可以用print语句,然后把希望打印的文字用单引号或者双引号括起来,但不能混用单引号和双引号: >>> print 'hello ...

  8. OpenCV 学习笔记(0)两幅图像标定配准

    参考教程 依赖opencv扩展库,使用sifi匹配 保存配准信息 "./config/calibratedPara.yaml" #include <iostream> ...

  9. Java学习笔记(4)----Public,Protected,Package,Private修饰符可见性

    Java修饰符类型(public,protected,private,friendly) public的类.类属变量及方法,包内及包外的任何类均可以访问:protected的类.类属变量及方法,包内的 ...

随机推荐

  1. div元素抓取

    var files = $(".button").find("input[type='image']"); files.each(function() { $( ...

  2. python查找并删除相同文件-UNIQ File-script版本

    今天用wxPython做了一个GUI程序,实现查找指定目录内的相同文件,主要原理是计算文件的md5值(计算前先找出文件大小相同的文件,然后计算这些文件的md5值,而不是所有文件都计算,大大减少了md5 ...

  3. 图形化的Git

    原文:http://gitbook.liuhui998.com/6_5.html Git有不少图形化界面工具用于读取和维护仓库. 捆绑的GUI Git自带了两个使用Tcl/Tk写成的GUI程序. Gi ...

  4. Oracl各个版本的下载地址

    http://www.oracle.com/technetwork/cn/database/enterprise-edition/downloads/112010-win32soft-098630-z ...

  5. Closest Binary Search Tree Value I & II

    Closest Binary Search Tree Value Given a non-empty binary search tree and a target value, find the v ...

  6. Flatten 2D Vector

    Implement an iterator to flatten a 2d vector. For example, Given 2d vector = [ [1,2], [3], [4,5,6] ] ...

  7. We will be discontinuing the Nitrous Development Platform and Cloud IDE on November 14th, 2016.

    我表示我很难过 Nitrous We will be discontinuing the Nitrous Development Platform and Cloud IDE on November ...

  8. 方法重写和方法重载;this关键字和super关键字

    1:方法重写和方法重载的区别?方法重载能改变返回值类型吗? 方法重写: 在子类中,出现和父类中一模一样的方法声明的现象. 方法重载: 同一个类中,出现的方法名相同,参数列表不同的现象. 方法重载能改变 ...

  9. Android Broadcast 和 iOS Notification

    感觉以上2个机能有许多相似之处,作个记录,待研究!

  10. android volley http请求框架

    2015年11月6日 14:35:19 注意: 1.安卓官方的volley在google的codesource上, 在github上有他的镜像android-volley, 并解决了官方的一部分bug ...