UE5俯视角游戏案例代码查看

2024-04-07 21:12

本文主要是介绍UE5俯视角游戏案例代码查看,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

对于初学者来说,UE的项目案例是我们入手的最佳途径,首先代码量少,思路清晰,还能给你提供一个清晰的结构。所以,我创建了一个俯视角的官方案例,来查看一下官方的代码学习一下。

首先打开引擎,启动引擎
在这里插入图片描述
然后创建一个示例,这是ue自带的案例
在这里插入图片描述
打开源代码,看到案例就几个文件
在这里插入图片描述

TopDownProject

这个项目名称我设置的是TopDownProject,TopDownProject.h和TopDownProject.cpp就是自动生成的项目主文件,它不需要我们自己创建,案例中里面这两个文件主要在里面增加了一个打印日志的宏,宏的第一个参数是定义了名称,可以不一样,但是相同的不需要定义两遍。这样方便后面查看哪里报错。

DECLARE_LOG_CATEGORY_EXTERN(LogTopDownProject, Log, All);
DEFINE_LOG_CATEGORY(LogTopDownProject)

定义完宏以后,使用,需要使用UE_LOG去打印,这里我将输入映射上下文设置为空指针,然后打印

	if(DefaultMappingContext == nullptr){UE_LOG(LogTemplateCharacter, Error, TEXT("当前操作映射上下文未设置"));}

可以看到在输出日志里面显示打印的内容
ELogVerbosity 枚举类型通常包含以下几个级别(具体级别可能因UE版本而异):

  • Verbose:最详细的日志级别,通常用于调试目的,包含大量的信息。
  • Log:常规日志级别,用于记录程序运行时的正常消息。
  • Warning:警告级别,用于记录可能导致问题的情况,但不一定是错误。
  • Error:错误级别,用于记录程序运行时遇到的严重问题或异常。
  • Display:用于显示给用户的信息,通常出现在用户界面上。
  • Fatal:致命错误级别,通常用于记录程序无法继续运行的情况。
    在这里插入图片描述

GameMode

案例重新创建了一个GameMode
在这里插入图片描述
它文件头设置了minimalapi,是为了加快编译,也无法作为蓝图父类,作为直接设置无法修改的类。

UCLASS(minimalapi)

在里面只是在构造函数内做了一些处理

public:ATopDownProjectGameMode();

因为无法在UE里面去修改内容,所以它在构造函数内,重新设置了默认Pawn类和玩家控制器类,可以通过上图看到。这里面也教给我们如何在C++里面去获取对应的蓝图的方法。你也可以看到官方开发人员也写的不标准,下面的NULL虽然也不会出错,但是推荐修改为nullptr(空指针)

ATopDownProjectGameMode::ATopDownProjectGameMode()
{// 使用我们自定义的 PlayerController classPlayerControllerClass = ATopDownProjectPlayerController::StaticClass();// 设置默认的控制Pawn为我们自定义的蓝图创建的Characterstatic ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/TopDown/Blueprints/BP_TopDownCharacter"));if (PlayerPawnBPClass.Class != nullptr){DefaultPawnClass = PlayerPawnBPClass.Class;}// 设置控制器为我们创建蓝图PlayerControllerstatic ConstructorHelpers::FClassFinder<APlayerController> PlayerControllerBPClass(TEXT("/Game/TopDown/Blueprints/BP_TopDownPlayerController"));if(PlayerControllerBPClass.Class != NULL){PlayerControllerClass = PlayerControllerBPClass.Class;}
}

剩下两个文件刚好是一个角色类和一个玩家控制类。

Character

在自定义角色类这里,类继承至ACharacter
在类里面创建了两个私有变量,用于存储相机和弹簧臂

private:/** Top down camera */UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))class UCameraComponent* TopDownCameraComponent;/** Camera boom positioning the camera above the character */UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))class USpringArmComponent* CameraBoom;

meta 这个参数用于控制属性在引擎和编辑器之间的交互方式。它还有其他设置的内容:

  • meta = (AllowPrivateAccess = “true”) 为变量即使是私有属性,也可以在UE里编辑器和访问
  • meta=(DisplayName=“自定义名称”) 用于在UE中自定义属性的显示名称
  • meta=(ToolTip=“这是一个提示信息”) 为属性提供编辑器中的工具提示,帮助解释属性的用途或如何设置它
  • meta=(EditCondition=“bSomeCondition”) 定义一个布尔表达式,用于控制属性是否可以在UE中编辑
  • meta=(ClampMin=“0.0”, ClampMax=“100.0”) 用于限制编辑器中可编辑属性的最小值和最大值
  • meta=(Category=“MyCustomCategory”) 指定属性在编辑器细节面板中所属的类别
  • meta=(AdvancedDisplay) 用于将属性标记为高级属性,使其在编辑器中默认隐藏,但可以通过点击“显示更多”或类似按钮来显示

然后又增加了两个对属性的获取公共函数,FORCEINLINE 内联函数是在调用点直接插入函数体代码的函数,而不是进行常规的函数调用。这可以减少函数调用的开销,从而可能提高执行速度,但也可能增加生成的代码大小。

	/** Returns TopDownCameraComponent subobject **/FORCEINLINE class UCameraComponent* GetTopDownCameraComponent() const { return TopDownCameraComponent; }/** Returns CameraBoom subobject **/FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }

在TopDownProjectCharacter的cpp文件中,只是在构造函数中初始化了一些内容,首先设置角色的胶囊体,然后设置角色移动相关的内容,并创建了相机弹簧臂和相机,最后设置帧回调。

ATopDownProjectCharacter::ATopDownProjectCharacter()
{// 设置角色胶囊体的尺寸GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);// 禁止相机随角色旋转bUseControllerRotationPitch = false;bUseControllerRotationYaw = false;bUseControllerRotationRoll = false;// Configure character movementGetCharacterMovement()->bOrientRotationToMovement = true; // 当设置为true时,角色的前方将自动朝向其移动的方向GetCharacterMovement()->RotationRate = FRotator(0.f, 640.f, 0.f); //控制角色旋转的速率GetCharacterMovement()->bConstrainToPlane = true; //当设置为true时,角色的移动将被约束在一个特定的平面上,通常是地面。GetCharacterMovement()->bSnapToPlaneAtStart = true; //游戏开始时,角色被吸附到地面,防止有空中坠落或者卡在地面的问题// 创建相机弹簧臂CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom")); //创建弹簧臂CameraBoom->SetupAttachment(RootComponent); //附加到根组件上CameraBoom->SetUsingAbsoluteRotation(true); // 不跟随根组件旋转CameraBoom->TargetArmLength = 800.f; //设置弹簧臂长度CameraBoom->SetRelativeRotation(FRotator(-60.f, 0.f, 0.f)); //设置弹簧臂的角度CameraBoom->bDoCollisionTest = false; // 设置为false,弹簧臂将不会与其他碰撞体产生交互// 创建相机TopDownCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("TopDownCamera")); //创建相机组件TopDownCameraComponent->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); //附加到弹簧臂上面TopDownCameraComponent->bUsePawnControlRotation = false; // 设置为false,相机的旋转不受角色控制// 激活帧更新,以便每帧更新光标PrimaryActorTick.bCanEverTick = true; //设置是否帧更新,如果当前值为false,即使设置其它,也不会被更新PrimaryActorTick.bStartWithTickEnabled = true; //游戏开始时,是否立即开始帧回调,如果bCanEverTick为false,也无法帧回调
}

这就是整个Character的内容,其实都是在蓝图里面都可以设置的东西,只不过修改成了使用c++去设置。

PlayerController

在PlayerController里面,首先增加了一个宏用于打印调试,和前面引擎文件里的一样,只是名称不一样,方便区分。

DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All);

然后在类内部设置了构造函数,定义了一些可编辑变量,比如点击地面时生成的箭头特效,设置一个时间阈值判断是点击事件还是长按事件,增强输入的上下文,还有点击的action(鼠标和触摸屏的)

public:ATopDownProjectPlayerController();/** 定义一个时间是长按还是点击 */UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)float ShortPressThreshold;/** 点击地面生成的箭头特效 */UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)UNiagaraSystem* FXCursor;/** MappingContext */UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))UInputMappingContext* DefaultMappingContext;/** 鼠标点击 Input Action */UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))UInputAction* SetDestinationClickAction;/** 触屏点击 Input Action */UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))UInputAction* SetDestinationTouchAction;

设置完成,可以在UE面板里面去修改对应的配置
在这里插入图片描述

接着覆盖BeginPlay函数,这个函数在开始运行时触发

virtual void BeginPlay();

在实现这里,获取增强输入的子系统,添加自定义的输入映射上下文

void ATopDownProjectPlayerController::BeginPlay()
{// Call the base class  Super::BeginPlay();//Add Input Mapping Contextif (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer())){Subsystem->AddMappingContext(DefaultMappingContext, 0);}
}

然后覆盖SetupInputComponent,这个函数允许我们自定义输入

virtual void SetupInputComponent() override;

在函数实现这里,绑定了InputAction的按下,悬停,抬起,取消四个事件(分别绑定了鼠标和触摸,兼容移动端)

void ATopDownProjectPlayerController::SetupInputComponent()
{// set up gameplay key bindingsSuper::SetupInputComponent();// Set up action bindingsif (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(InputComponent)){// Setup mouse input eventsEnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Started, this, &ATopDownProjectPlayerController::OnInputStarted);EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Triggered, this, &ATopDownProjectPlayerController::OnSetDestinationTriggered);EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Completed, this, &ATopDownProjectPlayerController::OnSetDestinationReleased);EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Canceled, this, &ATopDownProjectPlayerController::OnSetDestinationReleased);// Setup touch input eventsEnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Started, this, &ATopDownProjectPlayerController::OnInputStarted);EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Triggered, this, &ATopDownProjectPlayerController::OnTouchTriggered);EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Completed, this, &ATopDownProjectPlayerController::OnTouchReleased);EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Canceled, this, &ATopDownProjectPlayerController::OnTouchReleased);}else{UE_LOG(LogTemplateCharacter, Error, TEXT("'%s' Failed to find an Enhanced Input Component! This template is built to use the Enhanced Input system. If you intend to use the legacy system, then you will need to update this C++ file."), *GetNameSafe(this));}
}

接下来就是定义上面绑定的函数,以及对应所需的变量,就是通过这里实现的角色移动,接下来,我们看一下是如何实现移动的。

/** Input handlers for SetDestination action. */void OnInputStarted();void OnSetDestinationTriggered();void OnSetDestinationReleased();void OnTouchTriggered();void OnTouchReleased();private:FVector CachedDestination; //存储鼠标点击的位置bool bIsTouch; // 是否开启屏幕触摸float FollowTime; // 用于查看按住了多久

在鼠标按下时,会触发OnInputStarted()函数,这个函数内调用StopMovement()函数,停止角色移动。

void ATopDownProjectPlayerController::OnInputStarted()
{StopMovement();
}

鼠标按住,会触发角色跟随鼠标移动事件,在这种模式下,角色会直接朝向鼠标移动,不会自动躲避障碍物,我们看一下悬停回调函数的实现。
函数内先记录一下FollowTime 就是悬停按的时间,这个值会在鼠标抬起是使用。
然后通过鼠标位置发出射线去拾取点击的地面位置,然后通过角色位置和拾取位置计算朝向,根据朝向去移动。

void ATopDownProjectPlayerController::OnSetDestinationTriggered()
{// 长按时将帧的时间存储在变量内,用于鼠标抬起时判断是否为点击事件FollowTime += GetWorld()->GetDeltaSeconds();// 用于存储点击位置的数据信息FHitResult Hit;bool bHitSuccessful = false; //是否成功获取点击位置信息//bIsTouch是由屏幕触摸回调触发,并在触摸回调内设置其开启关闭,因为鼠标点击和触摸点击逻辑一样,只是获取点击地面位置的函数不一样。if (bIsTouch){bHitSuccessful = GetHitResultUnderFinger(ETouchIndex::Touch1, ECollisionChannel::ECC_Visibility, true, Hit);}else{bHitSuccessful = GetHitResultUnderCursor(ECollisionChannel::ECC_Visibility, true, Hit);}// 拾取到为止,从Hit内获取点击位置if (bHitSuccessful){CachedDestination = Hit.Location;}// 通过点击位置和角色位置计算出角色移动方向,并调用AddMovementInput移动。APawn* ControlledPawn = GetPawn();if (ControlledPawn != nullptr){FVector WorldDirection = (CachedDestination - ControlledPawn->GetActorLocation()).GetSafeNormal();ControlledPawn->AddMovementInput(WorldDirection, 1.0, false);}
}

AddMovementInput有三个值:

  • 方向向量(通常是一个FVector):这个参数定义了移动的方向。它可以是代表前后左右移动的二维向量,也可以是包含垂直移动的三维向量。
  • 缩放值(通常是一个浮点数float):这个参数用于调整移动的速度或幅度。通过改变这个值,你可以控制角色移动的快慢。
  • 强制标志(通常是一个布尔值bool):这个参数用于指定是否强制添加移动输入,即使某些条件不满足。它允许开发者在特定情况下覆盖正常的移动逻辑。
ControlledPawn->AddMovementInput(WorldDirection, 1.0, false);

最后我们看一下鼠标抬起事件,鼠标抬起事件首先判断鼠标悬停的时间,如果时间小于我们设置的ShortPressThreshold值,则代表当前属于点击事件,则可以触发自动寻路和播放粒子特效。如果时间大于,则代表属于鼠标悬停,角色跟随鼠标事件,不会触发自动寻路。在最后将FollowTime 设置为零。

void ATopDownProjectPlayerController::OnSetDestinationReleased()
{// 判断是否触发的点击事件,if (FollowTime <= ShortPressThreshold){// 使用函数库,将角色移动到目标位置UAIBlueprintHelperLibrary::SimpleMoveToLocation(this, CachedDestination);//使用Niagara生成生成粒子特效UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, FXCursor, CachedDestination, FRotator::ZeroRotator, FVector(1.f, 1.f, 1.f), true, true, ENCPoolMethod::None, true);}FollowTime = 0.f;
}

还有两个是触摸屏触发的事件,它内部只是设置bIsTouch布尔值,这个值为true代表是触摸屏触发的此事件,所以可以看到在悬停时将其设置为true,然后触发悬停事件,然后在抬起时将其设置为false。这样即使你这次是触摸屏触发的事件,在下一次修改为鼠标也是没问题的。

void ATopDownProjectPlayerController::OnTouchTriggered()
{bIsTouch = true;OnSetDestinationTriggered();
}void ATopDownProjectPlayerController::OnTouchReleased()
{bIsTouch = false;OnSetDestinationReleased();
}

弊端

由于此案例是一个教学案例,所以代码很精简,只实现了简单的功能,其也只适合制作单机游戏,如果将其设置为包含服务器的客户端运行的话,会发现它的自动寻路功能将会失效,那么我们还需要使用其它的方式实现。
在这里插入图片描述
接下来,我将在UE5 RPG的文章中实现可以在服务器上运行的自动寻路功能。

这篇关于UE5俯视角游戏案例代码查看的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/883688

相关文章

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(五):Blender锥桶建模

前言 本系列教程旨在使用UE5配置一个具备激光雷达+深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客往期教程: 第一期:基于UE5和ROS2的激光雷达+深度RG