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. Vijos P1769 网络的关键边

    Description 一个连通的无向图,有些点有A属性,有些点有B属性,可以同时具有.删掉某条边后,如果使得连通块中一些点不具有A,B属性的点,求这些边. Sol Tarjan求割边. 首先这些边一 ...

  2. 转:理解Cookie和Session机制

    原文: 理解Cookie和Session机制 摘要: Cookie工作原理 由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份.怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论 ...

  3. 2016.07.09 offsetWidth 和一个问题。

    javascript 中 offsetWidth 是对象的可见宽度,包滚动条等边线,会随窗口的显示大小改变 clientWidth.offsetWidth.clientHeight区别 IE6.0.F ...

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

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

  5. iOS UILocalNotification 每2周,每两个月提醒

    iOS 的UILocalNotification提醒提供了默认的重复频率,比如,一天,一个星期等等,但是对于非标准的频率,比如每,2周,每2个月,无法重复提醒. 我们的思路是在应用程序开始时,把即将发 ...

  6. FastReport中文网

    FastReport中文网 http://www.fastreportcn.com/Article/2.html

  7. ABAP 销售范围

    *&---------------------------------------------------------------------* *& Report  ZSDR008 ...

  8. pydev导入eclipse

    编辑器:Python 自带的 IDLE 简单快捷, 学习Python或者编写小型软件的时候.非常有用. 编辑器: Eclipse + pydev插件 1. Eclipse是写JAVA的IDE, 这样就 ...

  9. 从json传递数据显示表格实例

    @interface ViewController ()<UITableViewDataSource,UITableViewDelegate> { UITableView* table; ...

  10. ASM:《X86汇编语言-从实模式到保护模式》第10章:32位x86处理器的编程架构

    ★PART1:32位的x86处理器执行方式和架构 1. 寄存器的拓展(IA-32) 从80386开始,处理器内的寄存器从16位拓展到32位,命名其实就是在前面加上e(Extend)就好了,8个通用寄存 ...