虚幻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为第三人称角色控制,从而使游戏加载时,人物随之加载到场景中。
- 人物设计
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
- 虚幻4---打造3D人物关卡demo
- 虚幻4的关卡动态加载机制
- unity普通的3D地图+人物行走demo
- 虚幻4增强现实Demo
- 转:虚幻4引擎3d化UI教程
- 虚幻引擎4 DEMO打包下载
- Unreal Engine 4/虚幻4 视频纹理或者在关卡中播放视频
- Unreal Engine 4/虚幻4 流媒体纹理或者在关卡中播放流媒体
- 虚幻4动态加载画面(后台加载关卡)的实现
- 虚幻4引擎2d游戏基础
- 虚幻4 2d状态机动画基础
- Unreal Engine 4/虚幻 4 Demo下载地址
- 虚幻4引擎游戏Demo截图曝光 效果绝对震撼
- 虚幻4引擎公寓Demo图赏 真实度逆天
- 3D游戏中人物换装解决方案
- 3D游戏中人物换装解决方案
- 3D Demo
- QML 3D Demo
- 匿名对象
- 数据的更新
- LDAP网络用户账户
- android studio ndk 开发
- Windows+Python3下绘制Caffe训练日志中的Loss和Accuracy曲线图
- 虚幻4---打造3D人物关卡demo
- web标准
- Servlet从定向和路径匹配
- RecyclerView调用notifyDataSetChanged刷新,图片闪烁
- 例题4-1 古老的密码
- LeetCode 152. Maximum Product Subarray 解题报告
- sql sever数据库学习之-----数据更新与删除
- JS-闭包小解析
- Android开发:顶部&底部Tab导航栏实现(TabLayout+ViewPager+Fragment)