UE4 ShooterGame Demo的开火的代码
之前一直没搞懂按下鼠标左键开火之后,代码的逻辑是怎么走的,今天看懂了之前没看懂的部分,进了一步
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的开火的代码的更多相关文章
- 微信JS-SDK DEMO页面和示例代码
<?php require_once "jssdk.php"; $jssdk = new JSSDK("yourAppID", "yourApp ...
- 极客验证官方demo构建使用及代码分析
#什么是极客验证? 官方定义:极验验证是一种在计算机领域用于区分自然人和机器人的,通过简单集成的方式,为开发者提供安全.便捷的云端验证服务. #使用命令从github上获取: git clone ht ...
- linux poi生成excel demo调试附调用代码
1.下载poi-3.9-20121203.jar包 2.java code package com.userpackage; import java.io.FileOutputStream; impo ...
- spring-retry简单demo(附完整代码)
重试 最近项目要用到重试.开始想自己写,后来想用RetryTemplate,最后想到既然项目用了springboot,还是直接集成spring-retry把. 代码 Application packa ...
- 微信小程序DEMO——面包旅行的代码
API 集合在一起写了一个页面,并导出, const apiURL = 'http://xxx.xxxx.com'; const trip = { hot(data,callback){ wx.req ...
- ue4 shooterGame 第一步 搭建git linux服务器
1.分别在linux(服务器)上安装git.和openssh服务, 在windows(客户机)上安装cygwin,模拟linux环境以及安装windows git客户端. 2.windows的cygw ...
- h5 网络断网时,返回上一个页面 demo (与检测网络代码相结合,更直观看到结果)
页面一: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8& ...
- 李宏毅 Gradient Descent Demo 代码讲解
何为梯度下降,直白点就是,链式求导法则,不断更新变量值. 这里讲解的代码为李宏毅老师机器学习课程中 class 4 回归展示 中的代码demo Loss函数 python代码如下 import n ...
- 如何创建独立的UE4服务端
原文作者:@玄冬Wong 转载请注明原文出处:http://aigo.iteye.com/blog/2268777 这是论坛上对UE服务端功能的回答,意思是UE4提供了主流MMO网游服务端所具备的特性 ...
随机推荐
- 题解-poj3682King Arthur's Birthday Celebration
Problem poj-3682 题目大意:抛一次硬币有\(p\)的概率得到正面,当有\(n\)次正面时停止,抛第\(i\)次的花费为\(2i-1\),求抛的期望次数和期望花费 Solution 本来 ...
- 【转】gcc中的-w -W和-Wall选项
-w的意思是关闭编译时的警告,也就是编译后不显示任何warning,因为有时在编译之后编译器会显示一些例如数据转换之类的警告,这些警告是我们平时可以忽略的. -Wall选项意思是编译后显示所有警告. ...
- jquery获取浏览器URL参数
getRequestParams:function(param){ var reg = new RegExp("(^|&)" + param + "=([^&am ...
- spring集成cxf实现webservice接口功能
由于cxf的web项目已经集成了Spring,所以cxf的服务类都是在spring的配置文件中完成的.以下是步骤:第一步:建立一个web项目.第二步:准备所有jar包.将cxf_home\lib项目下 ...
- SQL Server统计数据库中表个数、视图个数、存储过程个数
表个数 SELECT count(*) FROM sys.objects WHERE type='U' 视图个数 SELECT count(*) FROM sys.objects WHERE type ...
- 快速安装freeswitch
前不久在Centos 6.4上安装了一台Freeswitch,测试已经OK.为了测试FS 的集群效果,从新在安装一台FS,快速安装的过程如下: 方案一:快速安装前提:不用重新下载Freeswitch. ...
- python第13天
装饰器 装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何改动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象. 装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等 ...
- 随机生成游戏用户昵称(nodejs版本)(含机器人头像,金币等)
1 前言 有时需要生成随机的用户(或机器人)昵称,头像,金币等,但又不想太生硬,可以现在网上爬一些常见昵称到文本中,然后读取出来,随机使用即可. 2 代码 var nickNameArr = []; ...
- Python-数据类型 主键auto_increment
MySQL数据操作: DML========================================================在MySQL管理软件中,可以通过SQL语句中的DML语言来实 ...
- jquery中的attr与prop的区别,什么时候用attr,什么时候用prop
只要有 Boolean() 属性的,简单说就是具有true 和 false 两个属性的属性,如 checked, selected 或者 disabled 使用prop(),(其实这些都是表单类的), ...