虚幻四C++入坑指南11:C++实现FPS游戏实现发射物

虚幻四C++入坑指南11:C++实现FPS游戏实现发射物
虚幻引擎4文档 > 编程指南 > C++ 编程教程 > 第一人称射击游戏教程 > 3 - 实现发射物 > 3.1 - 为游戏添加发射物
虚幻引擎4文档 > 编程指南 > C++ 编程教程 > 第一人称射击游戏教程 > 3 - 实现发射物 > 3.2 - 实现射击
虚幻引擎4文档 > 编程指南 > C++ 编程教程 > 第一人称射击游戏教程 > 3 - 实现发射物 > 3.3 - 设置发射物的碰撞和生命周期
虚幻引擎4文档 > 编程指南 > C++ 编程教程 > 第一人称射击游戏教程 > 3 - 实现发射物 > 3.4 - 使发射物和世界场景形成交互

轴映射

在这里插入图片描述

新建Actor类型的C++类“FPSProjectile”

在这里插入图片描述

这次动到了4个文件,子弹需要角色的摄像机的属性

01 FPSProjectile.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Camera/CameraComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "PhysicsEngine/SphereElem.h"
#include "GameFramework/DefaultPawn.h"//自己加的
#include "Components/SphereComponent.h"//自己加的
#include "GameFramework/ProjectileMovementComponent.h"
#include "FPSProjectile.generated.h"


UCLASS()
class QUICKSTART_API AFPSProjectile : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AFPSProjectile();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;
	//**********************************************************************
	// 球体碰撞组件。
	UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
		USphereComponent* CollisionComponent;
	// 发射物运动组件。
	UPROPERTY(VisibleAnywhere, Category = Movement)
		UProjectileMovementComponent* ProjectileMovementComponent;
	// 在发射方向上设置发射物初速度的函数。
	void FireInDirection(const FVector& ShootDirection);
	//******************************************************************
	// 发射物命中物体时调用的函数。
	void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit);
};


01 FPSProjectile.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FPSProjectile.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Components/SphereComponent.h"
// Sets default values
AFPSProjectile::AFPSProjectile()
{
 	// 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;

    //***********************************************************************
    // 使用球体代表简单碰撞。
    CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
    CollisionComponent->BodyInstance.SetCollisionProfileName(TEXT("Projectile"));
    CollisionComponent->OnComponentHit.AddDynamic(this, &AFPSProjectile::OnHit);
    // 设置球体的碰撞半径。
    CollisionComponent->InitSphereRadius(15.0f);
    // 将碰撞组件设为根组件。
    //模拟将驱动 CollisionComponent,所以将其设为 RootComponent。
    RootComponent = CollisionComponent;

    // 使用此组件驱动此发射物的运动。
    ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent"));
    //ProjectileMovementComponent,使用此组件驱动/更新发射物的运动,比如位置、碰撞后弹跳、向目标归为
    //原始Actor组件会被移动
    ProjectileMovementComponent->SetUpdatedComponent(CollisionComponent);
    //官网没加
    //设置碰撞预设
    CollisionComponent->BodyInstance.SetCollisionProfileName(TEXT("Projectile"));
    //初速度
    ProjectileMovementComponent->InitialSpeed = 3000.0f;
    //最大速度
    ProjectileMovementComponent->MaxSpeed = 3000.0f;
    //旋转每帧更新,匹配速度方向
    ProjectileMovementComponent->bRotationFollowsVelocity = true;
    //反弹
    ProjectileMovementComponent->bShouldBounce = true;
    //反弹系数
    ProjectileMovementComponent->Bounciness = 0.3f;
    //3秒后消亡
    InitialLifeSpan = 3.0f;
}

// Called when the game starts or when spawned
void AFPSProjectile::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AFPSProjectile::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}
//*******************************************************************************
// 在发射方向上设置发射物初速度的函数。
//只需提供一个发射方向,因为发射物的速度由 ProjectileMovementComponent 定义。
//在发射方向上设置初速度
void AFPSProjectile::FireInDirection(const FVector& ShootDirection)
{
    ProjectileMovementComponent->Velocity = ShootDirection * ProjectileMovementComponent->InitialSpeed;
}

// 发射物命中物体时调用的函数。
void AFPSProjectile::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit)
{
    if (OtherActor != this && OtherComponent->IsSimulatingPhysics())
    {
        OtherComponent->AddImpulseAtLocation(ProjectileMovementComponent->Velocity * 100.0f, Hit.ImpactPoint);
    }
}



02 FPSCharacter.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Math/Vector.h"
#include "FPSCharacter.generated.h"

//在.h没引入相关的头文件,没报错,是因为下面声明了一下
class UCameraComponent;
class USkeletalMeshComponent;


UCLASS()
class QUICKSTART_API AFPSCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AFPSCharacter();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;


	// 处理前进和后退的输入。
	UFUNCTION()
		void MoveForward(float Value);

	// 处理左右移动的输入。
	UFUNCTION()
		void MoveRight(float Value);

	// 按下按键时设置跳跃标记。
	UFUNCTION()
		void StartJump();

	// 松开按键时清除跳跃标记。
	UFUNCTION()
		void StopJump();

	// FPS 摄像机。
	UPROPERTY(VisibleAnywhere)
		UCameraComponent* FPSCameraComponent;


	// 第一人称模型(手臂),仅对拥有玩家可见。
	UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
		//骨骼类型的组件
		//#include "Components/SkeletalMeshComponent.h"(.cpp)
		USkeletalMeshComponent* FPSMesh;
	//***************************************************************************
		// 处理开火的函数。
	UFUNCTION()
		void Fire();
	// 从摄像机位置的枪口偏移。
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
		FVector MuzzleOffset;

	// 生成的发射物类。
	UPROPERTY(EditDefaultsOnly, Category = Projectile)
		TSubclassOf<class AFPSProjectile> ProjectileClass;
};


02 FPSCharacter.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FPSCharacter.h"
#include "Engine/Engine.h"
#include "Camera/CameraComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "FPSProjectile.h"

// Sets default values
AFPSCharacter::AFPSCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;


	//*************************************************************************
	// 创建一个第一人称摄像机组件。
	FPSCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
	/*
		void USceneComponent::SetupAttachment(class USceneComponent* InParent, FName InSocketName)
		class UCapsuleComponent* GetCapsuleComponent() const { return CapsuleComponent; }
		一个是场景类型,一个是胶囊体类型,类型不匹配,需要强转类型
		官网:FPSCameraComponent->SetupAttachment(GetCapsuleComponent());
	*/
	// 将摄像机组件附加到胶囊体组件。
	FPSCameraComponent->SetupAttachment((USceneComponent *)GetCapsuleComponent());
	// 将摄像机放置在眼睛上方不远处。
	FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));
	// 用 pawn 控制摄像机旋转。
	FPSCameraComponent->bUsePawnControlRotation = true;

	//*************************************************************************
		// 为拥有玩家创建一个第一人称模型组件。
	FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
	// 该模型仅对拥有玩家可见。
	//其他玩家看到的你的胳膊断的,像阴阳师的鬼切
	FPSMesh->SetOnlyOwnerSee(true);
	// 将 FPS 模型添加到 FPS 摄像机。
	FPSMesh->SetupAttachment(FPSCameraComponent);
	// 禁用部分环境阴影,保留单一模型存在的假象。
	//断臂投影也不行
	FPSMesh->bCastDynamicShadow = false;
	FPSMesh->CastShadow = false;

	// 拥有玩家无法看到普通(第三人称)身体模型。
	GetMesh()->SetOwnerNoSee(true);

}

// Called when the game starts or when spawned
void AFPSCharacter::BeginPlay()
{
	Super::BeginPlay();
	if (GEngine)
	{
		// 显示调试信息五秒。-1"键"值(首个参数)说明我们无需更新或刷新此消息。
		GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
	}
}

// Called every frame
void AFPSCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	
	
	// 设置"移动"绑定。
	//PlayerInputComponent->BindAxis("通知", this, &AFPSCharacter::调用事件);
	/*
	//使用结构体内部的函数需要绑定函数,指明是呢一个类来调用的
	template<class UserClass>模板结构体
	FInputAxisBinding& BindAxis(const FName AxisName, UserClass * Object, typename FInputAxisHandlerSignature::TUObjectMethodDelegate< UserClass >::FMethodPtr Func)
	{
		FInputAxisBinding AB(AxisName);
		AB.AxisDelegate.BindDelegate(Object, Func);
		AxisBindings.Emplace(MoveTemp(AB));
		return AxisBindings.Last();
	}
	*/
	//前后左右移动
	PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);

	// 上下左右旋转,具体函数实现官方写好了
	//z轴旋转,左右
	//y轴旋转,上下
	PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
	PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);

	// 设置"动作"绑定。
	//上面都是BingAction
	PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
	PlayerInputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);
	//*****************************************************************
	PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &AFPSCharacter::Fire);
}
//********************************************************************
void AFPSCharacter::MoveForward(float Value)
{
	// 明确哪个方向是"前进",并记录玩家试图向此方向移动。
	FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
	AddMovementInput(Direction, Value);
}

void AFPSCharacter::MoveRight(float Value)
{
	// 明确哪个方向是"向右",并记录玩家试图向此方向移动。
	FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
	AddMovementInput(Direction, Value);
}

void AFPSCharacter::StartJump()
{
	/*
		源代码
		UPROPERTY(BlueprintReadOnly, Category = Character)
		uint32 bPressedJump : 1;
	*/
	bPressedJump = true;
}

void AFPSCharacter::StopJump()
{
	bPressedJump = false;
}
//**************************************************************************
void AFPSCharacter::Fire()
{
	// 尝试发射物体。
	if (ProjectileClass)
	{
		// 获取摄像机变换。
		FVector CameraLocation;
		FRotator CameraRotation;
		GetActorEyesViewPoint(CameraLocation, CameraRotation);

		// 将 MuzzleOffset 从摄像机空间变换到世界空间。
		FVector MuzzleLocation = CameraLocation + FTransform(CameraRotation).TransformVector(MuzzleOffset);
		FRotator MuzzleRotation = CameraRotation;
		// 将准星稍微上抬。
		MuzzleRotation.Pitch += 10.0f;
		UWorld* World = GetWorld();
		if (World)
		{
			FActorSpawnParameters SpawnParams;
			SpawnParams.Owner = this;
			SpawnParams.Instigator = Instigator;
			//11有评论这么干
			//SpawnParams.Instigator = this;
			// 在枪口处生成发射物。
			AFPSProjectile* Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams);
			if (Projectile)
			{
				// 设置发射物的初始轨道。
				FVector LaunchDirection = MuzzleRotation.Vector();
				Projectile->FireInDirection(LaunchDirection);
			}
		}
	}
}


03 子弹模型

下载、解压、导入
发射物模型
在这里插入图片描述

04 子弹蓝图 BP_FPSProjectile11

04 01 基于C++类“FPSProjectile”新建蓝图类,我命名“BP_FPSProjectile11”(11是视频集数,方便索引)

在这里插入图片描述
在这里插入图片描述

04 02 添加“StaticMesh”类型的组件,命名为“ProjectileMeshComponent”

在这里插入图片描述
在这里插入图片描述

04 03 蓝图加子弹(建议下图这样加)

在这里插入图片描述

04 04 缩放0.09,no collision

在这里插入图片描述

05 角色蓝图 给新增的属性赋值

05 01 Gameplay、Projectile

在这里插入图片描述

05 02 演示(子弹的位置有点高啊)

在这里插入图片描述

06 碰撞通道

在这里插入图片描述
在这里插入图片描述

07 拷贝Floor,做一个Cube

在这里插入图片描述

08 子弹蓝图 碰撞预设

在这里插入图片描述

09 演示 Cube被子弹击飞

在这里插入图片描述

00 bug 角色蓝图没有写的属性Gameplay、Projectile

主体没跳过,error就把相应位置的头文件补齐。
我是第二天生成,不知道原因,就有如下图在FPSCharacter.h代码中写好的栏目,Gameplay、Projectile。
在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值