射击游戏案例(四)

2024-05-24 16:36
文章标签 游戏 案例 射击

本文主要是介绍射击游戏案例(四),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、瞄准偏移(AimOffset)

现在已经给角色添加了射击和准星,当角色在Pitch轴上偏移的时候,一般的游戏中都会有角色的手臂武器进行朝向的改变,比如角色向上看,手臂武器的指向向上。

附虚幻引擎5.2版本瞄准偏移如何创建、使用:5.2版本瞄准偏移

在将瞄准偏移所用到的动画帧批处理的时候,在附加设置处要注意附加动画类型、基础姿势类型、基础姿势动画设置好。

 创建出来之后,将做好的单帧动画拖入。

 CharacterAnim.h

UPROPERTY(EditAnywhere,BlueprintReadOnly,Category=Properties,meta=(AllowPrivateAccess="true"))
float PitchValue = 0.0f;//俯仰值

CharacterAnim.cpp

void UCharacterAnim::NativeUpdateAnimation(float DeltaSeconds)
{Super::NativeUpdateAnimation(DeltaSeconds);if (!CharacterRef){CharacterRef = Cast<AManCharacter>(TryGetPawnOwner());}else{FVector CharacterVelocity = CharacterRef->GetVelocity();Speed = CharacterVelocity.Size();IsInAir = CharacterRef->GetMovementComponent()->IsFalling();Direction = CalculateDirection(CharacterVelocity,CharacterRef->GetControlRotation());const FRotator CharacterRotator = CharacterRef->GetActorRotation();const FRotator ControlRotator = CharacterRef->GetControlRotation();const FRotator DeltaRotator = UKismetMathLibrary::NormalizedDeltaRotator(ControlRotator,CharacterRotator);const FRotator CurrentRotator = FRotator(PitchValue,0.0f,0.0f);const FRotator TargetRotator = UKismetMathLibrary::RInterpTo(CurrentRotator,DeltaRotator,DeltaSeconds,15.0f);PitchValue = FMath::ClampAngle(TargetRotator.Pitch,-90.0f,90.0f);}
}

打开动画蓝图,将瞄准偏移添加到状态机中,并用通过骨骼层混合动画。

 当向上瞄准的时候,武器和手部会向上偏移一些。

 二、射击

2.1 射击射线检测

在这里将使用从屏幕中央,也就是准星处射出一条射线去进行射线检测,判断是否射击到了物体。

在这里将BaseCharacter中的FireWeapon方法在ManCharacter中进行了重写。

ManCharacter.h

protected:virtual void BeginPlay() override;/*** 武器开火*/virtual void FireWeapon() override;/*** 获取以屏幕中心为射线检测开始点的世界位置和方向* @param StartLocation 世界位置* @param Direction 方向*/void GetScreenFireStartLocationAndDirection(FVector& StartLocation,FVector& Direction);

ManCharacter.cpp

void AManCharacter::GetScreenFireStartLocationAndDirection(FVector& StartLocation, FVector& Direction)
{if (GEngine && GEngine->GameViewport){FVector2D OutViewportSize;GEngine->GameViewport->GetViewportSize(OutViewportSize);FVector2D HalfViewportSize = FVector2D(OutViewportSize.X/2,OutViewportSize.Y/2);APlayerController* PC = UGameplayStatics::GetPlayerController(GetWorld(),0);PC->DeprojectScreenPositionToWorld(HalfViewportSize.X,HalfViewportSize.Y,StartLocation,Direction);}
}

HalfViewportSize就是屏幕中央的位置,使用DeprojectScreenPositionToWorld将屏幕坐标转化成世界坐标并获取了指向的方向。

在FireWeapon中进行射线检测:

void AManCharacter::FireWeapon()
{Super::FireWeapon();FVector OutWorldLocation;FVector OutWorldDirection;GetScreenFireStartLocationAndDirection(OutWorldLocation,OutWorldDirection);FVector StartLocation = OutWorldLocation;FVector EndLocation = StartLocation + OutWorldDirection * ShootDistance;FHitResult ScreenHitResult;FCollisionQueryParams QueryParams;QueryParams.AddIgnoredActor(this);//单通道射线检测GetWorld()->LineTraceSingleByChannel(ScreenHitResult,StartLocation,EndLocation,ECC_Visibility,QueryParams);FColor DrawColor = FColor::Red;if (ScreenHitResult.GetActor()){EndLocation = ScreenHitResult.Location;DrawColor = FColor::Green;}DrawDebugLine(GetWorld(),StartLocation,EndLocation,DrawColor,false,2.0f,0,2.0f);
}

如果在ManCharacter中重写了FireWeapon的话,要Super::FireWeapon();调用一下父类,会将父类中的FireWeapon内容执行一遍,再去往下执行。

在这里使用了一个DrawDebugLine画一条线的方式进行调试,看下是否检测到了东西,注意射线检测的通道,这里是ECC_Visibility,如果没检测到的话,是红线,检测到则是绿线。

 2.2 枪口特效

射击的时候给武器添加射击的特效

使用的方法是用SpawnEmitterAtLocation在指定位置生成的粒子特效,这里使用的是ParticleSystem特效。

武器的模型中添加一个Muzzle的插槽,提供生成的位置。

 ManCharacter.h

UPROPERTY(EditAnywhere,BlueprintReadOnly,Category=Properties,meta=(AllowPrivateAccess="true"))
UParticleSystem* MuzzleParticle;//枪口特效

ManCharacter.cpp

//枪口特效
if (MuzzleParticle)
{FTransform MuzzleTransform = WeaponMesh->GetSocketTransform("Muzzle");UGameplayStatics::SpawnEmitterAtLocation(GetWorld(),MuzzleParticle,MuzzleTransform.GetLocation(),MuzzleTransform.Rotator(),FVector(0.5f));
}

2.3  射击到物体的撞击特效

ManCharacter.h

UPROPERTY(EditAnywhere,BlueprintReadOnly,Category=Properties,meta=(AllowPrivateAccess="true"))
UParticleSystem* ImpactParticle;//枪口特效

ManCharacter.cpp

//撞击特效
if (ImpactParticle)
{UGameplayStatics::SpawnEmitterAtLocation(GetWorld(),ImpactParticle,EndLocation);
}

注意:撞击效果要放到射线检测成功处,如果没有射击到物体,不需要显示撞击特效。

2.4  射击轨道特效

射击轨道同样需要根据射击结束点来处理轨道的长短。

在轨道特效中有一个目标,其中可以使用目标命名,SetVectorParameter设置向量参数去处理。

 ManCharacter.h

UPROPERTY(EditAnywhere,BlueprintReadOnly,Category=Properties,meta=(AllowPrivateAccess="true"))
UParticleSystem* BeamParticle;//射击轨迹特效

ManCharacter.cpp

//射击轨迹特效
if (BeamParticle)
{FTransform MuzzleTransform = WeaponMesh->GetSocketTransform("Muzzle");UParticleSystemComponent* PSComp = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(),BeamParticle,MuzzleTransform.GetLocation());if (PSComp){PSComp->SetVectorParameter("Target",EndLocation);}
}

 2.5 射击音效

ManCharacter.h

UPROPERTY(EditAnywhere,BlueprintReadOnly,Category=Properties,meta=(AllowPrivateAccess="true"))
USoundBase* FireSound;//射击音效

ManCharacter.cpp

//射击音效
if(FireSound)
{UGameplayStatics::PlaySoundAtLocation(GetWorld(),FireSound,GetActorLocation());
}

2.6 射击效果优化

如图所示,准星瞄准的前方有一块立方体挡住,射击落点在准星处,而实际上射击轨道是穿过了立方体,所以,此时射击落点应当设置在碰撞到立方体处的位置。

 这里修复的方式是在以准星为落击点时,进行了射击检测的时候,如果射击到物体时,再以枪口为起点,准星的落击碰撞点为终点进行射线检测,如果碰撞到的话,落击点为枪口射线检测的结果为最终落击点。

 在ManCharacter.cpp中的FireWeapon方法:

FVector OutWorldLocation;
FVector OutWorldDirection;
GetScreenFireStartLocationAndDirection(OutWorldLocation,OutWorldDirection);
FVector StartLocation = OutWorldLocation;
FVector EndLocation = StartLocation + OutWorldDirection * ShootDistance;
FHitResult ScreenHitResult;
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(this);
//单通道射线检测
GetWorld()->LineTraceSingleByChannel(ScreenHitResult,StartLocation,EndLocation,ECC_Visibility,QueryParams);
if (ScreenHitResult.GetActor())
{EndLocation = ScreenHitResult.Location;//以枪口为初始点的射线检测FHitResult MuzzleHitResult;FCollisionQueryParams MuzzleQueryParams;MuzzleQueryParams.AddIgnoredActor(this);FTransform MuzzleTransform = WeaponMesh->GetSocketTransform("Muzzle");FVector MuzzleStart = MuzzleTransform.GetLocation();FVector MuzzleEnd = EndLocation;GetWorld()->LineTraceSingleByChannel(MuzzleHitResult,MuzzleStart,MuzzleEnd,ECC_Visibility,MuzzleQueryParams);if (MuzzleHitResult.GetActor()){EndLocation = MuzzleHitResult.Location;}//撞击特效if (ImpactParticle){UGameplayStatics::SpawnEmitterAtLocation(GetWorld(),ImpactParticle,EndLocation);}
}

2.7 代码重构和对应代码

2.7.1 ManCharacter.h

#pragma once#include "CoreMinimal.h"
#include "Gameplay/BaseCharacter.h"
#include "ManCharacter.generated.h"class USkeletalMeshComponent;
class UParticleSystem;
class USoundBase;/*** 小白人角色*/
UCLASS()
class SHOOTINGGAME_API AManCharacter : public ABaseCharacter
{GENERATED_BODY()public:AManCharacter();
protected:virtual void BeginPlay() override;/*** 武器开火*/virtual void FireWeapon() override;/*** 获取以屏幕中心为射线检测开始点的世界位置和方向* @param StartLocation 世界位置* @param Direction 方向*/void GetScreenFireStartLocationAndDirection(FVector& StartLocation,FVector& Direction);/*** 屏幕起始点射线检测* @param EndLocation 屏幕起始点射线检测的碰撞点* @param HitResult 碰撞结果*/void ScreenLineTrace(FVector& EndLocation,FHitResult& HitResult);/*** 枪口射线检测* @param OutLocation 输出的位置* @param ScreenHitLocation 屏幕点为起始点的射线检测碰撞点*/void MuzzleLineTrace(FVector& OutLocation,FVector ScreenHitLocation);/*** 设置开火的枪口特效,射击轨道特效,射击音效* @param TargetLocation 目标点* @param Hit 射线检测撞击结果*/void FireEffect(FVector TargetLocation,FHitResult Hit);
private:UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category=Components,meta=(AllowPrivateAccess="true"))USkeletalMeshComponent* WeaponMesh;UPROPERTY(EditAnywhere,BlueprintReadOnly,Category=Properties,meta=(AllowPrivateAccess="true"))float ShootDistance;//射击距离UPROPERTY(EditAnywhere,BlueprintReadOnly,Category=Properties,meta=(AllowPrivateAccess="true"))UParticleSystem* MuzzleParticle;//枪口特效UPROPERTY(EditAnywhere,BlueprintReadOnly,Category=Properties,meta=(AllowPrivateAccess="true"))UParticleSystem* ImpactParticle;//枪口特效UPROPERTY(EditAnywhere,BlueprintReadOnly,Category=Properties,meta=(AllowPrivateAccess="true"))UParticleSystem* BeamParticle;//射击轨迹特效UPROPERTY(EditAnywhere,BlueprintReadOnly,Category=Properties,meta=(AllowPrivateAccess="true"))USoundBase* FireSound;//射击音效
};

2.7.2 ManCharacter.cpp

#include "Gameplay/ManCharacter.h"
#include "Kismet/GameplayStatics.h"
#include "Particles/ParticleSystemComponent.h"AManCharacter::AManCharacter()
{PrimaryActorTick.bCanEverTick = true;WeaponMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WeaponMesh"));WeaponMesh->SetupAttachment(GetMesh(),"WeaponSocket");ShootDistance = 10000.0f;
}void AManCharacter::BeginPlay()
{Super::BeginPlay();
}void AManCharacter::FireWeapon()
{Super::FireWeapon();FVector OutLocation;FHitResult ScreenHitResult;//屏幕起始点射线检测ScreenLineTrace(OutLocation,ScreenHitResult);//射击效果FireEffect(OutLocation,ScreenHitResult);
}void AManCharacter::GetScreenFireStartLocationAndDirection(FVector& StartLocation, FVector& Direction)
{if (GEngine && GEngine->GameViewport){FVector2D OutViewportSize;GEngine->GameViewport->GetViewportSize(OutViewportSize);FVector2D HalfViewportSize = FVector2D(OutViewportSize.X/2,OutViewportSize.Y/2);APlayerController* PC = UGameplayStatics::GetPlayerController(GetWorld(),0);PC->DeprojectScreenPositionToWorld(HalfViewportSize.X,HalfViewportSize.Y,StartLocation,Direction);}
}void AManCharacter::ScreenLineTrace(FVector& EndLocation,FHitResult& HitResult)
{FVector OutWorldLocation;FVector OutWorldDirection;GetScreenFireStartLocationAndDirection(OutWorldLocation,OutWorldDirection);const FVector StartLocation = OutWorldLocation;EndLocation = StartLocation + OutWorldDirection * ShootDistance;FCollisionQueryParams QueryParams;QueryParams.AddIgnoredActor(this);//单通道射线检测GetWorld()->LineTraceSingleByChannel(HitResult,StartLocation,EndLocation,ECC_Visibility,QueryParams);if (HitResult.GetActor()){EndLocation = HitResult.Location;//以枪口为初始点的射线检测MuzzleLineTrace(EndLocation,EndLocation);}
}void AManCharacter::MuzzleLineTrace(FVector& OutLocation,FVector ScreenHitLocation)
{FHitResult MuzzleHitResult;FCollisionQueryParams MuzzleQueryParams;MuzzleQueryParams.AddIgnoredActor(this);FTransform MuzzleTransform = WeaponMesh->GetSocketTransform("Muzzle");FVector MuzzleStart = MuzzleTransform.GetLocation();FVector MuzzleEnd = ScreenHitLocation;GetWorld()->LineTraceSingleByChannel(MuzzleHitResult,MuzzleStart,MuzzleEnd,ECC_Visibility,MuzzleQueryParams);if (MuzzleHitResult.GetActor()){OutLocation = MuzzleHitResult.Location;}
}void AManCharacter::FireEffect(FVector TargetLocation,FHitResult Hit)
{const FTransform MuzzleTransform = WeaponMesh->GetSocketTransform("Muzzle");if (Hit.GetActor()){//撞击特效if (ImpactParticle){UGameplayStatics::SpawnEmitterAtLocation(GetWorld(),ImpactParticle,TargetLocation);}}//枪口特效if (MuzzleParticle){UGameplayStatics::SpawnEmitterAtLocation(GetWorld(),MuzzleParticle,MuzzleTransform.GetLocation(),MuzzleTransform.Rotator(),FVector(0.5f));}//射击轨迹特效if (BeamParticle){UParticleSystemComponent* PSComp = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(),BeamParticle,MuzzleTransform.GetLocation());if (PSComp){PSComp->SetVectorParameter("Target",TargetLocation);}}//射击音效if(FireSound){UGameplayStatics::PlaySoundAtLocation(GetWorld(),FireSound,GetActorLocation());}
}

这篇关于射击游戏案例(四)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/998946

相关文章

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

国产游戏崛起:技术革新与文化自信的双重推动

近年来,国产游戏行业发展迅猛,技术水平和作品质量均得到了显著提升。特别是以《黑神话:悟空》为代表的一系列优秀作品,成功打破了过去中国游戏市场以手游和网游为主的局限,向全球玩家展示了中国在单机游戏领域的实力与潜力。随着中国开发者在画面渲染、物理引擎、AI 技术和服务器架构等方面取得了显著进展,国产游戏正逐步赢得国际市场的认可。然而,面对全球游戏行业的激烈竞争,国产游戏技术依然面临诸多挑战,未来的

火柴游戏java版

代码 /*** 火柴游戏* <p>* <li>有24根火柴</li>* <li>组成 A + B = C 等式</li>* <li>总共有多少种适合方式?</li>* <br>* <h>分析:</h>* <li>除去"+"、"="四根,最多可用火柴根数20根。</li>* <li>全部用两根组合成"1",最大数值为1111。使用枚举法,A和B范围在0~1111,C为A+B。判断</li>** @

STL经典案例(四)——实验室预约综合管理系统(项目涉及知识点很全面,内容有点多,耐心看完会有收获的!)

项目干货满满,内容有点过多,看起来可能会有点卡。系统提示读完超过俩小时,建议分多篇发布,我觉得分篇就不完整了,失去了这个项目的灵魂 一、需求分析 高校实验室预约管理系统包括三种不同身份:管理员、实验室教师、学生 管理员:给学生和实验室教师创建账号并分发 实验室教师:审核学生的预约申请 学生:申请使用实验室 高校实验室包括:超景深实验室(可容纳10人)、大数据实验室(可容纳20人)、物联网实验

国产游戏行业的崛起与挑战:技术创新引领未来

国产游戏行业的崛起与挑战:技术创新引领未来 近年来,国产游戏行业蓬勃发展,技术水平不断提升,许多优秀作品在国际市场上崭露头角。从画面渲染到物理引擎,从AI技术到服务器架构,国产游戏已实现质的飞跃。然而,面对全球游戏市场的激烈竞争,国产游戏技术仍然面临诸多挑战。本文将探讨这些挑战,并展望未来的机遇,深入分析IT技术的创新将如何推动行业发展。 国产游戏技术现状 国产游戏在画面渲染、物理引擎、AI