没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
蓝图与.C+
它们如何配合在一起,以及为什么您应该同时使用这两种
观看视频:https://youtu.be/VMZftEVDuCE(47分钟)
这不是一个决定。了解是什么使
C++
和蓝图与众不同,它们有什么共同点,以及如何有效地将它们一起使用。我们还将学习一两件关于性能优化
和一些基本软件设计概念的知识。
内容表
介绍
共同点
设计理念:高层次与低层次
设计示例:武器系统
设计概念:脚本与编程
C++和 BP 作为编程和脚本语言
本次讨论的范围:C++与英国石油公司重叠的地方
性能:比较编制的C++和BP
性能:结论和分析
项目组织:类设计
设计概念:类型和依赖性
项目组织:C++模块
项目组织:BP 到C++依赖关系
设计示例:从 BP 到C++的重构
设计示例:在C++中做所有事情
设计示例:基本C++ / BP 插话
传统编程/脚本拆分
设计示例:C++中的蓝图功能库
主要活动:C++与蓝图
BP 优势:资产、视觉效果、脚本事件
BP 优点:易用性
C++优点:性能、基本代码
C++优点:发动机功能不暴露在 BP 中
C++优势:外部库
C++优点:差异和合并
个人喜好
结论
介绍
虚幻引擎为您提供了多个编程游戏选项:您可以使用C++,也可以使用虚幻蓝图系统。
C++和蓝图之间的一些区别是不言而喻的:有了C++,您使用通用的基于文本的编程语言编写代码。蓝图更直观,更具体地针对更高级的游戏编程:您
通过将表示事件、控制结构和函数调用的图形节点串在一起来编写代码,并通过编辑内对话来定义您的数据和界面,而不必使用精确的语法写出定义。
但是,除了这些明显的差异,还有一些更微妙的问题要问自己如何在虚幻中制作游戏。这不仅仅是:"我应该使用
C++
还是应该使用蓝图?事实上,这是
一个错误的前提——虚幻的设计方式C++和蓝图是非常互补的。因此,更好的问题是:
"
使用
C++
在哪里有意义,使用蓝图在哪里有意义?
这就是我想研究的问题。一路上,我们将在引擎盖下查看,以便更好地了解蓝图脚本和原生代码之间的性能权衡,我们将讨论一些基本设计原则,并了
解项目通常是如何组织起来以有效利用这两种方法的。最后,我们将总结一下区分两者的一些东西。
但是在我们讨论这一切之前,我想先谈谈蓝图和C++有共同之处的一些事情。
共同点
如果我有一个自定义的演员类型,我希望它生成另一个演员,当游戏开始,这里是可能看起来像在C++:
void ACoyote::BeginPlay()
{
Super::BeginPlay();
if (bSpawnAnvil)
{
const FVector SpawnOffset(100.0f, 0.0f, 1500.0f);
const FVector SpawnLocation = GetActorTransform().TransformPosition(SpawnOffset);
const FTransform SpawnTransform(FQuat::Identity, SpawnLocation);
FActorSpawnParameters SpawnInfo;
SpawnInfo.Owner = this;
AAnvil* Anvil = GetWorld()->SpawnActor<AAnvil>(AnvilClass, SpawnTransform, SpawnInfo);
if (Anvil)
{
Anvil->BeginFalling();
}
}
}
蓝图中也有同样的事情:
这两个片段可能看起来非常不同,但他们给我们的结果完全相同。这就给我们带来了一个重要的点:您可以选择在C++中实现这样的示例,或者您可能
会使用蓝图。但无论哪种方式,你写代码。
您可能在编写该代码时没有键入任何实际语法,但您仍在规定程序在运行时的行为方式。而且,几乎可以肯定,您将在既定的软件框架内工作,创建新
类,并定义这些类的行为和相互交互方式。
换句话说,你将处理软件设计。
设计理念:高层次与低层次
因此,让我们来谈谈设计。
当你考虑一个复杂的软件,如视频游戏,它是有帮助的垂直思考。通常,您的目标是实现一些复杂、高水平的功能。您实际实现该目标的方式是将问题
分解为更基本的功能,这些功能可以在较低级别上实现。
如果你的游戏需要有一个超酷的火箭发射器,发射不同种类的弹丸,那些弹丸飞来飞去,击中的东西,并导致爆炸,这很酷...但你不能只是实现它无
处。你必须从某样东西中积累起来。
因此,您的游戏设计为您提供了高级功能需要是什么样子的定义,而您使用的引擎、框架或库为您提供了坚实的低级别基础。
因此,我们作为程序员的设计流程是填写两者之间所有缺失的细节。
设计示例:武器系统
因此,对于武器系统,我们可能首先定义一个简单的继承等级,将我们的最终类重新连接到发动机提供的类型。然后,我们想决定我们的每个自定义类
应该负责什么,他们需要如何与游戏中的其他对象交互,以及他们应该利用什么基础引擎功能。
例如:基地武器类可以处理玩家的输入,管理弹药,决定是否开火,并处理冷却。
对于运行线痕迹或生成弹丸,我们可能使用专门的子类:一个用于即时命中武器,一个用于弹丸武器。我们最后的、具体的武器等级将从那里延伸。
当然,继承并不是我们分解问题的唯一工具:我们还可以使用帮手对象或生成新角色,并且我们可以使用组件添加可组合的功能位。
在每个级别,我们将使用在引擎中实现的功能:
为了瞄准和发射我们的武器,我们将使用玩家Pawn的输入和控制功能。
为了检测我们是否击中了什么东西,我们将运行线跟踪或处理碰撞事件。
为了让演员在命中时做出响应,我们可能会使用内置的损坏系统。
在非常高的水平上,我们希望控制所有这些事物的外观和声音,这意味着我们将整合不同的资产,以利用引擎的渲染、动画、效果和音频系统。
有了虚幻,我们可以在蓝图中C++或蓝图中实现这些内容。例如,下面介绍我们如何将武器的线跟踪功能(即检查火线碰撞的射线广播)作为C++功
能:
void AWeapon::RunWeaponTrace(const FTransform& MuzzleTransform, float TraceDistance)
{
const FVector TraceStart = MuzzleTransform.GetLocation();
const FVector TraceEnd = TraceStart + (MuzzleTransform.GetUnitAxis(EAxis::X) * TraceDistance);
const FCollisionQueryParams QueryParams(TEXT("WeaponTrace"), false, this);
FHitResult Hit;
if (GetWorld()->LineTraceSingleByChannel(Hit, TraceStart, TraceEnd, ECC_WeaponFire, QueryParams))
{
if (Hit.Actor.IsValid())
{
const float DamageAmount = 1.0f;
const FVector ShotFromDirection = (TraceEnd - TraceStart).GetSafeNormal();
const TSubclassOf<UDamageType> DamageTypeClass = UDamageType_WeaponFire::StaticClass();
const FPointDamageEvent DamageEvent(DamageAmount, Hit, ShotFromDirection, DamageTypeClass);
Hit.Actor->TakeDamage(DamageAmount, DamageEvent, OwningController, this);
}
}
}
但是,我们可以同样轻松地在蓝图中实现完全相同的功能:
...无论哪种方式,我们利用相同的基础引擎系统在几乎相同的方式。
设计概念:脚本与编程
因此,对于我们最终设计中的一个功能,如武器,在抽象的不同层次上,有各种各样的问题需要回答——从非常低的水平,如
"
如何获得我需要处理的
记忆
"
,到非常高级的,比如
"
当抱着我的玩家收集损坏电源时,我会发光什么紫色阴影?
这些低级别的问题通常在引擎编程领域:所有的核心技术,使我们能够建立一个游戏,而不必太关心我们正在制作什么样的游戏。
当我们开始利用该核心技术来解决我们制作的特定游戏的根本问题,并构建使我们的游戏可玩的系统时,我们进入游戏编程。
然后是建立在这些系统的基础上,以充实玩家的分钟到分钟的经验,我们可以广泛地将其标记为脚本。脚本侧重于更高层次的问题,如:游戏的整体流
程和进度:不同游戏对象之间的高级别交互;以及具体、具体的游戏对象的外观、感觉和行为。
剩余41页未读,继续阅读
资源评论
一碗情深
- 粉丝: 5776
- 资源: 4
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功