ImageVerifierCode 换一换
格式:DOCX , 页数:20 ,大小:353KB ,
资源ID:4346316      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/4346316.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Unity3D游戏开发笔记2.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Unity3D游戏开发笔记2.docx

1、Unity3D游戏开发笔记22013.1.193.【第一张地图与跳跃的改善】继续吧,为了方便继续编写的敌人之类的脚本,所以打算今天先把第一张地图画个大概。结果,画了我好久的地图. ()我对美术方面的天赋简直是惨不忍睹了.加之地图中途画的差不多的时候Unity又崩溃了一次.忘了保存(o)。于是又忙活半天.这个地图完全靠临时发挥了,第一张地图我画了好几次了,基本上每次画出来的地形之类的都完全不一样,所以就不多解释了,就上一张大概的场景图吧:看起来好简单吧?唉.开启编辑器,这时侯如果在场景中转悠的话,很轻易就可以发现人物跳跃的功能有些瑕疵,就是跳动速度太快,相机都晃的花眼.事实证明,偷懒是行不通的.

2、那么现在还是打开PlayerControl脚本改造一下吧。在脚本的Move函数中,原本的跳跃功能只有短短两行,就是判断人物是否位于地面,在的话,就把人物向上抬升一段距离,结果造成跳跃过于突兀的效果。现在的话,可以先把判断角色是否位于地面的那段if语句注释掉,删掉也可以。为了使跳跃起来不那么突兀,我的想法是定义一个bool变量,当角色在地面上按下空格键时,变量为true,否则当角色跳起来超过一定高度就为false,判断高度的方式,我想来想去,用了射线检测的方式(当然,没用的错误的实验肯定不会写出来的)。首先在最开始Start函数上面定义一个bool变量: #region 判断 private b

3、ool m_jumpTmp=true;/判断是否可以跳跃 #endregion然后在玩家按下空格后,定义一个临时的变量存放角色向下的方向,再判断角色是否位于地面,如果在地面,就可以挑。否则跳跃超过1.5米后,就得等落地了才能跳了: if(Input.GetKey(KeyCode.Space) Vector3 m_direction=m_transform.TransformDirection(Vector3.down);/方向向下的临时变量 if(m_controller.isGrounded) m_jumpTmp=true; else if(!Physics.Raycast(m_transf

4、orm.position,m_direction,1.5f)/判断跳跃高度 m_jumpTmp=false; if(m_jumpTmp) m_animation.CrossFade(Jump2); m_transform.Translate(Vector3.up*m_jump*Time.deltaTime); 之所以把东西写在按空格键里面,是因为节省些许性能。把代码如此改了之后,再回到游戏中运行试一下,跳跃果然要缓多了。2014.1.204.【敌人的AI(一)】今天就先来写敌人的AI吧。首先导入一群怪物的模型包,然后在根目录下新建一个文件夹,名为_Enemy,然后将导入的怪物模型移动进去,以方

5、便后来分辨。然后在_Script中新建一个文件夹,名为Enemy,然后在Enemy文件夹中新建一个脚本,名为Enemy。因为考虑到敌人肯定不止一个,所以每个敌人都采用单独的脚本肯定不现实(这也使我当初重写了四五遍敌人脚本后才恍悟到的.),我就想到是否可以直接先写一个敌人的主要脚本,往后每个敌人的脚本都从中继承,每个敌人到时只需要改一点就可以了。在脚本最开始,首先定义敌人的属性及自身的对象: #region 属性 public string m_name;/名字 public int m_level;/等级,以判断角色应当获取的经验 public int m_maxLife;/生命 public

6、 int m_currentLife;/当前生命 public int m_defense;/防御力 public int m_attack;/攻击力 public float m_speed;/速度 public int m_rotateSpeed;/旋转速度 public float m_attackRadius;/攻击半径 #endregion #region 对象 public Transform m_transform;/自己 #endregion在这里,对敌人就不设置魔法值了,其它属性跟角色的差不多罢。因为在游戏中我还设置了Boss,因此还必须定义一个判断敌人是否是Boss的boo

7、l变量,默认为false: #region 判断 public bool m_isBoss=false; #endregion然后在Start函数中取得自身对象:m_transform=this.transform;/获取自己对象因为现在这个敌人脚本只是一个基类,因此还必须要求从其继承的那些敌人能够为自己的属性进行赋值,所以我又定义了一个SetAttribute的虚函数函数,类型为保护,这样在子类中就可以用这个类进行敌人各项属性的赋值: protected void SetAttribute(string name,level,int Life,int defense,int attack,i

8、nt speed,int rotatteSpeed,float attackRadius) m_name=name; m_level=level; m_maxLife=Life; m_currentLife=Life; m_defense=defense; m_attack=attack; m_speed=speed; m_rotateSpeed=rotatteSpeed; m_attackRadius=attackRadius; 为了不在子类中更改Start函数,另外还要再声明一个Init的虚函数,里面什么都不写,并在Start函数最开始进行调用: void Start () Init();

9、 m_transform=this.transform;/获取自己对象 protected virtual void Init() 这样的话,子类初始化什么东西的话,就可以直接在这个函数中搞定了。然后,敌人的状态肯定要分为没有目标时,干什么,有目标时就攻击目标之类的动作,所以,应该再定义一个bool类型的变量,进行这点的判断吧。这个类型就定义在“判断”那一堆: #region 判断 public bool m_isBoss=false; protected bool m_isIdle=true; #endregion这时就可以在Update函数中进行判断了:if(m_isIdle)/如果处于空

10、闲状态else这时候,我选择在最开始加上一堆放“变量”的,并在那儿定义一个随机值m_idleStat用来作为随机播放动画的随机值,m_idleTime用来限制每一个动画播放的时长:#region 变量protected int m_idleStat;/定义空闲状态动画的随机值protected float m_idleTime=0;/每一个空闲状态持续时间#endregin现在就可以在Update函数中加上这些: if(m_isIdle) m_idleTime-=Time.deltaTime; if(m_idleTime0)/空闲随机时间到了就随机做出新动作 m_idleStat=Random

11、.Range(0,11); audio.clip=m_sound; audio.Play(); m_idleTime=3; 其中的随机值用来随机出010几个数字,用来判断随机播放什么动画。并且,在播放动画的同时,叫一声。声音变量定义在前面“变量”标签中,现在既然涉及到声音,那就把攻击声音和技能声音一块儿定义了: /声音 public AudioClip m_sound; public AudioClip m_attackSound; public AudioClip m_skillSound;既然涉及到了动画,那就要获取动画组件了。在脚本Start函数上面的“对象”标签中,再定义一个动画组件:

12、protected Animation m_animation;/动画组件 并在Start函数中进行初始化:m_animation=GetComponent(); 这时候再定义一个“动画”标签,将敌人的各个动画分别赋值给定义的string类型,这样会 更加好控制: #region 动画状态 protected string m_animationIdle=idle1; protected string m_animationIdle2=idle2; protected string m_animationIdle3=idle3; protected string m_animationWalk

13、=walk; protected string m_animationAttack=attack; protected string m_animationSkill=skill; protected string m_animationDeath=death; #endregion这些动画,到时候需要在Inspector中对敌人的动画进行改名,这时先就定义好吧。动画之类的都定义好了,在Update函数中就可以进行随机动画的判断了。这里我使用的Swicth,以前本来也不是使用switch进行判断的,现在写的时候觉得switch可能比较简单些,就改了结果好像还复杂些了.不过没办法,折腾了半天,都

14、差不多弄好了,就不改了:switch(m_idleStat) case 1:m_animation.CrossFade(m_animationIdle); audio.clip=m_sound; audio.Play(); break; case 2:m_animation.CrossFade(m_animationIdle); m_transform.Rotate(0,m_rotateSpeed*Time.deltaTime,0); break; case 3:m_animation.CrossFade(m_animationIdle2); break; case 4:m_animation

15、.CrossFade(m_animationIdle2); break; case 5:m_animation.CrossFade(m_animationWalk); m_transform.Rotate(0,m_rotateSpeed*Time.deltaTime,0); break; case 6:m_animation.CrossFade(m_animationWalk); m_transform.Rotate(0,m_rotateSpeed*Time.deltaTime,0); break; case 7:m_animation.CrossFade(m_animationWalk);

16、m_transform.Rotate(0,m_rotateSpeed*Time.deltaTime,0); break; case 8:m_animation.CrossFade(m_animationWalk); m_transform.Translate(Vector3.forward*m_speed*Time.deltaTime); break; default:m_animation.CrossFade(m_animationIdle3); m_transform.Translate(Vector3.forward*m_speed*Time.deltaTime); break; 原理就

17、是使用switch判断每个随机数字,在某些数字上就旋转或者前进,或者嫌在原地。东西看起一大堆,实际上原理很简单.然后在状态最后向自己前面发出一条射线,判断自己前方有没有人,有的话,就将状态m_isIdle置为false: m_forward=m_transform.TransformDirection(Vector3.forward); if(Physics.Raycast(m_transform.position,m_forward,out m_hit,m_attackDistance,m_layerMask) m_attackTarget=m_hit.collider.gameObject

18、.transform;/如果看见任何人类对象,就获取其位置,并将Idle状态置为false m_isIdle=false; 其中的m_forward是向前的一个Vector3变量,定义在前面“变量”标签中:protected Vector3 m_forward;/敌人的前方向hit是属于RaycastHit变量,所以也要在前面定义:protected RaycastHit m_hit;/射线碰撞m_attackDistance是定义的敌人视线距离(还是那句话,我数学不好,就不用那些复杂的模拟现实去判断怪物的视角高度之类的了,直接一条有距离的射线从敌人面前射出去,撞上了就代表“看见了”.),也要

19、定义在最前面“变量”标签中:protected float m_attackDistance=8;/会攻击的视线距离至于m_layerMask则是层蒙版,今天在这个上面又折腾了好久.我在编辑器的层标签里面新建了一个标签,命名为:“Human”,并把它指派给了玩家,然后再在最开始变量标签中定义了一个层 protected LayerMask m_layerMas; 在Start函数中进行初始化:m_layerMask=1LayerMask.NameToLayer(Human);最后m_attackTarget就是属于“看见”的目标对象了,看见了谁,就把谁赋给它,然后对这个对象进行攻击等等,也先定

20、义在开始的“对象”标签中:public Transform m_attackTarget;/攻击对象获取到了看见的对象后,就可以把m_isIdle这个空闲状态设置为false了,代表不再闲着没事儿,而是应该进行攻击了。接下来就在Update函数中的if(m_isIdle)判断后面加上一个else语句,里面放上 RotateTo(); Attack();两个函数。这两个函数写在外边,也是同样考虑到以后有的敌人可能会改变攻击方式的。首先是Rotate函数,定义在Update函数下边吧: protected void RotateTo() Vector3 m_oldAngle=m_transform

21、.eulerAngles;/当前旋转角度 m_transform.LookAt(m_attackTarget.position);/盯着攻击对象 float m_target=m_transform.eulerAngles.y;/目标角度吧 float m_targetAngle=Mathf.MoveTowardsAngle(m_oldAngle.y,m_target,m_rotateSpeed*Time.deltaTime);/计算应转动的角度 m_transform.eulerAngles=new Vector3(0,m_targetAngle,0);/转动角度 作用就是改变敌人的当前面向

22、的角度到面向攻击对象的方向,说实话,这一段我也不是很明白,只是知道大概达到了转向的效果。在Rotate函数下继续定义Attack攻击函数,在函数中用到的变量m_distanceToOther是敌人当前与攻击目标的距离,定义在前面的“变量”标签中:protected float m_distanceToOther;/与攻击对象的距离出此之外还有攻击的粒子效果,粒子效果放在“对象”标签中,这里我就先把两个粒子效果都定义起来了: public Transform m_attackParticle;/普通攻击粒子效果 public Transform m_skillParticle;/技能攻击粒子效果

23、这个粒子效果只是用来判断攻击对象的,真正的伤害计算我准备放到粒子效果里面,那样的话,大概能做到无论是NPC还是敌人都能进行攻击罢?(为自由的游戏而奋斗)。攻击函数: protected void Attack() m_distanceToOther=Vector3.Distance(m_transform.position,m_attackTarget.position); if(m_distanceToOtherm_attackRadius)/目标进入攻击半径,攻击 m_forward=m_transform.TransformDirection(Vector3.forward); if(P

24、hysics.Raycast(m_transform.position,m_forward,out m_hit,m_attackRadius,m_layerMask) m_animation.CrossFade(m_animationAttack); Instantiate(m_attackTransform,m_hit.collider.gameObject.transform.position,Quaternion.identity);/攻击,实例化一个粒子 else if(m_distanceToOther20)/如果距离小于20,对目标进行追击 m_animation.CrossFad

25、e(m_animationWalk); m_transform.Translate(Vector3.forward*m_speed*Time.deltaTime); else if(m_distanceToOther90)/ 如果距离大于20,就回到Idle状态,不追目标了 m_isIdle=true; else/超过九十米的话,为了省点资源,就把这个敌人销毁罢 Destroy(this.gameObject); 这个攻击函数会先对自己与攻击对象的距离进行判断,若果两者之间的距离小于自身的攻击半径,就向前发射一条射线,若果碰撞到了任何人类层的目标,就进行攻击(实例化一个普通攻击的粒子效果)。否

26、则两则距离小于20米的话,就项目标跑过去,当然,距离大于90米的话(出了玩家的视线范围),就直接销毁自身。好了,天色不早了,接下来的明天继续吧。2014.1.215.【敌人AI(二)与.攻击判定】昨天的脚本现在其实已经可以运行进行测试了。那么就先测试一下。首先找到_Enemy文件夹中导入的怪物模型,这里我以wolf,也就是狼为例,它也将作为玩家最先见到的敌人。将狼的模型拖入场景中,然后在Inspector面板中将小狼模型所需要用到的动画按照先前脚本中定义的名字改名,这里主要是为了方便,因为默认状态动画有了,就不用在继承“敌人”脚本的子类中去赋值动画名称了,相比在脚本中赋值动画名来说,在Insp

27、ector中改动画的名字显得轻松多勒!如图:只需要将需要用到的动画改名就可以了。然后就是脚本了。在_Script文件夹下的Enemy文件夹下新建一个脚本,名为“EnemyWolf”,双击打开脚本。在最开始那儿就不能让其继承自Monobehavaour,而要改为Enemy。然后覆盖先前啥都没写的Init函数,他将实现小狼属性的初始化:public class EnemyWolf : Enemy protected override void Init() SetAttribute(小狼,2,100,20,20,2,60,2.5f); 好了!这个脚本就算完成了!什么?!就这点?木错,以后的敌人跟这

28、个相差应该也不是很大,就是这样。然后将一个狗叫的音效拖到脚本的m_sound上(浪叫不好找啊,就用狗叫来代替咯.),并将音效赋给小狼的AudioSource组件,去掉勾选默认播放。现在可以将脚本拖到场景里的小狼身上了,运行游戏,小狼开始在原地转悠起来,过一会儿叫一声.并且看见玩家的角色后,还会跑过来一直跟着。(本来是有问题的,调试了良久之后,放在这儿的脚本当然没有问题了.),现在初步的AI就完成了。额.又调试了一下,发现还是有个小问题,就是敌人经常看不见玩家的角色似的?直接无视?又仔细调试了几遍,发现了原因所在, 这个原因挺重要的,就在这儿提一下: 默认这些对象的position一般都是物体的

29、 最底部,也就是人的脚下之类的地方,直接发射射线的话,从地面射出的射线恐怕也只有射中别人的脚.( ),所以发射射线时,应该让坐标向上抬起一段距离,所以应该改一改Enemy的脚本,把脚本中两处发射射线的地方,第一个起始位置加上一个Vector3.up: if(Physics.Raycast(m_transform.position+Vector3.up,m_forward,out m_hit,m_attackRadius,m_layerMask) 。现在就没问题了,当角色进入攻击半径时,它甚至会进行攻击。只是因为现在还没有将攻击的粒子赋给它,所以控制台会打印一个错误。刚才用手机去了一趟官网,被打击勒.那么导入粒子资源包,创建一个_Particle文件夹存放,然后拖放一个粒子效果到小狼脚本上去,同时将小狼攻击音效拖放到其身上,再次运行游戏,便可以看见攻击效果了。考虑到以后工程项目中都会存在这些资源,所以以后我都不会再提起导入资源包的事儿了。虽然是这些行为看似没问题了,不过小狼的攻击明显过快,这里就还的设置一个攻击间隔,定义在最开始的“变量”标签中:protected float m_attackDelay=2;/攻击延时然后再Attack函数中进行攻击间隔的判断,只有当攻击间隔时间到了,小狼才会再次攻击:m_attackDelay-=Time.deltaTime;

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1