UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

立即归还,本文将总结所有这些整理UE4有关角色的网络格、动画、子弹类HUD一个简单的实现。

(五)角色加入网格

Character类为我们默认创建了一个SkeletaMeshComponent组件,所以我们只须要做的就是使用哪一个静态网格模型。接下来我们为我们的FPSCharacter类创建一个蓝图,这样我们能够简单的把资源指定给静态网格模型这里,而且方便以后操作加入的组件。

作为開始,我们首先要导入一个第三人称的静态网格模型。最后我们设置成两个网格,一个是我们自己看的,另外一个是其它人看到的。

1.加入一个完整的全身的网格。如今点击这里加载资源吧。

我把我们要用到的所有资源所有放进去了,GenericMale.fbx文件就是有全身网格的,HeroFPP.FBX是等下我们要用到的自己看自己仅仅有胳膊和武器的网格,Sphere.FBX是个球体网格模拟子弹,crosshair.TGA是瞄准的十字准心。FPP_Animations文件夹存放的是胳膊和武器的那个网格的用的的动画。这是我的文件夹结构,仅供參考。

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

大家把他们都加载进来吧,注意一点就是,注意加载所有。比方加载网格,须要勾选加载材质,加载动作的时候。要选择网格,例如以下:

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

好了。关于资源加载的问题,就一次性说清,以后就不说了。

2.在蓝图目录内,新建蓝图

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

这里注意。在下拉框中选择FPSCharacter,使其作为蓝图的父类,给蓝图命名为“BP_FPSCharacter”,打开它。

3.选中Mesh。指定网格,并把Mesh的z轴值改为-88

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTcwNzA3Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

完毕以后就应该是这样了。为什么是-88?由于是已经调整好的数值,当使用自己的网格模型时。须要自己调整。终于目标是 使得网格被外面的胶囊组件包裹,而且方向为箭头所指向的方向。这将会使得模型在世界中正确行走,方向正常。能够直接在视图中调整,也能够直接设置数值。

4.编译保存蓝图,如今,我们要告诉我们的游戏模型使用最新我们创建的蓝图类来作为游戏角色的pawn物体。而不是我们之前创建的父类:FPSCharacter。返回VS,在模式的CPP文件构造函数中,删除

DefaultPawnClass = AFPSCharacter::StaticClass();

并加入例如以下代码:

AMyNewFPSGameMode::AMyNewFPSGameMode(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
//DefaultPawnClass = AMyNewFPSCharacter::StaticClass(); static ConstructorHelpers::FObjectFinder<UBlueprint> PlayerPawnObject(TEXT("Blueprint'/Game/Blueprints/BP_FPSCharacter.BP_FPSCharacter'"));
if (PlayerPawnObject.Object != NULL)
{
DefaultPawnClass = (UClass*)PlayerPawnObject.Object->GeneratedClass;
}
}

(这里提前说一下,大家无视我的类名,依照自己的来就可以)

   这里有很重要的一个知识点:在C++中引用蓝图(这样。就能够打通C++和蓝图了!

)。更准确的说应该是引用资源。这里的蓝图是以资源出现,等下我们也会发如今引用十字瞄准点的时候,使  用的是相同的方法,那就是:

static ConstructorHelpers::FObjectFinder<UBlueprint> PlayerPawnObject(TEXT("Blueprint'/Game/Blueprints/BP_FPSCharacter.BP_FPSCharacter'"));

TEXT里面的是资源的路径。获取资源路径有个小技巧,就是在内容浏览器中右键资源,选中复制引用命令,就会把详细的位置拷贝到剪贴板中了。

5.回到编辑器。选择编译,等待编译成功进入游戏測试。假设你移动摄像机。你会发现角色的影子,按下F1+Shift键,来获得鼠标指针。点击上面的弹出。这
 时候就能够在世界中任意的移动摄像机来看到角色的网格。

(六)更改摄像机试图(加入摄像机组件)

 
  
 在上一节的结尾。默认的摄像机是在网格的脖子里,如今我们来创建一个正确的摄像机。而且能够设置摄像机的一些属性比方位置和视图。我们通过给我们的FPSCharacter类加入一个摄像机组件来完毕(CameraComponent )。首先。我们为FPSCharacter加入一个属性来引用摄像机组件。

1.在角色.h文件中面加入以下的代码来加入一个公有变量FirstPersonCameraComponent。

/** First person camera
* 为摄像机新建变量,引用摄像机。在构造函数中做初始化------C++中加入组件。。蓝图中赋值。
*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
TSubobjectPtr<UCameraComponent> FirstPersonCameraComponent;

2.我们在FPSCharacter的构造函数中创建真正的组件,在FPSCharacter的构造函数中加入例如以下代码,来创建一个摄像机组件而且把他依附到胶囊组件上。

AMyNewFPSCharacter::AMyNewFPSCharacter(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
/********************创建、初始化摄像机********************************/
//创建摄像机组件
FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
FirstPersonCameraComponent->AttachParent = CapsuleComponent; // 摄像机的位置略微比眼睛要高
FirstPersonCameraComponent->RelativeLocation = FVector(0, 0, 50.0f + BaseEyeHeight);
// 同意玩家控制旋转
FirstPersonCameraComponent->bUsePawnControlRotation = true;
}

3.我们来调整摄像机的位置到眼睛的位置,在蓝图中也能够作调整,这里仅仅用调整他的位置信息,不用调整旋转。由于旋转会被鼠标改变。这部分代码就是上面的下两行。

4.好了。进游戏測试吧,摄像机应该在角色的头上,所以当你向下看的时候。将会看到角色的头部。

(七)加入第一人称网格

常规的FPS要准备和处理两套网格,一套是其它人看到的自己,可是对于自己来说它是隐藏的。这个就是全身的网格;另一种是仅仅有武器和手臂的网格,他们要依附在摄像机上。当玩家是第一人称的时候才被看到。

为了实现这个。我们首先要保持现有的网格,给它命名为“Mesh”。而且为我们的第一人称网格准备一个新的静态网格模型。

1.角色的.h文件里新建变量来引用新的网格。

/**
* 出生的时候的网格,仅仅有手臂和武器。 也是加入一个变量引用新的网格
*/
UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
TSubobjectPtr<USkeletalMeshComponent> FirstPersonMesh;

2.在构造函数中。加入例如以下代码来创建配置网格

///********************创建、初始化仅仅有手和武器的网格********************************/
//// 创建一个网格组件。他仅仅有手臂和武器
FirstPersonMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
FirstPersonMesh->SetOnlyOwnerSee(true);// 仅仅仅仅有这个Pawn才干够看到
FirstPersonMesh->AttachParent = FirstPersonCameraComponent;
FirstPersonMesh->bCastDynamicShadow = false;
FirstPersonMesh->CastShadow = false; ///********************除了自己。其它人看到全身*******************************/
//// 除了自己其它人都能看到
Mesh->SetOwnerNoSee(true);

上面其一部分代码中。说明了只唯独这个Pawn才干够看到。依附到第一人称摄像机,取消阴影;后一部分代码实现的功能呢,看凝视把。

3.编译C++代码。打开BP_FPSCharacter 蓝图,选择FirstPersonMesh组件。右面Detail面板中指定。

调整其位置属性为:{240,0,35},旋转属性{-180,
50, -180}.最后应该得到这么一张图

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

OK,进入游戏測试吧,

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

F1+Shift
而且选择弹出鼠标,这是你就不会再占有角色了,这个时候,你能够任意走动,而且看到两个人称的网格.

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

(八)加入弹药。实现射击

  
既然已经创建了角色,那我们给角色实现一个简单的武器,一枚简单的长得非常像手榴弹的子弹将会从屏幕中心射出,直到他碰到世界里面的物体。才会停下来。

接下来我们便加入输入的事件,事件映射,而且为子弹创建一个新的类。

1.处理输入。这里就不赘述,简述例如以下:加入事件映射。Fire,鼠标左键。

2.加入子弹类,使用UE4的C++类向导。相同简述:父类为Actor,命名FPSProjectile。

3.首先。我们应该确定一个简化表示用于碰撞模拟的物理对象。在这里,我们加入一个球体组件USphereComponent,在.h文件中面定义变量:

/** 胶囊碰撞组件 */
UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
TSubobjectPtr<USphereComponent> CollisionComp;

4.在CPP的构造函数里面加入组件,我们将把他作为根组件,由于我们要模拟它,而且在蓝图里面稍后为他加入可视化组件。

AFPSProjectile::AFPSProjectile(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
// 使用球体代表子弹
CollisionComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
CollisionComp->InitSphereRadius(15.0f);
RootComponent = CollisionComp;
}

这里是第二次在C++里面直接加入组件了。总结一下过程就是:声明变量--加入组件!

 5.UE4里面有一个自带的组件叫做子弹移动组件ProjectileMovementComponent ,他能够用于简单的弹道式的移动,我们把它加入到子弹类里面。

(1)在.h里面加入变量

/**子弹移动组件 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Movement)
TSubobjectPtr<class UProjectileMovementComponent> ProjectileMovement;

(2).cpp构造函数里面加入

// 使用子弹移动组件ProjectileMovementComponent控制子弹
ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileComp"));
ProjectileMovement->UpdatedComponent = CollisionComp;
ProjectileMovement->InitialSpeed = 3000.f;
ProjectileMovement->MaxSpeed = 3000.f;
ProjectileMovement->bRotationFollowsVelocity = true;
ProjectileMovement->bShouldBounce = true;
ProjectileMovement->Bounciness = 0.3f;

6.往后想一想,我们还须要一个功能通过初速度设置来“启动”我们的弹丸。我们自己定义一个函数来处理他。首先.h里面声明一个公有函数:

/** 子弹初速度*/
void InitVelocity(const FVector& ShootDirection);

cpp里面加入实现函数

void AFPSProjectile::InitVelocity(const FVector& ShootDirection)
{
if (ProjectileMovement)
{
// set the projectile's velocity to the desired direction 在所需方向上设置子弹的速度
ProjectileMovement->Velocity = ShootDirection * ProjectileMovement->InitialSpeed;
}
}

7.既然速度已经制定了,接下来我们仅仅须要设置一个启动的方向。首先在角色类中加入函数处理输入:

.h:

void OnFire();

.cpp文件里加入实现函数,在实现这个函数的时候,有两点须要考虑:

(1)在哪里产生子弹

(2)产生什么样的子弹(即传入子弹的类)。

第一个问题。为了制定产生的位置,我们须要一个摄像机空间的偏移量作为能够编辑的參数,因此我们能够在角色蓝图BP_FPSCharacter 里面设置它,然后就能够依据这个数据来计算子弹的初始化速度。主要是第二个,这里也是一个重点,简单来说,它的实质是两个C++的类是什么样的关系,怎样通信!我们解决的办法是,在C++里面定义一个共同拥有变量,然后等下再蓝图里面指定它。

所以在.h里面加入这个共同拥有变量把~

角色.h

/***************************这两项要在蓝图里指定******************************************/
/** 须要实例化的子弹类 */
UPROPERTY(EditDefaultsOnly, Category = Projectile)
TSubclassOf<class AFPSProjectile> ProjectileClass; /** Gun muzzle's offset from the camera location
枪口到摄像机的位置偏移量*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
FVector MuzzleOffset;

解释一下变量前面的两个宏,里我们使用仅仅能在蓝图设置默认EditDefaultsOnly 的说明符,这就意味着你仅仅能在蓝图类里面设置子弹类为默认,而在不是蓝图的每个实例中.

OnFire将会包括下面几步:

  • 由于我们的子弹产生位置是由相机空间决定,所以在我们真正计算子弹位置之前须要查询摄像机的位置信息.
  • 尝试实例化子弹.
  • 使用我们定义的函数给子弹一个初始化的速度.

OK,最后就是这个函数的实现了。

void AMyNewFPSCharacter::OnFire()
{
// try and fire a projectile
if(ProjectileClass !=NULL)
{
// Get the camera transform
FVector CameraLoc;
FRotator CameraRot;
GetActorEyesViewPoint(CameraLoc, CameraRot); // MuzzleOffset is in camera space, so transform it to world space before offsetting from the camera to find the final muzzle position
FVector const MuzzleLocation = CameraLoc + FTransform(CameraRot).TransformVector(MuzzleOffset);
FRotator MuzzleRotation = CameraRot;
MuzzleRotation.Pitch += 10.0f;// skew the aim upwards a bit UWorld*const World = GetWorld();
if (World)
{
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = this;
SpawnParams.Instigator = Instigator;// spawn the projectile at the muzzle
AFPSProjectile*const Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams); if (Projectile)
{
// find launch direction
FVector const LaunchDir = MuzzleRotation.Vector();
Projectile->InitVelocity(LaunchDir);
}
}
}
}

这个函数有点复杂,得须要好好理解一下。最后注意在角色cpp里面加入头文件

#include "FPSProjectile.h"

8.编译代码,回到编辑器,最后一步为子弹创建蓝图加入网格,创建新的蓝图。父类FPSProjectile。蓝图命名BP_FPSProjectile。在蓝图里面手动加入静态网格组件。命名ProjectileMesh,在右面的Detail面板中指定Mesh值,并调整其大小为:0.09(x、y、z都是)。另外把子弹网格组件ProjectileMesh的碰撞关闭,由于我们使用球形碰撞体来检測碰撞而不是网格物体。

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTcwNzA3Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

9.接下来。我们就要为刚刚C++里面加入的两个共同拥有变量赋值了!打开角色蓝图,点击头上的ClassDefault,然后在右面。你就能够看到这两个变量了。

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

分别依照上面赋值!之后,进入游戏測试吧!

应该但是打出子弹了。

(九)设置子弹的碰撞和生命周期

如今。我们须要考虑两件事情

  • 我们打出的子弹如今是不会消失的。 Scene Outliner面板告诉了我们
  • 弹不会产生碰撞。
  第一件事。幸运的是,UE4全部的Actors都有一个生命的限制。被一个默认生命期限限制。所以在子弹的构造函数中加入例如以下代码控制生命,也能够在蓝图的default中手动加入。  
// 子弹生命周期(全部的Actor都有的參数)
InitialLifeSpan = 3.0f;

接下来。就要解决子弹的碰撞问题了。

这部分问题,我看到的材料有点复杂,理解的不是非常透彻。得多操作几遍才干熟悉,我会把英文原文附上。所以熟能生巧...

1.UE4有几个实用的碰撞渠道,并且还提供了一些我们能够定制的碰撞渠道,如今我们来自定义为弹丸碰撞渠道。这样场景中的一切都能够选择怎样在我们的游戏中和一个子弹的相互作用。

在引擎配置.ini( DefaultEngine.ini,位于FPSProject
> Config)的下方加入以下的代码:

 [/Script/Engine.CollisionProfile]
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1, Name=Projectile)

这实际上是重命名了通用的渠道为“Projectile”。我们要在本地代码中重命名它,来保证事情的持续性和可读性。

这实际上是重命名了通用的渠道为“Projectile”。我们要在本地代码中重命名它。来保证事情的持续性和可读性。

2.UE4也有一个功能叫做碰撞分布,实质上是引擎总体使用的预先捆绑的碰撞的设置。往后想一下,也许我们能够在我们的游戏有非常多类型的弹丸,假设保持一致的碰撞设置当中可能是easy出错的,所以我们定义为弹一个新的文件。

继续在DefaultEngine.ini,加入代码:

  +Profiles=(Name="Projectile", CollisionEnabled=QueryOnly,ObjectTypeName=Projectile, CustomResponses=( \
(Channel=Static, Response=ECR_Block), \
(Channel=PawnMovement, Response=ECR_Block), \
(Channel=Dynamic, Response=ECR_Block), \
(Channel=PhysicsBody, Response=ECR_Block), \
(Channel=VehicleMovement, Response=ECR_Block), \
(Channel=Destructible, Response=ECR_Block) \
))

This
profile means that the projectile will be blocked by Static Actors, Pawns, Dynamic Actors, Actors simulating Physics, Vehicles, and Destructible Actors. 这个分布意味着,子弹能够被静态物体,Pawns, Dynamic Actors,
Actors simulating Physics, Vehicles, and Destructible Actors等等这些物体阻挡。

3.如今我们来设置我们的子弹使用这个分布,在子弹构造函数中,加入以下代码:

	//使用自己定义的碰撞分布
CollisionComp->BodyInstance.SetCollisionProfileName("Projectile");

ok,编译一下代码吧。

(十)子弹和世界的物体交互

 既然我们已经能够发现我们子弹的碰撞相互作用,我们能够决定怎么对她做出反应。在我们的子弹碰撞设置中,我们已经设置了对块的相互碰撞,接下来我们要为子弹类加入一个叫做OnHit的函数来处理这些事件。

1.自己定义一个函数OnHit。在子弹的.h文件下加入声明

/** 当子弹碰到其它物体时被调用*/
UFUNCTION() //这个必须有
void OnHit(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);

2.cpp里面实现它

void AFPSProjectile::OnHit(AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
if (OtherActor && (OtherActor != this) && OtherComp)
{
OtherComp->AddImpulseAtLocation(ProjectileMovement->Velocity * 100.0f, Hit.ImpactPoint);
}
}

3.托付,如今我们须要把这个函数交给子弹的球形组件的OnComponentBeginOverlap 事件托付,所以在子弹的构造函数中继续加入以下代码:

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

最后,你的子弹构造函数应该是这个样子:

AFPSProjectile::AFPSProjectile(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
// 使用球体代表子弹
CollisionComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
CollisionComp->InitSphereRadius(15.0f);
RootComponent = CollisionComp;
//使用自己定义的碰撞分布
CollisionComp->BodyInstance.SetCollisionProfileName("Projectile");
//碰撞事件托付
CollisionComp->OnComponentHit.AddDynamic(this, &AFPSProjectile::OnHit); // 使用子弹移动组件ProjectileMovementComponent控制子弹
ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileComp"));
ProjectileMovement->UpdatedComponent = CollisionComp;
ProjectileMovement->InitialSpeed = 3000.f;
ProjectileMovement->MaxSpeed = 3000.f;
ProjectileMovement->bRotationFollowsVelocity = true;
ProjectileMovement->bShouldBounce = true;
ProjectileMovement->Bounciness = 0.3f; // 子弹生命周期(全部的Actor都有的參数)
InitialLifeSpan = 3.0f;
}

好咧。编译代码!

4.回到编辑器,为了有一个对照的东西,我们选择地面物体SM_Template_Map_Floor这个网格。然后复制一份,改变他的大小为{0.2, 0.2, 3.0},位置为:{-230,
0, 160}.接下来,在Detail面板中,找到Physical选项,勾选计算物理Simulate Physics.然后就開始測试吧!

5.我们測试的时候回遇到非常多问题。退出游戏。提示

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

不要害怕。我们更具这里的信息记录更改即可,一般就是说,某一个网格没有勾选物理选项。这里好像有个问题。就是最后提示地面要模拟物理个警告我们不用管它。否则,地面就直接掉下去了。測试到最后的结果是。我们能够用子弹把这个正方体打下去!

(十一)增添十字锚点

    UE4有一个基类HUD我们能够扩展。

1.新建一个类,父类HUD,命名FPSHUD

2.我们想要在屏幕的*画一个十字的瞄准图片,首先我们加入对贴图资源的引用。事实上引用方法和蓝图一样。

(1)新建一个变量来引用它,在HUD的.h文件中面加入变量私有的即可:

private:
/**瞄准十字贴图 */
UTexture2D* CrosshairTex;

(2)我们在构造函数中引用资源,提醒一下,能够在内容浏览器中通过右键复制引用的方式找到资源的位置.

AFPSHUD::AFPSHUD(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
// 引用赋值
static ConstructorHelpers::FObjectFinder<UTexture2D> CrosshairTexObj(TEXT("Texture2D'/Game/Texture/crosshair.crosshair'"));
CrosshairTex = CrosshairTexObj.Object;
}

3.HUD基类有一个我们能够重写的虚函数叫做DrawHUD。来添加我们自己定义的须要往屏幕上加入的内容。我们如今来重写它!

HUD.H里面加入

virtual void DrawHUD() OVERRIDE;

cpp里面实现

void AFPSHUD::DrawHUD()
{
Super::DrawHUD(); // Draw very simple crosshair // 找到屏幕可绘区域的中心
FVector2D Center(Canvas->ClipX *0.5f, Canvas->ClipY *0.5f); //计算一下偏移
FVector2D CrosshairDrawPosition((Center.X-(CrosshairTex->GetSurfaceWidth()*0.5)),(Center.Y - (CrosshairTex->GetSurfaceHeight()*0.5f))); // 画出来
FCanvasTileItem TileItem(CrosshairDrawPosition, CrosshairTex->Resource, FLinearColor::White);
TileItem.BlendMode = SE_BLEND_Translucent;
Canvas->DrawItem(TileItem);
}

3.在游戏模式的构造函数里面加入

HUDClass = AFPSHUD::StaticClass();
AMyNewFPSGameMode::AMyNewFPSGameMode(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
//DefaultPawnClass = AMyNewFPSCharacter::StaticClass(); static ConstructorHelpers::FObjectFinder<UBlueprint> PlayerPawnObject(TEXT("Blueprint'/Game/Blueprints/BP_FPSCharacter.BP_FPSCharacter'"));
if (PlayerPawnObject.Object != NULL)
{
DefaultPawnClass = (UClass*)PlayerPawnObject.Object->GeneratedClass;
} HUDClass = AFPSHUD::StaticClass();
}

注意要写上头文件。

好了。到了这一步,就能够測试了!应该没问题!

(十二)
给角色加入动画

 
 1.创建动画蓝图,命名Arms_AnimBP ,选择父类:AniInstance
 目标骨架为HeroFPP_Skeleton

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTcwNzA3Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

2.我们须要创建一个状态机来设置这些动画的状态和转化,可是要想清楚怎么样来驱动这个状态机。

这里我们须要处理两个事情:1.人物是不是在走路。人物是不是在空中。我们给动画蓝图加入两个变量来存储这些信息。很多其它其它创建的方法。能够參考蓝图文档。

接下来加入两个布尔变量:bIsRunning,bIsFalling 
 UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

3.接下来,我们看动画蓝图里面的第一张图表:事件图表

(1)图表中加入第一个事件节点: Event
Blueprint Update Animation

这个节点同意我们当动画更新是,更新我们设置的变量,他们是和整个游戏状态是同步的。

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

  (2)我们能够通过询问角色的CharacterMovementComponent角色移动组件来为我们的变量赋正确的数值。为了实现这一点,我们须要加入一个动画控制角色的引用。

加入节点:Try
Get Pawn Owner,连线:Cast to Character  (中文为:类型转换为Character)

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

(3)例如以下图,在拖出一个节点:中文叫做获得CharacterMovement,继续加入节点Get
Movement Mode.   UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

(4)如今我们能够查询CharacterMovementComponent's 组件的MovementMode 来设置bIsFalling 变量是不是真,当我们在降落的状态的时候。连出新节点: Equal
(Enum).(中文:等于枚举值),设置其属性为Falling,获得变量bIsFalling。最后连接,例如以下图 
 UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

(5)接着,为了决定我们是在行走或是在站立,我们须要获得角色的速度而且设置bIsRunning 为真。当然是在值大于零的时候。

反之,先获得速度,假设角色不是站立。那么速度数组的长度会大于零。

所以例如以下图,继续加入节点Vector
Length

最后的最后,蓝图张这个样子:

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTcwNzA3Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

4.接下来,来看动画蓝图的第二个图表:动绘图表

(1)右键,新建状态机。重命名为Arms State Machine.如上图连线。

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTcwNzA3Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

(2)双击ArmStateMachine状态机节点来编辑它的图表。

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

在这个图表中我们须要五个状态。接下来处理第一个状态

(1)图表右键,加入状态,命名为Idle,双击进入状态的图表.

(2)图表中右键。查找Idle,加入Play FPP_Idle节点,例如以下图连接:

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTcwNzA3Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

(3)OK。第一个状态加入成功,接下来,依照相同的方法加入另外的四个状态

  • Run
  • JumpStart
  • JumpEnd
  • JumpLoop
  最后效果:
UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTcwNzA3Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

(4)接下来,我们来加入状态之间的转换,事实上这部分,说白了。就是连线,加转换条件。

<1>Entry->Idle

<2>Idle->Run,双击这个线。在里面加入转换的条件

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

双击连线,进入转换规则的图表,从变量栏中拉出bIsRunning。并获得。然后依照下图链接

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

<3>Run->Idle

转换条件:

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTcwNzA3Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

<4>Idle->JumpStart

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTcwNzA3Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

<5>Run->JumpStart

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

<6>JumpStart->JumpLoop

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

这里有一点要注意:从JumpStart到JumpLoop发生在JumpStart立即就要完毕的时候。所以在转换的规则中,我们加入一个节点:FPP_JumpStart的剩余时间<=0.1的节点,然后如上图连接。

<7>JumpLoop->JumpEnd

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

<8>JumpEnd->Idle

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

(5)终于的动绘图表例如以下:    UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTcwNzA3Ng==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" style="font-family:sans-serif; font-size:15px; line-height:1.5">

5.联系动画蓝图和角色蓝图。(两个蓝图的连接!

(1)编译、保存动画蓝图

(2)打开角色蓝图BP_FPSCharacter

(3)看下图:

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

最后最后最后啦!!

。!測试你的游戏吧。没问题。

UE4的编程C++创建一个FPSproject(两)角色网格、动画、HUD、子弹类

好了,到眼下为止,我们的这个第一人称射击类游戏就算完毕了!

(十三)
总结一下今天

 
 
今天做了例如以下一些事情:

1.给角色加入网格,加入自己定义摄像机。调整视角,加入第二套网格

  2.加入弹药。实现射击
   (1)加入弹药类。实例化弹药
   (2) 子弹碰撞和生命周期
 3.加入HUD 十字瞄准点
 4.给角色加入动画。
 
  做了非常多事。事实上最重要的是。应该攻克了一些童鞋心中的疑惑,比方:
(一)C++和蓝图应该怎么互相有联系呢?
  答案:能够用蓝图来继承C++的类,这仅仅是他们联系的一张方式,以后,我们甚至能够自己加入节点,完好蓝图。
(二)C++怎样訪问蓝图
  答案:通过引用资源这样的方式
(三)C++也能够直接加入组件。方式是:
    1.加入变量
    2.构造函数中创建组件

第二部分:全篇总结


(一)整个流程:
第一步:创建project,并自己定义GameMode
    1.创建空白project
    2.设置启动关卡.
    3.自己定义GameMode
    4.改动启动游戏模式为GameMode

1.创建关卡
2.创建游戏模式
3.制作一个角色
4.控制输入:映射轴(键盘WASD--前进。鼠标X,Y--向上看,向右看),映射事件(Space--Jump)

还是那一套。进入游戏測试。

这里总结一下:前面这么多处理输入控制的函数,事实上每一类控制要想完毕都须要三部:

1.处理映射:在项目设置中处理映射。包含轴映射(键盘鼠标都能够)。事件映射。

1.加入函数:这里要在角色的.h和.cpp文件中都要加入,一个是声明一个是实现

2.函数和输入绑定!

这一步。在角色重写的那个设置玩家输入组件的函数里面实现。


5.给角色加入网格,加入自己定义摄像机。调整视角。加入第二套网格

6.加入弹药,实现射击
  (1)加入弹药类,实例化弹药
  (2) 子弹碰撞和生命周期
7.加入HUD 十字瞄准点
8.给角色加入动画。

(二)我已近把涉及到的这几个类传上去了,仅供參考:

    1.http://pan.baidu.com/s/1dDpOhsH
    2.大家也能够直接新建一个C++的第一人称模板类的项目,啥也别做。打开看看,事实上内容是差点儿相同的。


(三)最后的说明


  最后说明,博客的主人俺仅仅是一个大三的学生,这些是我花费了自己大量的课余时间整理的,制作分享。不会考虑不论什么商业因素,假设大家喜欢,欢迎大家支持,假设文中有错误。还望大家指出。我们一同学习一同进步。

如需转载,请注明作者,注明CSDN本文链接。希望大家能多多支持,以后不定期会更新一些更新的教程给大家!

版权声明:本文博客原创文章,博客,未经同意,不得转载。

上一篇:AngularJS动态设置CSS


下一篇:Codeforces Round #356 (Div. 2) C. Bear and Prime 100 水题