直接使用计时器,按住鼠标左键可以每1秒设计一次
但是通过频繁点击鼠标左键,可以实现更快的发射速度。
void ASWeapon::StartFire() //人物中通过函数与鼠标左键IE_Pressed绑定
{
GetWorldTimerManager().SetTimer(TimerHandle_TimeBetweenShots, this, &ASWeapon::Fire, 1.f, true);
}
void ASWeapon::StopFire() //人物中通过函数与鼠标左键IE_Released绑定
{
GetWorldTimerManager().ClearTimer(TimerHandle_TimeBetweenShots);
}
控制发射速率:
首先设置几个变量
FTimerHandle TimerHandle_TimeBetweenShots; // 计时器
float LastFireTime; //上次射击完成时间 单次射击函数Fire末尾设置
UPROPERTY(EditDefaultsOnly, Category = "Weapon")
float RateOfFire; //开火速率(每分钟发射次数)
float TimeBetweenShots; //射击频率,即60/RateOfFire 在BeginPlay中设置
单次射击Fire函数最后设置LastFireTime
LastFireTime = GetWorld()->TimeSeconds;
修改StartFire函数:
void ASWeapon::StartFire()
{
//应添加延迟 = 上次射击结束时间 - 当前时间 + 射击频率
float FirstDelay = FMath::Max(LastFireTime + TimeBetweenShots - GetWorld()->TimeSeconds, 0.0f);
//加入延迟项,延迟第一次点击后立即点击第二次的触发时间。如果不设置最后一项,会使用射击频率作为延迟
GetWorldTimerManager().SetTimer(TimerHandle_TimeBetweenShots, this, &ASWeapon::Fire, TimeBetweenShots, true, FirstDelay);
}
小bug:LastFireTime在游戏刚开始时默认值为0,在游戏刚开始的TimeBetweenShots时间内无法射击。
解决:在BeginPlay中设置,这样游戏刚开始的射击延迟为0
LastFireTime = GetWorld()->TimeSeconds - TimeBetweenShots;
记录一下用到的SetTimer函数的API
/**
* Sets a timer to call the given native function at a set interval. If a timer is already set
* for this handle, it will replace the current timer.
*
* @param InOutHandle If the passed-in handle refers to an existing timer, it will be cleared before the new timer is added. A new handle to the new timer is returned in either case.
* @param InObj Object to call the timer function on.
* @param InTimerMethod Method to call when timer fires.
* @param InRate The amount of time (in seconds) between set and firing. If <= 0.f, clears existing timers.
* @param InbLoop true to keep firing at Rate intervals, false to fire only once.
* @param InFirstDelay The time (in seconds) for the first iteration of a looping timer. If < 0.f InRate will be used.
*/
template< class UserClass >
FORCEINLINE void SetTimer(FTimerHandle& InOutHandle, UserClass* InObj, typename FTimerDelegate::TUObjectMethodDelegate< UserClass >::FMethodPtr InTimerMethod, float InRate, bool InbLoop = false, float InFirstDelay = -1.f)
{
InternalSetTimer(InOutHandle, FTimerUnifiedDelegate( FTimerDelegate::CreateUObject(InObj, InTimerMethod) ), InRate, InbLoop, InFirstDelay);
}