UE4C++(10):制作第一人称射击游戏

10/15/2020

文章目录

  • 添加日志消息
  • 游戏模式(AGameModeBase)
  • 角色类(Pawn)
    • 为什么使用C++还要使用蓝图
      • 注意事项!
  • 实现发射物
    • 创建球体碰撞组件
    • 发射物运动组件
    • 实现射击
    • 抛射物碰撞预设
      • 碰撞响应、碰撞处理
    • 增加碰撞代理
  • 增加准星(HUD类)
  • 参考资料

添加日志消息

if (GEngine)
{
   // 显示调试信息五秒。 
   // -1"键"值(首个参数)说明我们无需更新或刷新此消息。
   GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Hello World, this is FPSGameMode!"));
}
  • 建议别放在Tick函数中
  • 最好用在StartPlay或者BeginPlay函数里面
  • GEngine表示游戏引擎,继承于UObject

游戏模式(AGameModeBase)

定义游戏规则:

  • 玩家加入游戏的条件,比如初级场,高级场等等
  • 游戏暂停和关卡过渡
  • 获胜条件
  • 等等游戏特定的行为

UE4C++(10):制作第一人称射击游戏_第1张图片
默认的游戏模式最主要的是分配Classes专栏

  • 游戏状态
  • 玩家控制器
  • HUD 界面
  • 默认玩家属性和行为
  • 等等

角色类(Pawn)

UE4C++(10):制作第一人称射击游戏_第2张图片
UE4C++(10):制作第一人称射击游戏_第3张图片

  • Character表示双足站立的人物
  • 创建C++类FPSCharacter
  • 设置轴映射,即按键操作,WASD表示移动,鼠标左键开火,空格跳跃
  • 实现角色移动函数并绑定到移动组件
// 调用后将功能绑定到输入
void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // 设置"移动"绑定。
    PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
}

InputComponent 是定义如何处理输入数据的组件。InputComponent 可附加到需要接收输入的 actor。
BindAxis 和BindAction 绑定了一个委托函数到项目设置中定义的行为或者轴

为什么使用C++还要使用蓝图

因为蓝图可以可视化操作,C++加载一个模型后,并不能直接看到模型的样子,最重要的是模型的初始位置和朝向的调整是很难确定的,同时摄像机的视图也需要仔细调整!

注意事项!

当你对C++的某些Component的属性进行重写的时候,它并不会更新已经生成的蓝图类,比如加入你已经拥有了一个FPSCharacter的蓝图类,现在C++想要隐藏骨骼模型

GetMesh()->SetOwnerNoSee(true);

蓝图类Renderring下的Owner No See 属性将会有一个恢复默认设置的标志,这个标志表示C++里面设置了默认情形,但需要手动调整。如果你生成了一个新的蓝图类,将会直接赋值默认属性。
Rendering下的属性

实现发射物

创建球体碰撞组件

UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
        USphereComponent* CollisionComponent; //即蓝图中的Sphere Collision
        
 // 使用球体代表简单碰撞。
 CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
 // 设置球体的碰撞半径。
 CollisionComponent->InitSphereRadius(15.0f);
 // 将碰撞组件设为根组件。
 RootComponent = CollisionComponent;

发射物运动组件

// 发射物运动组件。
UPROPERTY(VisibleAnywhere, Category = Movement)
UProjectileMovementComponent* ProjectileMovementComponent;

// 使用此组件驱动该发射物的运动。
ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent"));
ProjectileMovementComponent->SetUpdatedComponent(CollisionComponent);
ProjectileMovementComponent->InitialSpeed = 3000.0f;
ProjectileMovementComponent->MaxSpeed = 3000.0f;
ProjectileMovementComponent->bRotationFollowsVelocity = true;
ProjectileMovementComponent->bShouldBounce = true;
ProjectileMovementComponent->Bounciness = 0.3f;

// 在发射方向上设置发射物初速度的函数。
void AFPSProjectile::FireInDirection(const FVector& ShootDirection)
{
 	ProjectileMovementComponent->Velocity = ShootDirection * ProjectileMovementComponent->InitialSpeed;
}

FPSProjectile

实现射击

定义发射物生成的位置或方向

// 定义生成的发射物类,人物生成发射物
UPROPERTY(EditDefaultsOnly, Category = Projectile)
TSubclassOf<class AFPSProjectile> ProjectileClass;
// 从摄像机位置的枪口偏移,即方位
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
FVector MuzzleOffset;

//实现射击
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;
            // 在枪口处生成发射物。
            AFPSProjectile* Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams);
            if (Projectile)
            {
                // 设置发射物的初始轨道。
                FVector LaunchDirection = MuzzleRotation.Vector();
                Projectile->FireInDirection(LaunchDirection);
            }
        }
    }
}

蓝图中的FPSProjectile

抛射物碰撞预设

Edit->Project Setting->Engine->Collision

CollisionComponent->BodyInstance.SetCollisionProfileName(TEXT("Projectile"));

InitialLifeSpan = 3.0f; //子弹的声明周期

碰撞响应、碰撞处理

// 发射物命中物体时调用的函数。
UFUNCTION()
void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit);

// 发射物命中物体时调用的函数。
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);
    }
}
  • 碰撞的不是自己同时被碰撞到的组件模拟了物理
  • 被碰撞到的组件增加一个冲量

增加碰撞代理

CollisionComponent->OnComponentHit.AddDynamic(this, &AFPSProjectile::OnHit);

增加准星(HUD类)

// 将在屏幕中央绘制此项。
UPROPERTY(EditDefaultsOnly)
UTexture2D* CrosshairTexture;

void AFPSHUD::DrawHUD()
{
    Super::DrawHUD();

    if (CrosshairTexture)
    {
        // 找到画布中心。
        FVector2D Center(Canvas->ClipX * 0.5f, Canvas->ClipY * 0.5f);

        // 纹理维度进行一半偏移,使纹理中心和画布中心对齐。
        FVector2D CrossHairDrawPosition(Center.X - (CrosshairTexture->GetSurfaceWidth() * 0.5f), Center.Y - (CrosshairTexture->GetSurfaceHeight() * 0.5f));

        // 在中心点绘制准星。
        FCanvasTileItem TileItem(CrossHairDrawPosition, CrosshairTexture->Resource, FLinearColor::White);
        TileItem.BlendMode = SE_BLEND_Translucent;
        Canvas->DrawItem(TileItem);
    }
}

参考资料

UE4官网第一人称射击

你可能感兴趣的:(UE4,C++,学习篇,游戏开发,UE4)