虚幻4---打造3D人物关卡demo

来源:互联网 发布:php 微信群发接口 编辑:程序博客网 时间:2024/05/22 12:00

一. 引擎平台
Unreal4.14,虚幻引擎 4 是由游戏开发者制作并供游戏开发者使用的一整套游戏开发工具。虚幻引擎4支持高级的DirectX 11 & 12渲染功能,支持C++源代码(需要VC2015运行库的支持),制作从二维的移动平台游戏到主机平台的各种大作。
二. 实现功能
1. 场景切换:三个场景,绿洲,中心湖,室内房间
2. 不同天气:雾天,雨天
3. 人物切换:由于虚幻4不像unity,商店中的大部分人物模型需要付费使用,而网上找到的大部分模型不支持骨骼重定向与自带人物动物绑定,所以难以实现比较多的人物切换,只找到了一个可用的携带有基本动作的动漫人物。
4. 人物运动: 新的人物模型携带几个基本动作动画,在引擎中设定运动状态机后可正常运动。
5. 运动数据显示:加载虚拟运动数据,根据运动状态实时加载数据。
三. 实验内容
1. 关卡设计:

4个关卡:开始,绿洲,中心湖,房间,后三个关卡为开始关卡的子关卡
这里写图片描述
逻辑关系:
这里写图片描述
A. 开始关卡:
界面:
这里写图片描述
蓝图实现:Beginplay->在打开关卡时,加载一个MainMenuScreen类的视口端口在画面中(也就是加载开始菜单)
这里写图片描述
MainMenuScreen类蓝图设计:
这里写图片描述
外观设计:如图多个文本视图,6个按钮控件
文本视图设置:如实现 则其视图设置如下:
这里写图片描述这里写图片描述
蓝图设计:
实现加载子关卡功能:play1,play2,play3三个按钮对应加载3个场景
这里写图片描述
实现退出游戏功能:quit按钮执行游戏退出
这里写图片描述
实现修改分辨率功能:800*600,1280*720按钮实现修改分辨率,窗口大小
R.set Res XXX*XXX为命令行命令
这里写图片描述
B. Grass(绿洲)
界面:
这里写图片描述
世界大纲:
这里写图片描述
雾天场景:
在世界中,拖动引擎自带的视觉效果对象放入世界中

这里写图片描述
地貌:使用地貌工具进行绘画
这里写图片描述
其他内容由引擎自带内容,从模式中选取加载到关卡中
蓝图实现:按键P触发退出该场景,返回菜单
这里写图片描述

C. Middlelake(中心湖)
界面:
这里写图片描述
这里写图片描述
世界大纲:
这里写图片描述
雨天场景:由人物类蓝图实现,见下文
蓝图实现:同grass,按键P触发退出该场景,返回菜单
这里写图片描述

D. Room(房间) 该场景为素材库中加载而来
界面:
这里写图片描述
世界大纲:包含146个Actor
这里写图片描述
蓝图实现:同grass,按键P触发退出该场景,返回菜单
这里写图片描述
E. 关卡世界设置,选定c3d1GameMode,由自定义设定的游戏模式,选择pawnclass为第三人称角色控制,从而使游戏加载时,人物随之加载到场景中。
这里写图片描述

  1. 人物设计
    A. 组件:雨天粒子,人物模型,摄像机,data(动态加载模拟数据显示控件),人物动作继承characterMovement(引擎自带提供的动作)
    这里写图片描述
    B. Data控件
    外观:读取数据文件,实时显示,并根据数据改变右侧的进度条
    这里写图片描述
    蓝图设计:每一行有对应的设置数字与进度条的函数及变量
    这里写图片描述
    以head为例:
    在进度条的详细窗口中,绑定变量headhp与加载百分比
    设置进度条的背景图与加载图
    这里写图片描述这里写图片描述
    setheadhp读入一个浮点数,设置浮点数变量headhp(0-1)作为进度条的加载百分比,从而改变进度条的长度
    setheadnumber读入一个字符串,设置文本变量head,改变显示的数字
    这里写图片描述
    这里写图片描述

C. 人物蓝图:
联合C++代码控制蓝图:设置人物类代码

c3d1Character.h: #pragma once#include "GameFramework/Character.h"#include "c3d1Character.generated.h"UCLASS(config=Game)class Ac3d1Character : public ACharacter{    GENERATED_BODY()    /** Camera boom positioning the camera behind the character */    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))    class USpringArmComponent* CameraBoom;    /** Follow camera */    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))    class UCameraComponent* FollowCamera;public:    Ac3d1Character();    /** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)    float BaseTurnRate;    /** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)    float BaseLookUpRate;protected:    /** Resets HMD orientation in VR. */    void OnResetVR();    /** Called for forwards/backward input */    void MoveForward(float Value);    /** Called for side to side input */    void MoveRight(float Value);    /**      * Called via input to turn at a given rate.      * @param Rate  This is a normalized rate, i.e. 1.0 means 100% of desired turn rate     */    void TurnAtRate(float Rate);    /**     * Called via input to turn look up/down at a given rate.      * @param Rate  This is a normalized rate, i.e. 1.0 means 100% of desired turn rate     */    void LookUpAtRate(float Rate);    /** Handler for when a touch input begins. */    void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);    /** Handler for when a touch input stops. */    void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);protected:    // APawn interface    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;    // End of APawn interfacepublic:    FTimerHandle timerHandle[360]; //设置定时器,根据读取数据,实时加载数据,数据有360组    FString num;//暂存数字作为传递给显示函数    int32 count=0;//定时器计数    FString str;    FString tmphead[7][360];//存储温度及出汗数据    FString tmptime[360];//存储时间数据    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Controller)    FString FileName = FString("1.dat");//加载的默认数据,可在蓝图中修改//以下为相关各部位数据显示的变量,在蓝图中绑定为各进度条的加载百分比    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Controller)        FString headhpnumber;    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Controller)        FString trunkhpnumber;    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Controller)        FString sweathpnumber;    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Controller)        FString armhpnumber;    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Controller)        FString leghpnumber;    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Controller)        FString foothpnumber;    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Controller)        FString handhpnumber;    UFUNCTION(BlueprintImplementableEvent, Category = "SplineMesh")        void PrintMessage(const FString &Message);    UFUNCTION(BlueprintImplementableEvent, Category = "SplineMesh")        void Changehead(const FString &Message);//以下为进度条设置函数,在蓝图中重载    UFUNCTION(BlueprintImplementableEvent, Category = "SplineMesh")        void Changetrunk(const FString &Message);    UFUNCTION(BlueprintImplementableEvent, Category = "SplineMesh")        void Changearm(const FString &Message);    UFUNCTION(BlueprintImplementableEvent, Category = "SplineMesh")        void Changehand(const FString &Message);    UFUNCTION(BlueprintImplementableEvent, Category = "SplineMesh")        void Changeleg(const FString &Message);    UFUNCTION(BlueprintImplementableEvent, Category = "SplineMesh")        void Changefoot(const FString &Message);    UFUNCTION(BlueprintImplementableEvent, Category = "SplineMesh")        void Changesweataccu(const FString &Message);//gethead函数读取数据并设置定时器    UFUNCTION(BlueprintCallable, Category = "SplineMesh")        void Gethead();    UFUNCTION(BlueprintCallable, Category = "SplineMesh")        void clearclock();//清除定时器    /** Returns CameraBoom subobject **/    FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }    /** Returns FollowCamera subobject **/    FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }};C3d1character.cpp:#include "c3d1.h"#include "Kismet/HeadMountedDisplayFunctionLibrary.h"#include "c3d1Character.h"#include <windows.h>#include <iostream>#include <ctime> #include <string>using namespace std;Ac3d1Character::Ac3d1Character(){    // Set size for collision capsule    GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);    // set our turn rates for input    BaseTurnRate = 45.f;    BaseLookUpRate = 45.f;    // Don't rotate when the controller rotates. Let that just affect the camera.    bUseControllerRotationPitch = false;    bUseControllerRotationYaw = false;    bUseControllerRotationRoll = false;    // Configure character movement    GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...       GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate    GetCharacterMovement()->JumpZVelocity = 600.f;    GetCharacterMovement()->AirControl = 0.2f;    // Create a camera boom (pulls in towards the player if there is a collision)    CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));    CameraBoom->SetupAttachment(RootComponent);    CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character       CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller    // Create a follow camera    FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));    FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation    FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm    // Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character)     // are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)}//////////////////////////////////////////////////////////////////////////// Inputvoid Ac3d1Character::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent){    // Set up gameplay key bindings    check(PlayerInputComponent);    PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);    PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);    PlayerInputComponent->BindAxis("MoveForward", this, &Ac3d1Character::MoveForward);    PlayerInputComponent->BindAxis("MoveRight", this, &Ac3d1Character::MoveRight);    // We have 2 versions of the rotation bindings to handle different kinds of devices differently    // "turn" handles devices that provide an absolute delta, such as a mouse.    // "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick    PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);    PlayerInputComponent->BindAxis("TurnRate", this, &Ac3d1Character::TurnAtRate);    PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);    PlayerInputComponent->BindAxis("LookUpRate", this, &Ac3d1Character::LookUpAtRate);    // handle touch devices    PlayerInputComponent->BindTouch(IE_Pressed, this, &Ac3d1Character::TouchStarted);    PlayerInputComponent->BindTouch(IE_Released, this, &Ac3d1Character::TouchStopped);    // VR headset functionality    PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &Ac3d1Character::OnResetVR);}void Ac3d1Character::OnResetVR(){    UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();}void Ac3d1Character::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location){    // jump, but only on the first touch    if (FingerIndex == ETouchIndex::Touch1)    {        Jump();    }}void Ac3d1Character::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location){    if (FingerIndex == ETouchIndex::Touch1)    {        StopJumping();    }}void Ac3d1Character::TurnAtRate(float Rate){    // calculate delta for this frame from the rate information    AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());}void Ac3d1Character::LookUpAtRate(float Rate){    // calculate delta for this frame from the rate information    AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());}void Ac3d1Character::MoveForward(float Value){    if ((Controller != NULL) && (Value != 0.0f))    {        // find out which way is forward        const FRotator Rotation = Controller->GetControlRotation();        const FRotator YawRotation(0, Rotation.Yaw, 0);        // get forward vector        const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);        AddMovementInput(Direction, Value);    }}void Ac3d1Character::MoveRight(float Value){    if ( (Controller != NULL) && (Value != 0.0f) )    {        // find out which way is right        const FRotator Rotation = Controller->GetControlRotation();        const FRotator YawRotation(0, Rotation.Yaw, 0);        // get right vector         const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);        // add movement in that direction        AddMovementInput(Direction, Value);    }}void Ac3d1Character::Gethead2()//加载进度条,实现改变{    UWorld* World = GetWorld();    World->GetTimerManager().ClearTimer(timerHandle[count]);    num = FString(tmphead[0][count]);    Changehead(num);//head数据变化    num = FString(tmphead[1][count]);    Changetrunk(num); //trunk数据变化    num = FString(tmphead[2][count]);    Changearm(num); // arm数据变化    num = FString(tmphead[3][count]);    Changehand(num); //hand数据变化    num = FString(tmphead[4][count]);    Changeleg(num); //leg数据变化    num = FString(tmphead[5][count]);    Changefoot(num); //foot数据变化    num = FString(tmphead[6][count]);    Changesweataccu(num); //weataccu数据变化    count++;}void Ac3d1Character::Gethead(){    count = 0;    FString gameDir = FPaths::GameDir();        FString AbsoluteFilePath = gameDir + "/" + FileName;    FFileHelper::LoadFileToString(str, *AbsoluteFilePath);//加载数据文件内容到str    int i = 368;//数据开头    i = i + 10;//head    FString s;    for (int k = 0; k < 7; k++)//读取温度数据到tmphead    {        int tm = i;        for (int j = 0; j < 360; j++)        {            s = "";            s = s + str[i] + str[i + 1] + str[i + 2] + str[i + 3] + str[i + 4] + str[i + 5] + str[i + 6] + str[i + 7];            tmphead[k][j] = s;            i += 73;        }        i = tm + 9;//开始下一项温度读取    }    i = 368;//时间    for (int j = 0; j < 360; j++)//读取时间数据到tmptime   {        s = "";        s = s + str[i] + str[i + 1] + str[i + 2] + str[i + 3] + str[i + 4] + str[i + 5] + str[i + 6] + str[i + 7];        tmptime[j] = s;        //PrintMessage(s);        i += 73;    }    UWorld* World = GetWorld();    for (int j = 0; j < 360; j++)//设置定时器,每个定时器在计时到时调用gethead2函数改变进度条,时间为读取到的tmptime。    {        s = tmptime[j];        float MyShinyNewFloat = FCString::Atof(*s);        World->GetTimerManager().SetTimer(timerHandle[j], this, &Ac3d1Character::Gethead2, MyShinyNewFloat, false);    }    for (int j = 0; j < 360; j++)    {        s = tmptime[j];        float MyShinyNewFloat = FCString::Atof(*s);//将数据转换为浮点型    }}void Ac3d1Character::clearclock()//清除定时器{    UWorld* World = GetWorld();    for (int j = 0; j < 360; j++)    {        World->GetTimerManager().ClearTimer(timerHandle[j]);        World->GetTimerManager().ClearTimer(trunktimerHandle[j]);    }}

蓝图设计:
获得人物携带的data显示控件:
这里写图片描述
以重载changehead为例:先将从函数传来的字符串设置为headhpnumber的值,然后通过getprogress获得使用的data控件,再根据这个值调用head的两个set函数,将进度条百分比设置为该值
这里写图片描述
按键WASD触发数据加载:
使用4个bool型变量表示WASD按键是否按下,松开时为真
这里写图片描述
按键时改变状态:其他三个按键相同
这里写图片描述
当四个键中,有一个键按下而其他按键松开时才触发数据加载函数,当有一个键没松开时,数据加载函数继续运行,当按键松开时是四个按键都松开的状态时才触发清除定时器函数
这里写图片描述
其他三个按键WSD蓝图相同
雨天场景实现:
在场景加载开始时,检测当前关卡名称,只有当前关卡为middlelake,则将雨天粒子设置为可见状态
这里写图片描述
雨天粒子:
这里写图片描述
在material中将材质设置成相应的sheet、drops、ripples材质,设置相关粒子发射数构成。

切换场景数据:通过不同按键设置不同的filename,从而实现数据文件的选择 这里写图片描述
切换人物模型:通过按键触发选择不同的人物mesh并设置相应的动作控制类
这里写图片描述
控制人物移动速度:
按键触发设置人物运动的最大运动速度,Q+50,E-50
这里写图片描述

D. 人物动作
状态机:默认情况到跳跃,跳跃到结束
这里写图片描述
设置两个变量判断是否在空中,以及人物速度
这里写图片描述
状态机规则:
Isinair为真时进入jumpstart,在jumpstart即将执行完时进去jumploop,知道isinair为假时,进入jumpend,在jumpend动作执行完后才进去idle/Run
Idle/Run:
通过speed来控制当前人物动作
Speed:0-300:行走;300-600:快走;600-800:奔跑
这里写图片描述
这里写图片描述
JumpStart:开始跳跃时播放跳跃动作
这里写图片描述
在Jumploop和jumpend中,由于动作的稀少,没有比较合适的动作,因此设置为站立状态
这里写图片描述
场景蓝图执行逻辑:
检测当前控制器是否为该模型,若是则通过isfalling函数设置isinair变量,根据当前人物移动速度设置speed
这里写图片描述

0 0