掌握Unity 2D游戏开发-AI和状态机(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/mastering-unity-d-game-development-ai-and-state-m-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 13 分钟阅读 - 6211 个词 阅读量 0掌握Unity 2D游戏开发-AI和状态机(译文)
原文地址:https://www.codeproject.com/Articles/813160/Mastering-Unity-D-Game-Development-AI-and-State-M
原文作者:Simon Jackson
译文由本站 robot-v1.0 翻译
前言
Mastering Unity 2D Game Development – AI and State Machines
掌握Unity 2D游戏开发-AI和状态机 终于到了,我的第一个书名现在已经在Packt的发布网站和所有领先的在线书店上发布(可能还没有那么知名的??).如果您喜欢在这些摘录中看到的内容,那么您将喜欢整本书.以下是为您准备的商品概述.(It is finally here, my first title has now been published on Packt’s publishing site and all of the leading online bookstores (probably a few less reputable as well ??). If you like what you see in these snippets, they you are going to love the full book. Here’s an overview of what’s in store for you.) 此代码段的示例项目和代码可在此处找到:(The sample project and code for this snippet can be found here:) Mecanim状态机.zip(Mecanim State Machines.zip)
关于这本书(About the Book)
这本书对我来说是一个有趣的挑战,而且写的方式与我在博客中使用的风格相同.我一直觉得最好教育和向您展示,不仅是如何做事,而且为什么你应该以另一种方式做,如果有其他选择,我会指出.作为读者,您应该了解自己的选择(然后下定决心)(The book was an interesting challenge for me and is written with the same flair I use within my blog, I have always felt it’s better to educate and show you, not only how to do things but also why you should do it one way over another, plus if there are any alternatives, I’ll point them out. As a reader, you should be informed about your choices (and then make your own mind up) ).().) 通过其页面,您将构建一个RPG游戏框架,然后可以对其进行扩展和制作自己的游戏,目的是为您提供足够的提示,技巧和帮助,以构建您自己的成品游戏.(Through its pages, you will build an RPG game framework which you can then extend and make your own, the aim is to give you enough hints, tips and help to build your own finished game.) 标题应该是您期望的:(Here’s what you should expect from the title:)
- 贯穿Unity 4.3和2D游戏开发的新改进(以及其他所有功能,以防万一您错过了它)(A run through the new improvements in Unity 4.3 and 2D game development (plus everything else in case you missed it))
- 深入了解新的Sprite系统和动画改进功能(本章的第一章太大了,必须一分为二)(A deep dive in to the new Sprite system and the Animation improvements (the first of my chapters that got so big it had to be split in twain))
- 使用2D摄像机,场景和子画面分层以及一些高级编码技术,可以构建自己的RPG对话系统.(Working with 2D camera’s, scenes and sprite layering plus some advanced coding techniques which lead up to building your own RPG conversation system.)
- 我们涵盖了构建地图和探索系统的最终结论,即遇到了一些令人讨厌的地精,他们的牛排确实很卑鄙.(We cover building a map and exploration system with the eventual conclusion of running into some nasty goblins who have a really mean steak.)
- 如果您想购物,那么您来对地方了,我对这把可爱的1级剑感兴趣吗?学习构建购物系统,然后再退缩.(If shopping is your thing, you’ve come to the right place, can I interest you in this lovely lv 1 sword. Learn to build a shopping system and then head back out in to the fray.)
- 在第二章中,它的靴子也有两个很大的地方,必须在中间将其切断,其中包括回合制战斗系统,其中包括使用您可能从未考虑过的Mecanim(状态战斗机和AI有人吗? )(In the second chapter that also got two big for its boots and had to be severed right down the middle, we cover turn based battle systems, including some was to use Mecanim that you may have never considered before (State battle machines and AI anyone?))
- 完成游戏框架后,我们将看完您的标题并查看编辑器,以了解如何扩展它以帮助我们为我们构建游戏(编辑器脚本,美味),并提供有关启用应用内应用的深入报告购买正确的方式.(With the game framework done, we look at finishing your title and looking at the editor to see how we can extend it to help build our game for us (editor scripting, yummy), rounding up with an in depth report on enabling in-app purchasing the right way.)
- 最后,我们全面了解如何扩展和部署到平台上,并在序列化(保存和加载)方面提供帮助,使代码仅在特定平台或编辑器上运行,以及大量的营销提示与技巧.(Finally, we round up with a look at extending and deploying to platforms, cram packed with help on serialisation (saving and loading), making code only run on specific platforms or the editor and masses of hints and tips on marketing.) 我对这本书唯一的遗憾是它再大不过了(My only regret with this book is that it couldn’t be bigger) 在这些标题的页面中,有足够的信息可以让您90%拥有自己的游戏,您所要做的就是完成游戏并添加更多内容!(there is more than enough information within this titles' pages to get you 90% there with your own game, all you got to do is finish it and add lots more content!.) 与我所做的所有事情一样,如果您想对本书中的任何主题有更多的了解,请在我的博客上给我留言或发表评论,并且我乐于为该主题撰写更多内容.(As with everything I do, if there’s more you want to know on any subject within the book, drop me a line or comment on my blog and I’ll be more than happy to write even more on the subject.)
书够用了–我的摘录在哪里(Enough About the Book – Where’s My Snippet)
本系列的第二个片段比完整的片段更具讽刺意味,仅仅是因为这是一个有趣的主题,只有这本书通过完整的工作示例才算是真正的正义:(The second snippet in this series is more of a tease than a full snippet, simply because it’s such an interesting subject, only the book does it true justice with a full working example:)
Mecanim状态机(Mecanim State Machines)
(我仍然继续输入Mechanim并继续删除H,哈哈.)((I still keep typing Mechanim and keep having to delete the H, lol.)) 对于使用Mecanim玩过的任何人,您都会发现它是一个很棒的3D动画系统,可以使用装备和准备好的动画对3D模型进行动画处理,此外,它还可以将这些动画混合在一起以提供更逼真的视图.虽然从本质上讲,Mecanim只是具有精美图形界面的非常漂亮的状态机.在Unity 4.3中对其进行了增强,使其还包括2D Sprite动画.(For any of you who have played with Mecanim, you will have found it to be a great 3D animation system to animate your 3D models using rigs and prepared animations, plus it can blend those animations together to give a more realistic view. At its heart though, Mecanim is nothing more than a very fancy state machine with a wonderful graphical interface. It was they enhanced in Unity 4.3 to include 2D sprite animation as well.) 您可能没有意识到,您不必将Mecanim仅仅用于动画,几乎可以在需要状态机的任何情况下使用它,从游戏状态到AI机!每个人都有自己的实现类型以及自己的小技巧和窍门,以充分利用它们.(What you may not realise is that you don’t have to use Mecanim for just animation, you can use it for almost any scenario that requires a state machine, from Game state to even AI machines! Each have their own types of implementations and their own little tips and tricks to make the best of them.)
一个简单的游戏状态机(A Simple Game State Machine)
非动画Mecanim系统的最简单示例是游戏的战斗状态机,我们需要处理一些复杂的方法(主要是由于Mecanim处理当前状态的方式),但最终我们会获得更好的结果具有易于管理的界面的系统,(The simplest example of a non-animator Mecanim system is a game’s battle state machine, there are a few complexities to the approach (mostly due to the way Mecanim handles current state) that we need to handle but in the end we get a much better system with a easy to manage interface,)
如果我们尝试用代码创建一个简单的游戏状态系统,通常会导致复杂的(If we try to do a simple game state system in code, we usually end up with a complicated mess of) switch
要么(or) if
所有人都在争辩说清楚每次更新中应该发生的事情(它并不总是很混乱,但可以很容易地做到这一点).(statements all competing to figure out what it supposed to happen in each game update (it’s not always messy but it can easily get that way).)
假设我们有当前流程:(Say we have the current flow:)
在普通代码中,我们很可能以(In normal code, we would most likely start with an) Enum
每个状态的定义(或仅使用(definition for each state (or just use) string
如果您胆敢的话,例如:(s if you’re daring) like this:)
enum BattleState
{
Battle_start,
Intro,
Player_attack,
Opponent_attack,
Player_dead,
Opponent_dead,
Battle_result,
Battle_over
}
然后在更新外观中实现以下内容:(Then in the update look implement something like this:)
void Update () {
//wait loop when a pause is required
if (timer > 0)
{
timer -= Time.deltaTime;
return;
}
// Set the next state;
currentBattleState = nextBattleState;
//What to do in the current state and where to go next
switch (currentBattleState)
{
case BattleState.Battle_start:
playerHealth = 10;
opponentHealth = 10;
nextBattleState = BattleState.Intro;
break;
case BattleState.Intro:
timer = 3f;
nextBattleState = BattleState.Player_attack;
break;
case BattleState.Player_attack:
if (Input.GetKeyDown(KeyCode.Space))
{
opponentHealth -= 5;
if (opponentHealth <= 0)
{
nextBattleState = BattleState.Opponent_dead;
}
else if (playerHealth <= 0)
{
nextBattleState = BattleState.Player_dead;
}
else
{
nextBattleState = BattleState.Opponent_attack;
}
}
break;
case BattleState.Opponent_attack:
playerHealth -= Random.Range(0, 10);
if (opponentHealth <= 0)
{
nextBattleState = BattleState.Opponent_dead;
}
else if (playerHealth <= 0)
{
nextBattleState = BattleState.Player_dead;
}
else
{
nextBattleState = BattleState.Player_attack;
}
timer = 1f;
break;
case BattleState.Player_dead:
case BattleState.Opponent_dead:
timer = 3f;
nextBattleState = BattleState.Battle_over;
break;
case BattleState.Battle_result:
timer = 2f;
nextBattleState = BattleState.Battle_over;
break;
}
}
一旦我们想要添加一些更改,我们最终将在所有路径中进行拖曳,以检查我们所处的状态,所需的状态以及需要设置的标志. (根据我的经验,您最终还会受到意想不到的影响,导致您添加更多状态来跟踪不同的情况,并且通常使情况在未来变得更糟或更难诊断.(As soon as we want to add a little change, we end up trawling through all the paths to check what state we are in, to the state we need to be and what flags we need to set. (In my experience, you also end up with unintended effects that cause you to add more states to track different conditions and usually making things worse or harder to diagnose in the future.) )()) 您可以通过查看(You can see this more fully by checking out the)OldStyleStateMachine.cs(OldStyleStateMachine.cs)脚本附加到(script attached to the)战国机器(BattleStateMachine)示例场景中的GameObject带有可下载的项目.只需打开它即可查看基本示例(确保关闭Mecanim脚本).(GameObject in the example scene with the downloadable project. Just turn it on to see the basic example (ensuring you turn off the Mecanim script).) 确实是一个非常基本的示例,但是只需使用几个复杂的路径将其成像50倍,代码的每个部分都需要了解它周围的所有内容才能做出正确的决定,现在您可能会开始看到更大的图片.(A very basic example indeed, but just imaging it 50x bigger with several complicated paths, each part of the code needing to know everything around it in order to make the right decision, now you may start to see the larger picture.)
那么Mecanim为我们做了什么?(So What Has Mecanim Ever Done For Us?)
使用Mecanim本身来实现状态机的流程非常简单,实际上我们已经在上面进行了描述.以图片中的轮廓为例,我们可以将其转换为Mecanim设计板,如下所示:(Using Mecanim itself to implement the flow of the state machine is very simple, in fact we’ve practically drawn it above. Taking our outline in the image, we can convert this to a Mecanim design board looking something like this:)
我们将游戏状态设计流程复制为空的Mecanim状态,并向Animator添加了一些参数来跟踪运行状况,是否处于战斗状态以及是否表示发生了攻击.那么代码又如何,使用Mecanim如何简化呢?(We’ve replicated the flow of our game state design as empty Mecanim states and added some parameters to the Animator to track health, whether we are in battle and a trigger to denote an attack has occurred. So what about the code, how does using Mecanim simplify things?)
简而言之,它消除了代码中的所有选择和决定,现在所有这些选择和决定都移到了Mecanim中,我们只需要告诉Animator什么时候发生变化.如果我们随后将此Animator应用于(Putting it simply, it removes all the choice and decision from code, that is now all moved to Mecanim and we simply need to tell the Animator when something changes. If we then apply this Animator to the) BattleStateMachine GameObject
在我们的示例场景中,使用分配给controller属性的上述控制器,然后我们可以考虑通过脚本来利用它.(in our example scene, using the above controller assigned to the controller property, we can then look to exploit it through script.)
更好的是,任何状态都可以通过简单而快速的转换快速加入任何其他状态.(Even better, any state can be quickly joined to any other state with a simple and quick transition.)
仍在使用我们的(Still using our) Enum
和以前一样(这是代码的进行指南),我们的代码可以简化为:(as before (as it is the code’s guide to what is going on), our code is simply reduced to:)
void Update()
{
currentBattleState = battleStateHash[battleStateMachine.GetCurrentAnimatorStateInfo(0).nameHash];
switch (currentBattleState)
{
case BattleState.Battle_start:
playerHealth = 10;
opponentHealth = 10;
battleStateMachine.SetInteger("Player_health", playerHealth);
battleStateMachine.SetInteger("Opponent_health", opponentHealth);
battleStateMachine.SetBool("Battle_inprogress", true);
break;
case BattleState.Player_attack:
Attacking = false;
if (Input.GetKeyDown(KeyCode.Space) && !keyPressed)
{
keyPressed = true;
opponentHealth -= Random.Range(3, 5);
battleStateMachine.SetTrigger("Attack");
}
battleStateMachine.SetInteger("Opponent_health", opponentHealth);
break;
case BattleState.Opponent_attack:
keyPressed = false;
if (!Attacking)
{
playerHealth -= Random.Range(0, 10);
battleStateMachine.SetTrigger("Attack");
Attacking = true;
}
battleStateMachine.SetInteger("Player_health", playerHealth);
break;
case BattleState.Battle_result:
battleStateMachine.SetBool("Battle_inprogress", false);
break;
}
}
这从代码中消除了状态机的许多复杂性,您只需要声明您希望在每个门口发生的事情.(This removes a lot of the complexity for the state machine from the code and you simply need to state what you want to happen at each gate.) 我们需要了解一些陷阱,这主要与Mecanim的功能和速度有关:(There are a few gotchas we need to be aware of which are mainly to do with the power and speed of Mecanim:)
- Update的运行速度比Mecanim快,因此,如果更新代码中包含单个操作,则需要满足此要求(如一些示例所示)(Update runs faster than Mecanim, so if you have singular actions in your update code, you need to cater for this (as shown by a few)
private
布尔值)(booleans)) - 输入(如键盘)在多个更新循环中可能为true(因此,键盘输入为布尔值)(Inputs (like keyboard) can be true for several update loops (hence the boolean’s for keyboard input))
- Mecanim会完全按照您的指示进行操作,这可能会引起混乱,并且多个路径可能同时为真!(Mecanim will do EXACTLY what you tell it to, which can cause confusion and multiple paths can be true at the same time!)
现在故事快要结束了,您会注意到,在每次更新开始时,我们都会获得Animator的当前状态.问题在于Mecanim当前根本不使用状态名称,它实际上使用哈希机制来不仅跟踪Animator当前所处的当前状态,而且还跟踪其当前所处的状态生命中的确切点(如果您正在进行混合或动画处理,如果只需要状态,则用处较小.由于我们喜欢使用名称(当然,您也可以只使用哈希数字),因此我们需要对其进行缓存,在脚本中,我创建了一个字典,并以脚本开头将其缓存,如果您愿意,可以对其进行缓存在构建时.(Now that’s almost the end of the story as you will note that at the beginning of each update, we get the Animator’s current state. The problem is that Mecanim currently does not work with state names at all, it actually uses a hashing mechanism to track not only the current state the Animator is currently positioned at but also the exact point in the states life it’s currently up to (useful if you are doing blending or animation, less useful if you just want the state). As we like to work with names (optional of course, you can work with just the hashed numbers) we need to cache them, in the script I create a dictionary and cache them with the script starts, if you wished, you could cache them at build time.)
在测试中,我没有看到多少成功的例子,但是如果您有很多状态,可能需要考虑在构建时缓存状态名称.(In testing, I’ve not seen much of a hit but if you have a lot of states, it may be something to consider caching state names at build time.)
所以在这个例子中(So in the example, the)
Start
和(and)Awake
方法如下所示,以缓存状态名称和哈希键:(methods look as follows, to cache the state names and hash keys:)
Animator battleStateMachine;
private Dictionary<int, BattleState> battleStateHash = new Dictionary<int, BattleState>();
private BattleState currentBattleState;
void Awake()
{
//Get the Animator state machine, error if none found on this GO
battleStateMachine = (Animator)GetComponent(typeof(Animator));
if (!battleStateMachine || !battleStateMachine.runtimeAnimatorController)
{
Debug.LogError("State Machine Missing or not configured)");
}
}
void Start () {
//Cache all the hashes of the States in our State Machine (case sensitive!)
foreach (BattleState state in (BattleState[])System.Enum.GetValues(typeof(BattleState)))
{
battleStateHash.Add(Animator.StringToHash("Base Layer." + state.ToString()), state);
}
}
有点麻烦,但因为它是一件很小的事情,很容易使用.(It’s a little hassle but as it’s such a minor thing that’s easy to work with.) 正如您所希望看到的那样,此功能非常强大,并且通过Mecanim做出的复杂决策更容易实现,只是要意识到,强大的力量将带来巨大的责任!(As you can hopefully see, this is very powerful and makes complex decisions through Mecanim a lot easier to implement, just be aware that with great power comes great responsibility!) .(.) 本文仅真正介绍了将Mecanim用作纯状态机的可能性,在书中,我们探索了上述的完整系统,甚至深入研究了通过Mecanim实现的基本AI系统(This article truly only scratches the surface of what is possible with Mecanim using it as a pure state machine, in the book, we explore a full system such as the above and even delve in to a basic AI system implemented through Mecanim)
希望您喜欢这个节目(We Hope You Enjoyed the Show)
我确实希望您喜欢这个小片段,只是(希望)本书中许多小片段中的一个.这些片段的确有很多细节,因为我有更多的空间可以使用(限制500页以上的页面给您带来的惊喜真是令人惊讶.(I do hope you like this little snippet, just one of (hopefully) many little break out sections from the book. These snippets do have a lot more detail as I have more space to work with (it is really surprising how restricting 500+ pages gives you) ),但每个部分都介绍了您需要了解的所有内容.() but everything you need to know is covered in each section.) 我很高兴这个标题终于发布并可供人们抓住,有任何疑问/问题/想法,只要在我的博客上使用"联系"页面给我下一行,我保证会尽快与您联系.(I’m so glad this title is finally published and out there for people to grab, any queries / questions / thoughts, just drop me a line using the Contact page on my blog and I promise to get back to you.) 此代码段的示例项目和代码可在此处找到:(The sample project and code for this snippet can be found here:) Mecanim状态机.zip(Mecanim State Machines.zip)
等等,还有更多!(Wait, There’s more!)
现在,Unity终于撤回了新的闪亮高级UI系统的封面,我可以正式宣布,我已经完成了Packt的第二个标题的大部分准备工作,这将是有关该新标题的深入概述和指南. UI系统.(Now that Unity has finally pulled back the covers on the new shiny and advanced UI system, I can formally announce that I’m already most of the way through on my second title with Packt which will be an in depth overview and guide to the new UI system.) 因此,如果您想了解如何从新的UI系统中获得最大收益,并从遭受Beta困扰的数月中学习一些狡猾的提示和技巧,那么这将是您的理想之选.(So if you want a leg up on how to make the best out of the new UI system and learn some cunning tips and tricks from many months of suffering through the beta then this will be a title for you.) 如果您想获取更多详细信息或有任何特定要求,请尽我所能,我将尽我所能进行尽可能多的报道(尽管是我,但我在很多领域都已经超出预算,比您需要的更多细节)曾经需要,但这不会阻止我.(If you want more details or have any particular requests just let me know, I’ll do my best to cover as much as I can (Although being me, I’m already over budget in a lot of areas with more detail than you could ever need but that won’t stop me.) )())
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# Unity3D game 新闻 翻译