之前一直没搞懂按下鼠标左键开火之后,代码的逻辑是怎么走的,今天看懂了之前没看懂的部分,进了一步

ShooterCharacter.cpp

void AShooterCharacter::OnStartFire()
{
AShooterPlayerController* MyPC = Cast<AShooterPlayerController>(Controller);
if (MyPC && MyPC->IsGameInputAllowed())
{
if (IsRunning())
{
SetRunning(false, false);
}
StartWeaponFire();
}
}
void AShooterCharacter::StartWeaponFire()
{
if (!bWantsToFire)
{
bWantsToFire = true;
if (CurrentWeapon)
{
CurrentWeapon->StartFire();
}
}
}

ShooterWeapon.cpp,其中Role==ROLE_Authority表示该程序运行在服务器。如果是客户端,则将调用ServerStartFire来调用服务端的StartFire方法。这是多人游戏中的机制

void AShooterWeapon::StartFire()
{
if (Role < ROLE_Authority)
{
ServerStartFire();
} if (!bWantsToFire)
{
bWantsToFire = true;
DetermineWeaponState();
}
}
void AShooterWeapon::DetermineWeaponState()
{
EWeaponState::Type NewState = EWeaponState::Idle; if (bIsEquipped)
{
if( bPendingReload )
{
if( CanReload() == false )
{
NewState = CurrentState;
}
else
{
NewState = EWeaponState::Reloading;
}
}
else if ( (bPendingReload == false ) && ( bWantsToFire == true ) && ( CanFire() == true ))
{
NewState = EWeaponState::Firing;
}
}
else if (bPendingEquip)
{
NewState = EWeaponState::Equipping;
} SetWeaponState(NewState);
}
void AShooterWeapon::SetWeaponState(EWeaponState::Type NewState)
{
const EWeaponState::Type PrevState = CurrentState; if (PrevState == EWeaponState::Firing && NewState != EWeaponState::Firing)
{
OnBurstFinished();
} CurrentState = NewState; if (PrevState != EWeaponState::Firing && NewState == EWeaponState::Firing)
{
OnBurstStarted();
}
}
void AShooterWeapon::OnBurstStarted()
{
// start firing, can be delayed to satisfy TimeBetweenShots
const float GameTime = GetWorld()->GetTimeSeconds();
if (LastFireTime > && WeaponConfig.TimeBetweenShots > 0.0f &&
LastFireTime + WeaponConfig.TimeBetweenShots > GameTime)
{
GetWorldTimerManager().SetTimer(TimerHandle_HandleFiring, this, &AShooterWeapon::HandleFiring, LastFireTime + WeaponConfig.TimeBetweenShots - GameTime, false);
}
else
{
HandleFiring();
}
}

下面标红的FireWeapon这个函数,实际上在AShooterWeapon中是一个虚函数,并且没有实现,实现是放在了子类中。它有两个子类,分别是AShooterWeapon_Instant(弹道类)和AShooterWeapon_Projectile(投掷类)

我觉得肯定真正使用到的类就是这两个子类,所以包括之前的这个流程,实际上都是子类中的,只不过是从父类中继承而已,当然我此时此刻没有去深究那些方法的可见性修饰符,是否会被继承这些细节问题,我先暂时这么认为吧

void AShooterWeapon::HandleFiring()
{
if ((CurrentAmmoInClip > || HasInfiniteClip() || HasInfiniteAmmo()) && CanFire())
{
if (GetNetMode() != NM_DedicatedServer)
{
SimulateWeaponFire();
} if (MyPawn && MyPawn->IsLocallyControlled())
{
FireWeapon(); UseAmmo(); // update firing FX on remote clients if function was called on server
BurstCounter++;
}
}
else if (CanReload())
{
StartReload();
}
else if (MyPawn && MyPawn->IsLocallyControlled())
{
if (GetCurrentAmmo() == && !bRefiring)
{
PlayWeaponSound(OutOfAmmoSound);
AShooterPlayerController* MyPC = Cast<AShooterPlayerController>(MyPawn->Controller);
AShooterHUD* MyHUD = MyPC ? Cast<AShooterHUD>(MyPC->GetHUD()) : NULL;
if (MyHUD)
{
MyHUD->NotifyOutOfAmmo();
}
} // stop weapon fire FX, but stay in Firing state
if (BurstCounter > )
{
OnBurstFinished();
}
} if (MyPawn && MyPawn->IsLocallyControlled())
{
// local client will notify server
if (Role < ROLE_Authority)
{
ServerHandleFiring();
} // reload after firing last round
if (CurrentAmmoInClip <= && CanReload())
{
StartReload();
} // setup refire timer
bRefiring = (CurrentState == EWeaponState::Firing && WeaponConfig.TimeBetweenShots > 0.0f);
if (bRefiring)
{
GetWorldTimerManager().SetTimer(TimerHandle_HandleFiring, this, &AShooterWeapon::HandleFiring, WeaponConfig.TimeBetweenShots, false);
}
} LastFireTime = GetWorld()->GetTimeSeconds();
}
void AShooterWeapon_Instant::FireWeapon()
{
const int32 RandomSeed = FMath::Rand();
FRandomStream WeaponRandomStream(RandomSeed);
const float CurrentSpread = GetCurrentSpread();
const float ConeHalfAngle = FMath::DegreesToRadians(CurrentSpread * 0.5f);

   //获取AShooterPlayerController的rotation的单位向量
const FVector AimDir = GetAdjustedAim();
const FVector StartTrace = GetCameraDamageStartLocation(AimDir);
const FVector ShootDir = WeaponRandomStream.VRandCone(AimDir, ConeHalfAngle, ConeHalfAngle);
const FVector EndTrace = StartTrace + ShootDir * InstantConfig.WeaponRange; const FHitResult Impact = WeaponTrace(StartTrace, EndTrace);
ProcessInstantHit(Impact, StartTrace, ShootDir, RandomSeed, CurrentSpread); CurrentFiringSpread = FMath::Min(InstantConfig.FiringSpreadMax, CurrentFiringSpread + InstantConfig.FiringSpreadIncrement);
}

UE4 ShooterGame Demo的开火的代码的更多相关文章

  1. 微信JS-SDK DEMO页面和示例代码

    <?php require_once "jssdk.php"; $jssdk = new JSSDK("yourAppID", "yourApp ...

  2. 极客验证官方demo构建使用及代码分析

    #什么是极客验证? 官方定义:极验验证是一种在计算机领域用于区分自然人和机器人的,通过简单集成的方式,为开发者提供安全.便捷的云端验证服务. #使用命令从github上获取: git clone ht ...

  3. linux poi生成excel demo调试附调用代码

    1.下载poi-3.9-20121203.jar包 2.java code package com.userpackage; import java.io.FileOutputStream; impo ...

  4. spring-retry简单demo(附完整代码)

    重试 最近项目要用到重试.开始想自己写,后来想用RetryTemplate,最后想到既然项目用了springboot,还是直接集成spring-retry把. 代码 Application packa ...

  5. 微信小程序DEMO——面包旅行的代码

    API 集合在一起写了一个页面,并导出, const apiURL = 'http://xxx.xxxx.com'; const trip = { hot(data,callback){ wx.req ...

  6. ue4 shooterGame 第一步 搭建git linux服务器

    1.分别在linux(服务器)上安装git.和openssh服务, 在windows(客户机)上安装cygwin,模拟linux环境以及安装windows git客户端. 2.windows的cygw ...

  7. h5 网络断网时,返回上一个页面 demo (与检测网络代码相结合,更直观看到结果)

    页面一: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8& ...

  8. 李宏毅 Gradient Descent Demo 代码讲解

    何为梯度下降,直白点就是,链式求导法则,不断更新变量值. 这里讲解的代码为李宏毅老师机器学习课程中 class 4 回归展示 中的代码demo   Loss函数 python代码如下 import n ...

  9. 如何创建独立的UE4服务端

    原文作者:@玄冬Wong 转载请注明原文出处:http://aigo.iteye.com/blog/2268777 这是论坛上对UE服务端功能的回答,意思是UE4提供了主流MMO网游服务端所具备的特性 ...

随机推荐

  1. 1.Spring Boot入门及其jar包依赖模型分析

    Spring Boot介绍 Spring Boot是由Pivotal团队提供的新框架,其设计目的是简化Spring应用的搭建以及开发过程.其目标是: 为所有Spring开发提供一个从根本上更快,且方便 ...

  2. MySQL报错InnoDB: A long semaphore wait【转】

    mysql登录后无法执行命令如show processlist 查看MySQL错误日志 参考以下方法,执行 1.系统层面 [root@pisphkdcbsql01 ~]# cat /proc/sys/ ...

  3. 026_lsof命令经验总结

    一.lsof处理删除文件未释放句柄问题. 但是如果你不知道是哪个文件,或者是很多文件都有这样的情况,那你需要使用如下命令 lsof |grep deleted 注:这个deleted表示该已经删除了的 ...

  4. linux下使用命令模式去编译Qt程序

    1.打开终端输入,qmake -v ,如果提示版本信息正,就可以编译程序了. 2.当前目录切换到程序源代码目录,cd /home/likewei/untitled2 3.生成untitled2.pro ...

  5. mybatis:在springboot中的配置

    ## Mybatis 配置 mybatis.type-aliases-package=com.xfind.core.entity.xianyu mybatis.mapper-locations=cla ...

  6. MVC、MVP、MVVM模式

    MVC,MVP和MVVM都是常见的软件架构设计模式(Architectural Pattern),它通过分离关注点来改进代码的组织方式.不同于设计模式(Design Pattern),只是为了解决一类 ...

  7. JQery插件zClip ----实现粘贴复制功能

    使用了这个插件,但是用在table,td中话,我是一个列表来的,对此使用此插件还是有点问题的?点击其中的一个会全部都被选中. <script type="text/javascript ...

  8. 22)django-中间件

    一:中间件介绍 django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后, django会根据自己的规则在合适的时机执行中间件中相应的方法. 在dj ...

  9. redhat7.3 superset的离线安装

    superset是一个python 开发的可视化工具,可以与kylin连接进行数据分析,在官网的讲解中,采用了在线安装方式,生产环境中有yum源,但是没有网,不得不采用离线安装方式.(我们先在有网的环 ...

  10. Vue中的render函数随笔

    使用vue-cli创建项目后,再main.js里面有这样一段代码: new Vue({ render:h => h(App) }).$mount('#app') render函数是渲染一个视图, ...