这是一篇关于unity 完成NPC对话的博客,博主在文章中给我们认真讲解了如何在unity中完成NPC对话。下面我们就来看unity 完成NPC对话的实现过程吧。

相信每一个喜欢RPG游戏的人,都会被PRG游戏中的剧情所打动吧。那么作为一部RPG,其剧情主要是靠人物间的对话串联起来的,玩家通过整合所有人物的对话信息来理解和把握整个故事的起因经过。所以从故事的角度来看,RPG游戏更能让玩家产生共鸣、增强游戏对于玩家的代入感。个人感觉目前的网游根本不能达到单机游戏这样完整的叙事性的目的,网游中充斥着只有厮杀、咆哮和谩骂。所以博主本人是十分厌倦网游的,尤其是对腾讯代理的各种网游残害祖国的花朵这件事情深恶痛绝。或许国产单机游戏真得比不上同时代的国外大作,可是武侠、仙侠离开了中国的传统文化还称得上是武侠、仙侠吗?我不想贬低任何一部游戏,因为每个游戏都有自己的特点,我想说的是游戏应该是一种艺术。何为艺术呢?就是这部游戏让你的心中存着一个信念,能够让你明白什么才是最重要的。仙剑奇侠传和古剑奇谭陪伴博主至今,博主每一次玩都有着不一样的感受。仙剑和古剑名义上是在说剑,其实何尝不是在说人呢?人力有时或许是卑微弱小的,可是一旦当你知道为什么而存在着的时候,你就会愿意去不断的努力以突破自我,历代的故事主角无一不是面对着这样的选择。二十几岁的人,正是应该努力的时候,你有什么资格整天靠着电视剧、游戏来让自己一天天地荒废时光呢?一部游戏如果不能为你带来任何有益的启示或者思考,那么你就永远不知道自己为什么要在游戏里战斗,那么你就永远不知道自己为什么执剑?游戏与现实是有区别的,可是道理都是相通的。你不努力,一定会有人比你更努力!

大家可能发现我最近更新文章的频率没有那么高了,因为宿舍里整天都在厮杀,遍地狼烟,实在让我无法安静地写博客了。所以我选择在晚上这个时候来更新今天的文章。好了,我们现在就来开始今天的内容吧。我们今天希望实现的是RPG游戏中的NPC对话系统。博主的思路是这样的,首先,我们根据用户鼠标的位置向NPC发射射线,如果射线击中了NPC,则进入对话状态。当用户按下空格键或者单击鼠标左键时,开始显示事先定义好的NPC对话数据。由于传统的GUI方式效率过低,所以我们今天采取的方式是再场景中使用GUI Text ,然后在脚本中更新它的内容,这样就实现了与NPC对话的目的。我们继续使用在前面的文章中搭建的场景,如图:



我们接下来向场景中拖入一个熊的模型作为我们这里的NPC,在Tag中添加NPC后,为其设置NPC标签,并加上一个合适的触发器,博主这里使用的是球体触发器。接下来,我们创建一个GUI Text,将其命名为Description,它将作为我们显示NPC对话的一个GameObject。到目前为止,场景我们已经搭建完成了。接下来,我们来编写用于控制NPC对话的脚本NPC.cs:

  1. [csharp]
  2. using UnityEngine;
  3. using System.Collections;
  4. public class NPC : MonoBehaviour
  5. {
  6. //定义NPC对话数据
  7. private string[] mData={"你好,我是NPC","这是一个Unity3D编写的脚本",
  8. "对话框是基于GUI实现的","博主是一个喜欢游戏的人","这是一个关于NPC对话的简单实现"
  9. ,"大家就不要笑话这个界面丑陋了啊"};
  10. //当前对话索引
  11. private int index=0;
  12. //用于显示对话的GUI Text
  13. public GUIText mText;
  14. //对话标示贴图
  15. public Texture mTalkIcon;
  16. //是否显示对话标示贴图
  17. private bool isTalk=false;
  18. void Update ()
  19. {
  20. //从角色位置向NPC发射一条经过鼠标位置的射线
  21. Ray mRay=Camera.main.ScreenPointToRay(Input.mousePosition);
  22. RaycastHit mHi;
  23. //判断是否击中了NPC
  24. if(Physics.Raycast(mRay,out mHi))
  25. {
  26. //如果击中了NPC
  27. if(mHi.collider.gameObject.tag=="NPC")
  28. {
  29. //进入对话状态
  30. isTalk=true;
  31. //允许绘制
  32. if(Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0))
  33. {
  34. //绘制指定索引的对话文本
  35. if(index<mData.Length)
  36. {
  37. mText.text="NPC:"+mData[index];
  38. index=index+1;
  39. }else
  40. {
  41. index=0;
  42. mText.text="NPC:"+mData[index];
  43. }
  44. }
  45. }
  46. }
  47. }
  48. void OnGUI()
  49. {
  50. if(isTalk)
  51. {
  52. //禁用系统鼠标指针
  53. Screen.showCursor=false;
  54. Rect mRect=new Rect(Input.mousePosition.x-mTalkIcon.width,
  55. Screen.height-Input.mousePosition.y-mTalkIcon.height,
  56. mTalkIcon.width,mTalkIcon.height);
  57. //绘制自定义鼠标指针
  58. GUI.DrawTexture(mRect,mTalkIcon);
  59. }
  60. }
  61. }

在上述脚本中,我们根据isTalk标志来判断是否进入了对话状态,如果进入对话状态,则将系统默认的鼠标指针修改为我们自定义的鼠标指针,提示用户要进入对话了。在此前提下,如果用户按下了空格键或者鼠标左键,则NPC会依次将对话数据一句一句地显示出来,当所有对话显示完全后,我们将索引清零,让对话从头开始,依次循环。

好了,我们一起来看看最终实现的效果吧,这里博主给对话文本加上了背景:


背景加上效果会好很多,不过博主目前还没有想到如何能够使对话框背景响应用户的操作的办法,所以这个问题暂时没有写到今天的文章里,等博主研究好具体细节后会加在这篇文章的后面,希望大家继续关注我的博客啊。好了,今天的博客就是这样啦,希望大家喜欢,有什么问题可以给我留言,我一定尽自己最大的努力为大家解答。谢谢大家!

博主当时写这篇文章时提到一个对话框的问题,现在给出一个可以实际使用的方法,就是我们将对话框背景及对话框文字制作成预设,然后我们在屏幕底部的位置使用克隆物体的方法来生成预设对象。当用户每次按下空格键时,先判断当前场景中是否存在预设对象,如果存在则修改文本,如果不存在,则先创建预设对象,然后再修改文本。当一组对话显示完后,判断玩家与NPC的距离,如果该距离大于我们设定的对话距离,则销毁对话。否则,暂时隐藏对话框。这就是博主目前可以想到的方法了。