C++继承关系图
参考学习视频
1、蓝图实现武器放入骨骼中的槽口
步骤1、在人物上给右手添加插槽
步骤2、武器的骨骼实现
步骤3、蓝图的实现
【进阶版】
【效果图】
【备注】
你也可以通过在插槽右键添加预览资源,旋转插槽进行一个持枪的具体调整
2、C++实现发射激光+特效生成
【Sweapon.cpp】
// Fill out your copyright notice in the Description page of Project Settings. #include "SWeapon.h" #include "Components/SkeletalMeshComponent.h" #include "Components/ActorComponent.h" #include "Engine/World.h" #include "DrawDebugHelpers.h" #include "Kismet/GameplayStatics.h" #include "Particles/ParticleSystemComponent.h" #include "PhysicalMaterials/PhysicalMaterial.h" #include "CoopGame.h" // Sets default values ASWeapon::ASWeapon() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; MeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MeshComponent")); RootComponent = MeshComponent; MuzzleSocketName = "MuzzleSocket"; TrancerTargetgetName = "Target"; BaseDamage = 20; HeadDamage = 100; } // Called when the game starts or when spawned void ASWeapon::BeginPlay() { Super::BeginPlay(); } static int32 DebugWeapnDrawing = 0; FAutoConsoleVariableRef CVARDebugWeaponDrawing( TEXT("COOP.WeaponsLine"), DebugWeapnDrawing, TEXT("Draw Debug Lines for Weapons"), ECVF_Cheat ); void ASWeapon::Fire() { //获得当前玩家 AActor* MyOwner = GetOwner(); if (MyOwner) { APawn* MyPawn = Cast<APawn>(GetOwner()); //镜头震动 if (MyPawn) { APlayerController *PC = Cast<APlayerController>(MyPawn->GetController()); if (PC) { PC->ClientPlayCameraShake(FireCamShake); } } FVector EyeLocation; FRotator EyeRotator; //获取眼睛位置信息 MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotator); FVector MuzzleLocation = MeshComponent->GetSocketLocation(MuzzleSocketName); //FVector DirectRotation = MeshComponent->GetSocketRotation(MuzzleSocketName).Vector(); //弹道终点 = 起点+方向 * 10000 FVector TraceEnd = EyeLocation + EyeRotator.Vector() * 10000; //撞击句柄,获取弹道信息 FHitResult Hit; //碰撞查询参数 FCollisionQueryParams QueryParams; //FCollisionQueryParams QueryParams; //忽略玩家和这把枪 QueryParams.AddIgnoredActor(MyOwner); QueryParams.AddIgnoredActor(this); //复合追踪,让射击更精准,可以追踪目标网格每一个三角形 QueryParams.bTraceComplex = true; QueryParams.bReturnPhysicalMaterial = true; FVector TraceEndPoint = TraceEnd; //GetWorld()->LineTraceSingleByChannel(Hit, 起点, 终点, 可见性弹道,碰撞查询参数) 如果击中则为真 if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, COLLISION_WEAPON, QueryParams)) { AActor* HitActor = Hit.GetActor(); TraceEndPoint = Hit.ImpactPoint; //设置材质 EPhysicalSurface SurfaceType = UPhysicalMaterial::DetermineSurfaceType(Hit.PhysMaterial.Get()); UParticleSystem *SelectedEffect = nullptr; float realDamage = BaseDamage; if (SurfaceType == SURFACE_FLESHEAD) realDamage = HeadDamage; switch (SurfaceType) { case SURFACE_FLESHBODY: case SURFACE_FLESHEAD: SelectedEffect = FleshImpactEffect; break; default: SelectedEffect = DefaultImpactEffect; break; } //伤害对象,基础伤害,射击方向,命中信息,eventInstigator, 伤害者,伤害类 UGameplayStatics::ApplyPointDamage(HitActor, realDamage, EyeRotator.Vector(), Hit, MyOwner->GetInstigatorController(), this, DamageType); if (SelectedEffect) { //被击中处的特效 //GetWorld 特效,位置是撞击位置,旋转 命中效果 UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), SelectedEffect, Hit.ImpactPoint, Hit.ImpactNormal.Rotation()); } } //DrawDebugLine(GetWorld(), 起点, 终点, 颜色, 不需要一直存在, 持续1s, 0, 粗细); if(DebugWeapnDrawing > 0) DrawDebugLine(GetWorld(), MuzzleLocation, TraceEnd, FColor::Red, false, 1, 0, 1); if (MuzzleEffect) { 保证特效出生在枪口的槽位上SpawnEmitterAttached ,枪口特效,如何定位到槽位上的呢?只有一个槽位就这么些,如果有多个呢 //UGameplayStatics::SpawnEmitterAttached(MuzzleEffect, MeshComponent, MuzzleSocketName); UParticleSystemComponent *it = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), MuzzleEffect, MuzzleLocation); } //弹道特效 if (TracerEffect) { UParticleSystemComponent *it = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), TracerEffect, MuzzleLocation); if (it) { //参数名字,参数向量 it->SetVectorParameter(TrancerTargetgetName, TraceEndPoint); } } } } // Called every frame void ASWeapon::Tick(float DeltaTime) { Super::Tick(DeltaTime); }
关键代码:
//撞击句柄,获取弹道信息 FHitResult Hit; //碰撞查询参数 FCollisionQueryParams QueryParams; //FCollisionQueryParams QueryParams; //忽略玩家和这把枪 QueryParams.AddIgnoredActor(MyOwner); QueryParams.AddIgnoredActor(this); //复合追踪,让射击更精准,可以追踪目标网格每一个三角形 QueryParams.bTraceComplex = true; QueryParams.bReturnPhysicalMaterial = true; FVector TraceEndPoint = TraceEnd; //GetWorld()->LineTraceSingleByChannel(Hit, 起点, 终点, 可见性弹道,碰撞查询参数) 如果击中则为真 if (GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, COLLISION_WEAPON, QueryParams)) { //伤害对象,基础伤害,射击方向,命中信息,eventInstigator, 伤害者,伤害类 UGameplayStatics::ApplyPointDamage(HitActor, realDamage, EyeRotator.Vector(), Hit, MyOwner->GetInstigatorController(), this, DamageType); if (SelectedEffect) { //被击中处的特效 //GetWorld 特效,位置是撞击位置,旋转 命中效果 UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), SelectedEffect, Hit.ImpactPoint, Hit.ImpactNormal.Rotation()); } } //DrawDebugLine(GetWorld(), 起点, 终点, 颜色, 不需要一直存在, 持续1s, 0, 粗细); if(DebugWeapnDrawing > 0) DrawDebugLine(GetWorld(), MuzzleLocation, TraceEnd, FColor::Red, false, 1, 0, 1); if (MuzzleEffect) { 保证特效出生在枪口的槽位上SpawnEmitterAttached ,枪口特效,如何定位到槽位上的呢?只有一个槽位就这么些,如果有多个呢 //UGameplayStatics::SpawnEmitterAttached(MuzzleEffect, MeshComponent, MuzzleSocketName); UParticleSystemComponent *it = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), MuzzleEffect, MuzzleLocation); } //弹道特效 if (TracerEffect) { UParticleSystemComponent *it = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), TracerEffect, MuzzleLocation); if (it) { //参数名字,参数向量 it->SetVectorParameter(TrancerTargetgetName, TraceEndPoint); } } }
【Swapon.h】
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "SWeapon.generated.h" class UDamageType; UCLASS() class COOPGAME_API ASWeapon : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties ASWeapon(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Component") class USkeletalMeshComponent *MeshComponent; UFUNCTION(BlueprintCallable, Category = "Weapon") virtual void Fire(); //EditDefaultsOnly:只可通过类默认值修改内容 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") TSubclassOf<UDamageType> DamageType; UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Weapon") FName MuzzleSocketName; UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Weapon") FName TrancerTargetgetName; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") class UParticleSystem* MuzzleEffect; //默认击中特效 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") class UParticleSystem* DefaultImpactEffect; //击中身体时的特效 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") class UParticleSystem* FleshImpactEffect; //枪口特效 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") class UParticleSystem* TracerEffect; //窗口抖动 UPROPERTY(EditDefaultsOnly, Category = "Weapon") TSubclassOf<class UCameraShake> FireCamShake; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") float BaseDamage; UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon") float HeadDamage; public: // Called every frame virtual void Tick(float DeltaTime) override; };
3、C++实现应用点伤产生伤害 (原理:ue4自带函数,学习射击句柄)
//伤害对象,基础伤害,射击方向,命中信息,eventInstigator, 伤害者,伤害类 UGameplayStatics::ApplyPointDamage(HitActor, realDamage, EyeRotator.Vector(), Hit, MyOwner->GetInstigatorController(), this, DamageType); //撞击句柄 FHitResult Hit; GetWorld()->LineTraceSingleByChannel(Hit, EyeLocation, TraceEnd, COLLISION_WEAPON, QueryParams)
4、C++实现枪口特效 (原理:ue4自带函数)
if (MuzzleEffect) { 保证特效出生在枪口的槽位上SpawnEmitterAttached ,枪口特效,如何定位到槽位上的呢?只有一个槽位就这么些,如果有多个呢 //UGameplayStatics::SpawnEmitterAttached(MuzzleEffect, MeshComponent, MuzzleSocketName); UParticleSystemComponent *it = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), MuzzleEffect, MuzzleLocation); }
5、蓝图实现榴弹、手榴弹
新建SProjectileWeapon,并继承Sweapon.h,并重写Fire函数如下
SProjectileWeapon.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "SProjectileWeapon.h" #include "Engine/World.h" #include "Components/SkeletalMeshComponent.h" void ASProjectileWeapon::Fire() { //获得当前玩家 AActor* MyOwner = GetOwner(); if (MyOwner) { FVector EyeLocation; FRotator EyeRotator; //获取眼睛位置信息 MyOwner->GetActorEyesViewPoint(EyeLocation, EyeRotator); FVector MuzzleLocation = MeshComponent->GetSocketLocation(MuzzleSocketName); FActorSpawnParameters SpawnParams; //SpawnCollisionHandlingOverride?? AlwaysSpawn?? SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; if (ProjectileClass) { //类,位置,方向 GetWorld()->SpawnActor<AActor>(ProjectileClass, MuzzleLocation, EyeRotator, SpawnParams); } } }
SProjectileWeapon.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "SWeapon.h" #include "SProjectileWeapon.generated.h" /** * */ UCLASS() class COOPGAME_API ASProjectileWeapon : public ASWeapon { GENERATED_BODY() protected: virtual void Fire() override; UPROPERTY(EditDefaultsOnly, Category = "ProjectTileWeapon") TSubclassOf<AActor> ProjectileClass; };
子弹蓝图:【我这里有问题,apply radial damage 返回值是false,还没找到具体问题】
子弹爆炸时的特效蓝图