unity3d游戏中人走近门自动打开unity 计时器怎么写写

中国领先的IT技术网站
51CTO旗下网站
Unity3D游戏开发之仿仙剑奇侠传角色控制效果
在上一篇文章中,我们从Unity3D为我们提供的相机原型实现了非编码式的小地图,如果结合GUI在这个小地图下面绘制一些背景贴图,相信整体的效果会更好一些。
作者:秦元培来源:秦元培的博客| 11:05
在上一篇文章中,我们从Unity3D为我们提供的相机原型实现了非编码式的小地图,如果结合GUI在这个小地图下面绘制一些背景贴图,相信整体的效果会更好一些。博主希望这个问题大家能够自己去做更深入的研究,因为贴图的绘制在前面的文章中,我们已经已经提到了,所以这里就不打算再多说。今天呢,我们继续为这个小项目加入一些有趣的元素。首先请大家看一下下面的图片:
相信熟悉国产单机游戏的朋友看到这幅图片一定会有种熟悉的感觉,博主在本系列的第一篇文章中,就已经提到了博主是一个国产单机游戏迷,博主喜欢这样有内涵、有深度的游戏。或许从操作性上来说,仙剑系列的回合制在很大程度上落后于目前的即时制,但是我认为回合制和即时制从本质上来说没有什么区别,即时制是不限制攻击次数的回合制,所以从玩法上来讲,回合制玩家需要均衡地培养每一个角色,在战斗中寻找最优策略,以发挥各个角色的优势,因此博主认为如果把即时制成为武斗,那么回合制在某种程度上就可以称之为文斗,正是因为如此,仙剑系列注重剧情、注重故事性,为玩家带来了无数感动。鉴于国内网游玩家的素质,博主一贯反感网游,所以比较钟情于武侠/仙侠单机游戏,虽然仙剑同样推出了网络版,但是在游戏里开着喇叭、挂着语音、相互谩骂的网游环境,实在让我找不回仙剑的感觉。好了,闲话先说到这里,今天我们来说一说现价奇侠传四里面的角色控制。玩过仙剑奇侠传的人都知道,仙剑奇侠传真正进入3D界面的跨时代作品当属上海软星开发的仙剑奇侠传四,该公司之前曾开发了仙剑奇侠传三、仙剑奇侠传三外传等作品,后来由于某些原因,该公司被迫解散。而这家公司就是后来在国产单机游戏中的新锐&&上海烛龙科技的《古剑奇谭》。有很多故事,我们不愿意相信结局或者看到了结局而不愿意承认,青鸾峰上蓝衣白衫、白发苍苍的慕容紫英,随着魔剑幽蓝的剑影御剑而去的身影,我们都曾记得,或许他真的去了天墉城,只为一句:承君此诺,必守一生。好了,我们正式开始技术分享(博主内心有很多话想说)!
在仙剑奇侠传四中,玩家可以通过鼠标右键来旋转场景(水平方向),按下前进键时角色将向着朝前(Forward)的方向运动,按下后退键时角色将向着朝后(Backword)的方向运动、当按下向左、向右键时角色将向左、向右旋转90度。从严格意义上来说,仙剑四不算是一部完全的3D游戏,因为游戏视角是锁死的,所以玩家在平时跑地图的时候基本上是看不到角色的正面的。我们今天要做的就是基于Unity3D来做这样一个角色控制器。虽然Unity3D为我们提供了第一人称角色控制器和第三人称角色控制器,但是博主感觉官方提供的第三人称角色控制器用起来感觉怪怪的,尤其是按下左右键时那个旋转,感觉控制起来很不容易,所以博主决定自己来写一个角色控制器。首先我们打开项目,我们还是用昨天的那个例子:
很多朋友可能觉得控制角色的脚本很好写嘛,这是一个我们通常见到的版本:
&if(Input.GetKey(KeyCode.A)) &{ &&&&SetAnimation(LeftAnim); &&&&this.mState=PersonState.W &&&&mHero.transform.Translate(Vector3.right*Time.deltaTime*mSpeed); &} &&if(Input.GetKey(KeyCode.D)) &{ &&&&SetAnimation(RightAnim); &&&&this.mState=PersonState.W &&&&mHero.transform.Translate(Vector3.right*Time.deltaTime*(-mSpeed)); &} &&if(Input.GetKey(KeyCode.W)) &{ &&&&SetAnimation(UpAnim); &&&&this.mState=PersonState.W &&&&mHero.transform.Translate(Vector3.forward*Time.deltaTime*(-mSpeed)); &} &&if(Input.GetKey(KeyCode.S)) &{ &&&&SetAnimation(DownAnim); &&&&this.mState=PersonState.W &&&&mHero.transform.Translate(Vector3.forward*Time.deltaTime*(mSpeed)); &&&&Vector3&mHeroPos=mHero.transform. &} &
那么,我们姑且认为这样写没什么问题,那么现在我们导入官方提供的Script脚本资源包,找到MouseLook脚本,在Update()方法中添加对右键是否按下的判断,这样我们就可以实现按下鼠标右键时视角的旋转。修改后的脚本如下:
using&UnityE &using&System.C &&&&&&&&&&&&&&&[AddComponentMenu(&Camera-Control/Mouse&Look&)] &public&class&MouseLook&:&MonoBehaviour&{ &&&&&&public&enum&RotationAxes&{&MouseXAndY&=&0,&MouseX&=&1,&MouseY&=&2&} &&&&&public&RotationAxes&axes&=&RotationAxes.MouseXAndY; &&&&&public&float&sensitivityX&=&15F; &&&&&public&float&sensitivityY&=&15F; &&&&&&public&float&minimumX&=&-360F; &&&&&public&float&maximumX&=&360F; &&&&&&public&float&minimumY&=&-60F; &&&&&public&float&maximumY&=&60F; &&&&&&float&rotationY&=&0F; &&&&&&void&Update&() &&&&&{ &&&&&&&&&if(Input.GetMouseButton(1)) &&&&&&&&&{ &&&&&&&&&&&if&(axes&==&RotationAxes.MouseXAndY) &&&&&&&&&&&{ &&&&&&&&&&&&&float&rotationX&=&transform.localEulerAngles.y&+&Input.GetAxis(&Mouse&X&)&*&sensitivityX; &&&&&&&&&&&&& &&&&&&&&&&&&&rotationY&+=&Input.GetAxis(&Mouse&Y&)&*&sensitivityY; &&&&&&&&&&&&&rotationY&=&Mathf.Clamp&(rotationY,&minimumY,&maximumY); &&&&&&&&&&&&& &&&&&&&&&&&&&transform.localEulerAngles&=&new&Vector3(-rotationY,&rotationX,&0); &&&&&&&&&&&} &&&&&&&&&&&else&if&(axes&==&RotationAxes.MouseX) &&&&&&&&&&&{ &&&&&&&&&&&&&transform.Rotate(0,&Input.GetAxis(&Mouse&X&)&*&sensitivityX,&0); &&&&&&&&&&&&& &&&&&&&&&&&} &&&&&&&&&&&else&&&&&&&&&&&{ &&&&&&&&&&&&&rotationY&+=&Input.GetAxis(&Mouse&Y&)&*&sensitivityY; &&&&&&&&&&&&&rotationY&=&Mathf.Clamp&(rotationY,&minimumY,&maximumY); &&&&&&&&&&&&& &&&&&&&&&&&&&transform.localEulerAngles&=&new&Vector3(-rotationY,&transform.localEulerAngles.y,&0); &&&&&&&&&&&} &&&&&&&&&} &&&&&} &&&&& &&&&&void&Start&() &&&&&{ &&&&&&&&&&&&&&&&&&if&(rigidbody) &&&&&&&&&&&&&rigidbody.freezeRotation&=&true; &&&&&} &}&
接下来,我们将这个脚本拖放到我们的角色上,运行游戏,我们发现了一个问题:当旋转视角后,角色并没有如我们期望地向朝前的方向移动,相反,角色依然沿着世界坐标系里的Vector3.forward向前运动。按照我们的想法,当旋转视角以后,角色应该可以朝着前方运动。怎么办呢?这里我们在上面的代码中加上这样的代码:
&&&&&&&&if(Input.GetMouseButton(1)) &&&&&&&&{ &&&&&&&&&&&&&&&&&&&&&&mAngles+=Input.GetAxis(&Mouse&X&)&*&15; &&&&&&&&&&&&&&&&&&&&&&transform.rotation=Quaternion.Euler(new&Vector3(0,mAngles,0)); &&&&&&&&}&
这里代码的作用是当用户按下鼠标右键旋转视角时,我们首先计算在水平上的旋转角,然后让角色的坐标系跟着视角一起旋转,这样就相当于把Vector3.forward和旋转后的目标角度平行。这样的话,我们控制人物向前运动的时候,它就会按照这个新的方向去运动。这样我们的第一个问题就解决了。我们继续往下看,由于这个模型中只提供了一个行走/奔跑的方向动画,所以就出现了角色动画和角色行为不符的问题,怎么办呢?这时候,我们可以这样想,我们可以先把角色旋转到指定的方向,然后让角色朝着向前的方向运动,这样角色动画和角色行为就可以相互对应起来了。为此我们做下面的工作:
&&&&&public&enum&PersonDirection &&&&&{ &&&&&&&&&&&&&&&&&&Forward=90, &&&&&&&&&&&&&&&&&&Backward=270, &&&&&&&&&&&&&&&&&&Left=180, &&&&&&&&&&&&&&&&&&Right=0, &&&&&}&
我们这里定义了四个方向上的角度,当我们角色旋转到Forward方向时,我们根据用户按下的键,来判断角色要向那个方向旋转:
private&void&SetPersonDirection(PersonDirection&mDir) &&&&&{ &&&&&&&&&&&&&&&&&&if(mDirection!=mDir) &&&&&&&&&{ &&&&&&&&&&&&&transform.Rotate(Vector3.up*(mDirection-mDir)); &&&&&&&&&&&&&mDirection=mD &&&&&&&&&} &&&&&}&
在该方法中,如果目标方向大于当前方向,那么角色将逆时针旋转,否则将顺时针旋转,角度差值为0,则不旋转。
好了,现在角色已经旋转到相应的方向了,我们让它朝前运动:
transform.Translate(Vector3.forward&*&WalkSpeed&*&Time.deltaTime);&
接下来我们为角色定义状态枚举值:
&public&enum&PersonState &{ &&&&&idle, &&&&&run, &&&&&walk, &&&&&jump, &&&&&attack &}&
我们在上面的代码上面做修改,最终形成的代码为:
using&UnityE &using&System.C &&public&class&RPGControl&:&MonoBehaviour&{ &&&&& &&&&&&&&&&private&Animation&mA &&&&&&&&&&public&PersonState&mState=PersonState. &&&&&&&&&&public&PersonDirection&mDirection=PersonDirection.F &&&&&&&&&&public&float&mJumpValue=2F; &&&&&&&&&&&&&&&private&float&mA &&&&&&&&&&public&GameObject&mC &&&&&&&&&&public&PersonState&RunOrWalk=PersonState. &&&&& &&&&&public&float&WalkSpeed=1.5F; &&&&&public&float&RunSpeed=3.0F; &&&&&&&&&&public&enum&PersonState &&&&&{ &&&&&&&&&idle, &&&&&&&&&run, &&&&&&&&&walk, &&&&&&&&&jump, &&&&&&&&&attack &&&&&} &&&&&&&&&&public&enum&PersonDirection &&&&&{ &&&&&&&&&&&&&&&&&&Forward=90, &&&&&&&&&&&&&&&&&&Backward=270, &&&&&&&&&&&&&&&&&&Left=180, &&&&&&&&&&&&&&&&&&Right=0, &&&&&} &&&&& &&&&&void&Start&()& &&&&&{ &&&&&&&&&&&&&&&&mAnimation=gameObject.GetComponent&Animation&(); &&&&&} &&&&&&void&Update&()& &&&&&{ &&&&&&&&&&&&&&&&if(Input.GetKey(KeyCode.W)) &&&&&&&&{ &&&&&&&&&&SetPersonDirection(PersonDirection.Forward); &&&&&&&&&&SetPersonAnimation(); &&&&&&&&} &&&&&&&&&&&&&&&&if(Input.GetKey(KeyCode.S)) &&&&&&&&{ &&&&&&&&&&SetPersonDirection(PersonDirection.Backward); &&&&&&&&&&SetPersonAnimation(); &&&&&&&&} &&&&&&&&&&&&&&&&if(Input.GetKey(KeyCode.A)) &&&&&&&&{ &&&&&&&&&&SetPersonDirection(PersonDirection.Left); &&&&&&&&&&SetPersonAnimation(); &&&&&&&&} &&&&&&&&&&&&&&&&if(Input.GetKey(KeyCode.D)) &&&&&&&&{ &&&&&&&&&&SetPersonDirection(PersonDirection.Right); &&&&&&&&&&SetPersonAnimation(); &&&&&&&&} &&&&&&&&&&&&&&&&if(Input.GetKeyUp(KeyCode.A)||Input.GetKeyUp(KeyCode.D)||Input.GetKeyUp(KeyCode.S)||Input.GetKeyUp(KeyCode.W)||Input.GetKeyUp(KeyCode.Space))&&&& &&&&&&&&{ &&&&&&&&&&mAnimation.Play(&idle&); &&&&&&&&&&mState=PersonState. &&&&&&&&} &&&&&&&&&&&&&&&&if(Input.GetKey(KeyCode.Space)) &&&&&&&&{ &&&&&&&&&&transform.GetComponent&Rigidbody&().AddForce(Vector3.up&*&mJumpValue,ForceMode.Force); &&&&&&&&&&mAnimation.Play(&Jump&); &&&&&&&&&&mState=PersonState. &&&&&&&&} &&&&&&&&&&&&&&&&if(Input.GetMouseButton(0)) &&&&&&&&{ &&&&&&&&&&mAnimation.Play(&Attack&); &&&&&&&&&&mState=PersonState. &&&&&&&&&&StartCoroutine(&ReSetState&); &&&&&&&&} &&&&&&&&&&&&&&&&if(Input.GetMouseButton(1)) &&&&&&&&{ &&&&&&&&&&&&&&&&&&&&&&mAngles+=Input.GetAxis(&Mouse&X&)&*&15; &&&&&&&&&&&&&&&&&&&&&&transform.rotation=Quaternion.Euler(new&Vector3(0,mAngles,0)); &&&&&&&&} &&&&&} &&&&& &&&&&private&void&SetPersonDirection(PersonDirection&mDir) &&&&&{ &&&&&&&&&&&&&&&&&&if(mDirection!=mDir) &&&&&&&&&{ &&&&&&&&&&&&&transform.Rotate(Vector3.up*(mDirection-mDir)); &&&&&&&&&&&&&mDirection=mD &&&&&&&&&} &&&&&} &&&&& &&&&&private&void&SetPersonAnimation() &&&&&{ &&&&&&&&&if(RunOrWalk==PersonState.walk) &&&&&&&&&{ &&&&&&&&&&&&mAnimation.Play(&Walk&); &&&&&&&&&&&&mState=PersonState. &&&&&&&&&&&&transform.Translate(Vector3.forward&*&WalkSpeed&*&Time.deltaTime); &&&&&&&&&} &&&&&&&&&else&if(RunOrWalk==PersonState.run) &&&&&&&&&{ &&&&&&&&&&&&mAnimation.Play(&Run&); &&&&&&&&&&&&mState=PersonState. &&&&&&&&&&&&transform.Translate(Vector3.forward&*&RunSpeed&*&Time.deltaTime); &&&&&&&&&} &&&&&} &&&&& &&&&&IEnumerator&ReSetState() &&&&&{ &&&&&&&&&&&&&&&&&&yield&return&new&WaitForSeconds(mAnimation.clip.length); &&&&&&&&&mAnimation.Play(&idle&); &&&&&&&&&mState=PersonState. &&&&&} &&&&& &&&&&&&&& &} &
其中,SetPersonAnimation()方法将根据RunOrWalk值来决定角色是采用行走还是奔跑的方式移动。最后,我们加上一个摄像机跟随的脚本SmoothFollow,这个脚本在官方提供的Script资源包里,我们把该脚本绑定到主摄像机上,并设定我们的角色为其跟随目标。
最后看看效果动画吧:(2M图片大小的限制啊,还有这难用的编辑器啊)
在《Unity3D游戏开发之当仙剑奇侠传角色控制器效果》上文中,我们实现了一个简单的角色控制器。博主之前曾说过,这个控制器是存在问题的,具体存在什么问题呢?请大家和我一起来看今天的文章。今天博主想和大家说说碰撞器与刚体,为什么要讨论这个呢?我们先来看这样一个需求:我们希望我们的角色在游戏场景中运动时,四面的墙壁对角色一个&撞墙&的感觉,同时不能影响角色的位置,当碰到场景中的某些障碍物(如荆棘等)时,角色能够掉血。基于这样的需求,我们想给角色、墙壁和障碍物加上碰撞器,通过编码的方式来获得碰撞信息以确定碰撞对角色的影响。我们打开之前创建好的项目,如图所示:
我们知道,在Unity3D中存在这几种碰撞器:盒子碰撞器、球体碰撞器、胶囊体碰撞器、网格碰撞器、地形碰撞器、滚轮碰撞器。除了滚轮碰撞器专门为汽车设计以外,其余的碰撞器在平时的游戏设计中我们都能碰到。墙体可以看做是盒子,所以可以使用盒子碰撞器。这里我们用五个大箱子作为我们的障碍物,同样地我们使用盒子碰撞器。那么对于我们的角色呢?我们知道我们的角色模型并不是均匀规则的几何体,如果使用上述的碰撞器,会出现碰撞不精确的情况。怎么办呢?这里我们选择网格碰撞器。我们直接给它创建一个网格碰撞器:
运行程序,可是我们发现我们的角色并没有和场景中的墙体发生碰撞,会从墙体和障碍物中穿过去。这是怎么回事呢?我们发现Mesh Collider有一个Mesh属性,所以这里应该为这个Mesh属性添加一个网格。可是项目中并没有这样一个网格体啊,博主查阅了相关资料发现,Unity3D是可以为模型生成网格体,那么怎么做呢?我们先把这个手动添加的网格碰撞体移除,然后在项目中找到我们模型文件,在右边的属性面板选中Generate Collider,然后点击Apply
现在我们回到游戏场景窗口中,我们会发现是这样的结果:
这模型和网格完全不能匹配啊?这个问题,博主到目前为止没有找到一个合理的解释。如果我们此刻运行游戏,角色倒是可以响应碰撞了,我们这里使用的是Collision检验,如果还有朋友不知道怎么检测碰撞,请看这篇文章。但是新的问题随之而来了,我们的角色由于受到碰撞的影响受到了力的作用,碰撞后不再受玩家控制,直接从画面上消失了。最终博主的解决办法是:给墙体加上盒子碰撞器、给角色加上一个胶囊体、刚体(取消重力)。最终程序运行结果如下:
大家可以注意到再我松开鼠标的那一瞬间角色自己发生了旋转,而且这个作用一直在持续下去,不过这算是比较圆满的结果了。那么问题呢?问题就是我对碰撞器和刚体的概念越来越模糊。我们可以通过创建Cube、创建Sphere、创建Capsule分别创建对应的碰撞体并且可以通过代码来检测,因为这些组件自带了刚体和碰撞器,但是在我们上面的例子中,没有刚体结构同样可以发生碰撞,那么我们不禁要问一句:刚体和碰撞器究竟是什么关系?为什么没有刚体,碰撞器还能工作?如果没有碰撞器,只有刚体行不行?带着这样的疑问?博主找到了两个表格,希望对大家有所启发吧!
具体内容参见:
我自己都觉得有点晕了,唉,今天就先这样吧,什么时候想清楚了再回来总结吧!
本文出处:
【编辑推荐】
【责任编辑: TEL:(010)】
大家都在看猜你喜欢
头条头条热点头条原创
24H热文一周话题本月最赞
讲师:243829人学习过
讲师:90181人学习过
讲师:14893人学习过
精选博文论坛热帖下载排行
《精通ASP+XML+CSS网络开发混合编程》介绍当前网络开发的主流平台与技术之一的ASP+CSS+XML的知识与应用,全书各知识点均配以实例,按照基础...
订阅51CTO邮刊后使用快捷导航没有帐号?
只需一步,快速开始
&加载中...
查看: 17292|回复: 10
角色控制-点击移动以及自动寻路
TA的其他好贴
马上注册,加入CGJOY,让你轻松玩转CGJOY。
才可以下载或查看,没有帐号?
本帖最后由 A你 于
17:15 编辑
角色控制-点击移动以及自动寻路(一)
之前在D3D中做的人物控制里,在空间中两点之间行走是一个比较复杂的制作过程。跟大家分享一下我的制作过程,可以一起研究改进改进。
这里面需要解决几个问题:
1.如何取得目标地点
需要通过鼠标当前位置的屏幕二维坐标,逆矩阵变换到世界空间下,做从摄像机到这个点的射线。射线与地面mesh进行碰撞检测,获得一个交点,就是目标点。
2.如何移动角色
实时得出角色的移动方向向量,在两点之间做线性插值计算,移动的同时也要播放动画。
3.两点之间有障碍怎么办
这个过程是一个比较复杂的过程,可以通过两种办法,一种是做一种转向机制,先移动监测点(我自己起的,意思是一个前进向量和一个向下的碰撞向量的假象交点),监测到碰撞了,就将角色转向,再次监测,直到碰撞不到,向当前挪一步,再重复刚才的操作,直到绕过这个障碍物;另一种是俗称的A*算法,需要预先准备好一个二维图来标记哪里可以走,哪里不可以走,并设置权值,以便于计算最短路径。
4.里的碰撞需要注意什么
射线的碰撞检测是比较耗费CPU资源的,推荐的是尽量少用,比如当做场景内物体的鼠标拾取时,对备选对象队列进行筛选后,再去逐一做检测。unity3d中也是一样,只不过没有提供像DX中提供的那种API,无法用自定义的结构去决定对哪些对象进行射线碰撞。所以要引入Layer的概念,具体的操作下节说。
角色控制-点击移动以及自动寻路(二)
针对上一节中第四点--筛选待测物体来说一下U3D中Layer的用法。
U3D中的Layer可以简单地理解为一个集合,所有的GameObject都可以设置Layer,且只能设置一个Layer。
设置方法:
1.Edit-&Project Setting-&Tags复制代码(tag和layer在同一个设置面板上)
2.前几个Builtin Layer是系统默认的,不能修改,可以在后面几个Layer中,设置Layer的名称,比如&Players&复制代码3.在Hierarchy面板中选择GameObject,在Inspector面板上面的Layer下拉框中选择刚才设置好的Layer
从此,该GameObject就属于这个Layer集合中的一员了。
Layer的应用:LayerMask
LayerMask可以在射线碰撞过程中屏蔽掉一些GameObject。
LayerMask的方法:LayerMask.NameToLayer(&Players&) 复制代码返回该Layer的编号
LayerMask.LayerToName(8) 返回该Layer的名称
var layerMaskPlayers:LayerMask = 1 && LayerMask.NameToLayer(&Players&);
var layerMaskTerrains:LayerMask = 1 && LayerMask.NameToLayer(&Terrains&);
var FinalMask:LayerMask&&= (layerMaskPlayers.value | layerMaskTerrains.value);
var hitt : RaycastH
var ray : Ray = mainCamera.ScreenPointToRay(Input.mousePosition);
if( Physics.Raycast(ray,&&hitt, 600, FinalMask.value))
{ ... }
复制代码上面代码描述一个鼠标拾取规则,射线仅与Layer属于Players和Terrains的GameObject做碰撞。
LayerMask的使用是按位操作的,在设置新的Layer时可以看到一共只有32个,应该是因为记录Layer的变量是四个字节。LayerMask.NameToLayer方法返回的LayerId是所要移位的位数,比如在设置Layer时,Players这个Layer的ID是8,则var layerMaskPlayers:LayerMask = 1 && LayerMask.NameToLayer(&Players&);复制代码最后将所有的可能按位或操作,就得出所有需要做射线碰撞的GameObject。
如果想取“除了XXXLayer”的都显示,则可以用取反操作。
layerMaskPlayers = ~layerMaskPlayers.复制代码比如layerMaskPlayers = 1&&8;
则layerMaskPlayers = ;[/code]
在双字长的情况下,~layerMaskPlayers.value = -257
二进制表示:
角色控制-点击移动以及自动寻路(三)
为鼠标点击的位置增加一个光圈。需求如下:
鼠标右键点击地面,射线与地面的交点处出现一个光圈(纹理动画)。
该纹理动画会旋转,跟游戏中一样。
玩家移动到该光圈处,或者进入了其他状态,光圈消失。
玩家点击新的目标点,原目标点光圈消失。
光圈要随着地形的起伏改变自己的朝向,这样自然。
制作过程:
首先create一个Plane,去掉这个Plane的Collider Component,否则玩家会和光圈点发生碰撞。并为这个Plane指定一个纹理贴图,shader方式选择Particles/Alpha Blended Premultiply 颜色相乘,显得光圈亮一些。注意光圈图片必须要有Alpha通道,才能进行透明处理。
(注:另一种可选的shader方式是FX/Flare,与前面的那种不同,这个绘制出来的纹理将会一直显示在前端,相当于关闭了屏幕的深度缓冲区后再绘制。效果就是:即使在障碍物后面,也能看到它,比较不太符合现实逻辑,但是考虑到地形的起伏,光圈平面有可能会嵌入到地形里面,所以有时这个又比较合适,具体是不是有更好的办法处理这个问题,稍后再细细追究,或者大家可以提出更好的意见供参考。主要是U3D中不好确定渲染过程,不能动态操纵何时关闭屏幕深度缓冲区,其实怎么关闭屏幕的深度缓冲区也不清楚。。。)
然后在全局空GameObject(空的对象,不做任何逻辑处理,只为了挂接全局的脚本--不依附于任何Object的脚本)中增加一个鼠标相关控制脚本。加上前面所说过的改变鼠标指针UI操作,整个脚本如下:
这个脚本要完成的工作是:
通过传进来的prefab(transform类型),将光圈点放置在指定位置,并且根据射线与地形交点的面片的法线,调整这个光圈的朝向。还有一个在创建时要注意的是,将光圈的坐标沿着Y轴正向提高了一个数值,是为了避免纹理动画与地面纹理重合造成撕裂现象。
其中定义的两个方法CreateDestinationTex复制代码和DestroyDestinationTex复制代码将会在人物控制脚本中调用。
注:虽然Instantiate方法在手册中显示返回的类型是Object,但实际上是返回跟prefab同类型的一个对象,比如prefab是个transform类型,那么Instantiate返回的就是一个transform类型的对象,在Destroy一个prefeb对象时,Destroy(...) 括号里只能写Object或GameObject,如果是Transform,则会因为有其他Component依附于这个transform,而无法删除掉。
最后修改角色控制脚本,在其中获得鼠标控制脚本的对象:
private varScriptObj_cursorControl :&&Script_C
_ScriptObj_cursorControl = GameObject.Find(&GameObject_GlobalController&).GetComponent(Script_Cursor); 复制代码//获得鼠标图标脚本对象
然后在鼠标右键点击地面后,进入STATE_LERPWALK状态,同时调用鼠标控制脚本中的函数CreateDestinationTex在指定给位置创建一个光圈对象,而当不在STATE_LERPWALK状态下时,调用鼠标控制脚本中的函数DestroyDestinationTex删除该对象。
if (Input.GetMouseButtonUp (1) && _grounded)
{
复制代码......
//调用鼠标处理脚本
if(_ScriptObj_cursorControl != null)
//创建目标点光圈
_ScriptObj_cursorControl.CreateDestinationTex(_endPos,TextureOnFloor,_hit.normal);
if(_playerstate == PlayerState.STATE_LERPWALK && _grounded)
{...}
if(_ScriptObj_cursorControl != null)
_ScriptObj_cursorControl.DestroyDestinationTex(); // 删除目标点光圈
else
Debug.Log(&cursor scirpt error !&);
}
复制代码角色控制-点击移动以及自动寻路(四)
...
var _ray : R& && & //从摄像机发射到鼠标位置的射线
var _hit : RaycastH& &&&//射线与目标网格的交点数据
var _startPos : Vector3;& & //当前位置,出发点
var _endPos : Vector3;& &&&//鼠标点击位置,目标点
var _lerp :& && & //插值系数
var _deltaLerp :& &&&//插值系数递增步长
var _rotation : Q& &//从当前朝向(本地空间Z轴)转向目标方向的旋转四元数值
var _slerpRotation :& &//旋转插值系数
var _deltaSlerpRotation :&&//旋转插值系数递增步长
var _moveDirectionLerpWalk : Vector3; //鼠标点击地面后,应该移动的方向
var _movePrecision :& &&&//当前点与目标点的距离误差
private var _lastDistance:& & //暂时未制作自动寻路系统,地图上未划分网格,如果目标点玩家上不去,有可能会一直跑,玩家与目标点的距离会呈现“先缩小距离,后拉长距离”的结果,所以用此变量记录上一步的距离,当距离开始拉长时,就停下。
enum PlayerState
{
STATE_READY& &= 0,
STATE_RUN& & = 1,
STATE_IDLE& & = 2,
STATE_ATTACK& &= 3,
STATE_JUMP& & = 4,
STATE_LERPWALK = 5,//增加一个状态,标示处于右键点击地面后的移动状态
}
function Update()
//=========================================================================
//鼠标操作 - 右键按下后弹起
var layerPlayers :LayerMask = 1 && LayerMask.NameToLayer(&Players&);
//var layerTerrains :LayerMask = 1 && LayerMask.NameToLayer(&Terrains&);
//var finalLayer : LayerMask = (layerPlayers.value | layerTerrains.value);
layerPlayers = ~layerPlayers. //对Players这个Layer的数值2进制位取反,表示除了Players以外,其他Layer都可以与射线进行碰撞
if (Input.GetMouseButtonUp (1) && _grounded)
{
if(_cameraCurrent == null)
{
print(null);
_ray = _cameraCurrent.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (_ray, _hit, Mathf.Infinity , layerPlayers.value))
{
if(_hit.collider.gameObject.tag == &Terrains&)
{
//Debug.DrawLine (_ray.origin, _hit.point);
_playerstate = PlayerState.STATE_LERPWALK;
_lerp = 0;
_startPos = transform.
var tempVec = _hit.
tempVec.y = _startPos.y; //高度拉齐,为了算出方向向量
_endPos = _hit.
print(&*****the endpos is : & + _endPos);
_lastDistance = Vector3.Distance(_startPos , _endPos);
_deltaLerp = 1/Vector3.Distance(_startPos , _endPos);
_slerpRotation = 0;
var relativePos = tempVec - _startP
_rotation = Quaternion.LookRotation(relativePos); //这个函数很方便,计算出从当前朝向转向目标方向的旋转四元数
_moveDirectionLerpWalk = relativePos.
_moveDirectionLerpWalk *= _
//调用鼠标处理脚本
if(_ScriptObj_cursorControl != null)
//创建目标点光圈
_ScriptObj_cursorControl.CreateDestinationTex(_endPos,TextureOnFloor,_hit.normal);
}
}
}
if(_playerstate == PlayerState.STATE_LERPWALK && _grounded)
{
_lerp += _deltaL
//if(_lerp &= 1)
//{
// _playerstate = PlayerState.STATE_IDLE;
// transform.rotation = _
//
//}
_slerpRotation += _deltaSlerpR
if(_slerpRotation &= 1)
{
transform.rotation = _
}
//平滑旋转人物的朝向
transform.rotation = Quaternion.Slerp(transform.rotation, _rotation, _slerpRotation);
//插值虽然计算得准,但直接用插值就无法做碰撞了,这里只用来保存坐标
//先取出移动方向向量,用Move方法移动,可以顺便做碰撞
var position = Vector3.Lerp(_startPos , _endPos , _lerp);
var _flagsLerp : CollisionFlags = _controller.Move(_moveDirectionLerpWalk * Time.deltaTime);
_animation.Play(&run&);
var distance = Vector3.Distance(transform.position,_endPos);
//以当前坐标和目标坐标的距离作为结束条件,小于误差范围值则停下
if(distance &= _movePrecision)
_playerstate = PlayerState.STATE_IDLE;
//当距离由大变小,又开始由小变大时,也要停下
else if(distance &= _lastDistance)
_playerstate = PlayerState.STATE_IDLE;
//记录上一帧中,玩家与目标点的距离
else
_lastDistance =
}
else
{
if(_ScriptObj_cursorControl != null)
_ScriptObj_cursorControl.DestroyDestinationTex(); // 删除目标点光圈
else
Debug.Log(&cursor scirpt error !&);
}
//=========================================================================
}
复制代码总结:右键点击地面,实现上要结合上一篇的内容,点击地面后在地面上创建一个与点击到的三角形朝向相同的平板,上面贴上一个纹理,通过旋转这个平板实现纹理的旋转动画
如何让别人关注你?
虽然看不懂,但一看就是好东西
本楼回复(<span id="dp_count_)
如何让别人关注你?
没工程么?真难得看
本楼回复(<span id="dp_count_)
如何让别人关注你?
文字比较多,先收藏了,谢谢分享
本楼回复(<span id="dp_count_)
如何让别人关注你?
{:soso_e160:}
本楼回复(<span id="dp_count_)
如何让别人关注你?
本楼回复(<span id="dp_count_)
如何让别人关注你?
先标记一下,回头细看
本楼回复(<span id="dp_count_)
如何让别人关注你?
标记标记&&谢谢楼主分享&&{:7_236:}
本楼回复(<span id="dp_count_)
如何让别人关注你?
本楼回复(<span id="dp_count_)
如何让别人关注你?
谢谢分享。
本楼回复(<span id="dp_count_)
如何让别人关注你?
Powered by}

我要回帖

更多关于 unity3d 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信