UE4 Demo总结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UE4 Demo总结相关的知识,希望对你有一定的参考价值。

参考技术A 一、项目概述

1.根据项目需求,我做了一个小游戏,小游戏的规则很简单,游戏开始时会有4个四处巡逻的AI,当发现玩家后会追上玩家然后自爆。

     玩家会扣一定的血量,当玩家的血量归零时,游戏就会失败。

2.场景中会放置一些金币,玩家拾取后会加分,当拾取所有金币后则游戏成功。

GameInstance这个类可以跨关卡存在,它不会因为切换关卡或者切换游戏模式而被销毁。

二、项目总结

1.制作该项目的具体步骤如下:

     a.首先需要制作游戏的开始界面,使用UMG进行设计,具体做法为:

          1.使用Border组件进行背景图片的设计

          2.使用Vertical Box组件进行选项框的设计。

          3.在设计好大小的Vertical Box中设计选项按钮。

          4.设计按钮的绑定事件,点击开始按钮则跳转到游戏,点击退出按钮则终止游戏进程。

     b.然后设计会四处巡逻的AI,并且发现玩家后会追向玩家:

          1.首先设计AI的结构,本项目中的AI是继承玩家Character的。

          2.继承好以后删除AI的FollowCamera组件和输入相关的蓝图。

          3.在AI头顶添加一个Widget组件来显示AI名字。

          4.设计AI的自动巡逻和跟随玩家的逻辑,利用蓝图来进行设计:

               a.首先为AI添加一个PawnSensing组件来设计AI的视野。

               b.当AI看到玩家时,获取当前玩家的位置,让AI移动到该位置。

               c.当AI成功追上玩家后,销毁AI并扣除玩家的HP

               d.当AI没有看到玩家时,会先获取一个随机的坐标值,然后让AI移动到该坐标。

     c.设计玩家逻辑:

          1.首先为玩家添加一个Widget组件来显示玩家的血条和分数。

          2.然后为玩家设计两个Int类型变量,分别为HP和Points

          3.设计拾取金币逻辑,即当玩家与金币碰撞后,Points就加1。

          4.设计每帧触发事件,即每帧判断当前HP和Points的值。

          5.若HP的值<=0,则显示游戏失败界面并退出游戏。

          6.若Points的值>3,则显示游戏成功界面并退出游戏。

     d.设计金币蓝图:

          1.金币蓝图的逻辑较为简单,就是当玩家碰撞到金币时就销毁金币Actor

          2.设计金币的样式,添加一个RotatingMovement组件来让金币自动旋转。

2.制作该项目过程中遇到的难点:

     1.设计开始界面时,还没点击开始游戏按钮,游戏进程就已经开始运行了?

          答:这个问题的原因主要是开始界面和游戏进程在一个关卡中,

              解决这个问题的方法有两种,一种就是将界面设计在另一个关卡中,当点击开始游戏按钮后就跳转到游戏进程关卡。

              还有一种方法就是在界面弹出后,主动暂停游戏进程,当点击开始游戏按钮后再恢复游戏进程。

     2.在设计玩家头顶的血条信息时,当第一个AI碰撞后,血条直接归0?

          答:这个问题的出现是类型转换的问题,由于血条使用的是ProgressBar组件,它的值是0到1的float类型的值。

              而之前设计的HP的值是0到100的Int类型的值,由于Int类型的值不存在小数运算,所以就会出现这个问题。

              解决这个问题的方法就是将HP转换成Float类型再进行运算。    

UE4 ShooterGame Demo的开火的代码

之前一直没搞懂按下鼠标左键开火之后,代码的逻辑是怎么走的,今天终于看懂了。但是我只是知道了代码怎么调用的,但是还没有深入看最后的开火函数的内容,我要继续研究一下ShooterWeapon.cpp里面的void AShooterWeapon::HandleFiring()方法

技术分享图片

ShooterCharacter.cpp

void AShooterCharacter::OnStartFire()
{
    AShooterPlayerController* MyPC = Cast<AShooterPlayerController>(Controller);
    if (MyPC && MyPC->IsGameInputAllowed())
    {
        if (IsRunning())
        {
            SetRunning(false, false);
        }
        StartWeaponFire();
    }
}
void AShooterCharacter::StartWeaponFire()
{
    if (!bWantsToFire)
    {
        bWantsToFire = true;
        if (CurrentWeapon)
        {
            CurrentWeapon->StartFire();
        }
    }
}

ShooterWeapon.cpp,其中Role==ROLE_Authority表示该程序运行在服务器。如果是客户端,则将调用ServerStartFire来调用服务端的StartFire方法。这是多人游戏中的机制

void AShooterWeapon::StartFire()
{
    if (Role < ROLE_Authority)
    {
        ServerStartFire();
    }

    if (!bWantsToFire)
    {
        bWantsToFire = true;
        DetermineWeaponState();
    }
}

 

void AShooterWeapon::DetermineWeaponState()
{
    EWeaponState::Type NewState = EWeaponState::Idle;

    if (bIsEquipped)
    {
        if( bPendingReload  )
        {
            if( CanReload() == false )
            {
                NewState = CurrentState;
            }
            else
            {
                NewState = EWeaponState::Reloading;
            }
        }        
        else if ( (bPendingReload == false ) && ( bWantsToFire == true ) && ( CanFire() == true ))
        {
            NewState = EWeaponState::Firing;
        }
    }
    else if (bPendingEquip)
    {
        NewState = EWeaponState::Equipping;
    }

    SetWeaponState(NewState);
}

 

void AShooterWeapon::SetWeaponState(EWeaponState::Type NewState)
{
    const EWeaponState::Type PrevState = CurrentState;

    if (PrevState == EWeaponState::Firing && NewState != EWeaponState::Firing)
    {
        OnBurstFinished();
    }

    CurrentState = NewState;

    if (PrevState != EWeaponState::Firing && NewState == EWeaponState::Firing)
    {
        OnBurstStarted();
    }
}

 

void AShooterWeapon::OnBurstStarted()
{
    // start firing, can be delayed to satisfy TimeBetweenShots
    const float GameTime = GetWorld()->GetTimeSeconds();
    if (LastFireTime > 0 && WeaponConfig.TimeBetweenShots > 0.0f &&
        LastFireTime + WeaponConfig.TimeBetweenShots > GameTime)
    {
        GetWorldTimerManager().SetTimer(TimerHandle_HandleFiring, this, &AShooterWeapon::HandleFiring, LastFireTime + WeaponConfig.TimeBetweenShots - GameTime, false);
    }
    else
    {
        HandleFiring();
    }
}

 

void AShooterWeapon::HandleFiring()
{
    if ((CurrentAmmoInClip > 0 || HasInfiniteClip() || HasInfiniteAmmo()) && CanFire())
    {
        if (GetNetMode() != NM_DedicatedServer)
        {
            SimulateWeaponFire();
        }

        if (MyPawn && MyPawn->IsLocallyControlled())
        {
            FireWeapon();

            UseAmmo();
            
            // update firing FX on remote clients if function was called on server
            BurstCounter++;
        }
    }
    else if (CanReload())
    {
        StartReload();
    }
    else if (MyPawn && MyPawn->IsLocallyControlled())
    {
        if (GetCurrentAmmo() == 0 && !bRefiring)
        {
            PlayWeaponSound(OutOfAmmoSound);
            AShooterPlayerController* MyPC = Cast<AShooterPlayerController>(MyPawn->Controller);
            AShooterHUD* MyHUD = MyPC ? Cast<AShooterHUD>(MyPC->GetHUD()) : NULL;
            if (MyHUD)
            {
                MyHUD->NotifyOutOfAmmo();
            }
        }
        
        // stop weapon fire FX, but stay in Firing state
        if (BurstCounter > 0)
        {
            OnBurstFinished();
        }
    }

    if (MyPawn && MyPawn->IsLocallyControlled())
    {
        // local client will notify server
        if (Role < ROLE_Authority)
        {
            ServerHandleFiring();
        }

        // reload after firing last round
        if (CurrentAmmoInClip <= 0 && CanReload())
        {
            StartReload();
        }

        // setup refire timer
        bRefiring = (CurrentState == EWeaponState::Firing && WeaponConfig.TimeBetweenShots > 0.0f);
        if (bRefiring)
        {
            GetWorldTimerManager().SetTimer(TimerHandle_HandleFiring, this, &AShooterWeapon::HandleFiring, WeaponConfig.TimeBetweenShots, false);
        }
    }

    LastFireTime = GetWorld()->GetTimeSeconds();
}

 

以上是关于UE4 Demo总结的主要内容,如果未能解决你的问题,请参考以下文章

UE4项目界面基础知识总结(三)

UE4基础知识总结

UE4异步操作总结转载

UE4基础知识总结(五)

UE4 代码总结

UE4基础知识总结(四)