本次学习:
1.第三人称视角研究
2.摇杆区域制作
3.视角限制设计
4.简单的战斗部分
1.第三人称视角研究
第三人称视角是什么大家玩玩游戏就懂了-0- 羽化不是专业制作人,只是一个玩家,下面是羽化玩家身份的总结出来的一些经验,很多词汇非专业,见谅。。。
1.人物移动 玩过魔兽世界的玩家可能都知道W A S D可以控制人物往8个方向移动,但人的面向不会改变,意味着有左移右移和后退等动作,羽化认为这样设计比较有真实感,而且效果很好,但有些游戏比如神鬼寓言就有所改变,W A S D不仅可以控制移动方向,而且还能改变人的面向,这种设计更加灵活,适合ACT,不适合ARPG,所以羽化这是做的一个ARPG,使用的是魔兽世界的移动标准,摇杆第一次点进区域就可自由移动,原来羽化就是这么想的,看到混乱与秩序的摇杆后觉得更加合理,所以就借鉴了下。
2.视角移动 ARPG也有很多种视角,有斜45°类似火炬之光这种,也有魔兽世界一样360°的,羽化原来做过斜45°的Demo,固定视角可以解决很多问题,但也伴随着更棘手的问题,既然公司要求,所以就做了这个360°的视角转换,包括手势放大缩小。视角改变很容易,但当视角更改以后问题出现了,玩过魔兽世界包括众多自由视角游戏的玩家都知道视角虽然可以随便移动,但存在着很多约束,比如你向上滑动时,视角不可能穿过地面而到地下,一定会沿着人的方向放大,这是前人给我们的经验,比如有一个物体挡在人物和玩家中间时,视角应该拉近,这样就不会产生视觉死角,诸如此类的情况很多,就运用到了射线Ray,进入我们今天的主题。
大家可以看到,羽化这个Demo用的东西也不多,这是前期的一个Demo,还不算完整,如果有机会给大家分享下羽化现在的Demo。
2.摇杆区域制作
触摸屏发展至今,羽化见过最好大的移动摇杆莫过于“混乱与秩序”的移动摇杆了,本身摇杆制作并不困难,主要是学习下这种为玩家带来方便的思维模式,先把代码送上:
Rocker.js:
-
-
varSpeed:float=0.05;
-
-
varSpeed_L:float=0.1;
-
-
varRole:Transform;
-
-
varPlayer_true:Transform;
-
-
varAttackPrafab:Transform;
-
-
varAttackRange:Transform;
-
-
-
privatevarPO_X:int=0;
-
privatevarPO_Y:int=0;
-
-
privatevarPT_X:int=0;
-
privatevarPT_Y:int=0;
-
-
staticvarPR_M:boolean=false;
-
-
privatevarPM_X:int=0;
-
privatevarPM_Y:int=0;
-
-
privatevarPS_X:int=0;
-
privatevarPS_Y:int=0;
-
-
privatevarM_X:int=0;
-
privatevarM_Y:int=0;
-
-
privatevarPC_X:int=0;
-
privatevarPC_Y:int=0;
-
-
privatevartouchDeltaPosition:Vector2;
-
-
privatevarDistance:int=0;
-
privatevarDistance_D:int=0;
-
-
staticvarCamera_Record:float=-2.0;
-
-
staticvarAngles:int=0;
-
-
staticvarFocus:boolean=false;
-
-
privatevarhit:RaycastHit;
-
-
privatevarEnemie:Vector3;
-
-
privatevarRange:float=6.0;
-
-
privatevarCreationTime:double=-10.0;
-
-
privatevarAttacking:boolean=false;
-
-
staticvarTest=0.0;
-
-
functionUpdate()
-
{
-
-
-
-
if(Focus)
-
{
-
if(Vector3.Distance(transform.position,Enemie)>Range)
-
{
-
Focus=false;
-
Camera.main.depth=-1;
-
return;
-
}
-
Camera.main.depth=-3;
-
transform.LookAt(Enemie);
-
Player_true.transform.LookAt(Enemie);
-
}
-
-
if(Time.time>(CreationTime+0.5)&&Role.animation.IsPlaying("Attack")&&Attacking)
-
{
-
Instantiate(AttackPrafab,AttackRange.transform.position,Quaternion.identity);
-
Attacking=false;
-
}
-
-
if(Input.touchCount==1)
-
{
-
Player_Move();
-
Attack();
-
-
if(Input.GetTouch(0).position.y>Screen.height-50&&Input.GetTouch(0).position.x>Screen.width-50)
-
{
-
Application.Quit();
-
}
-
}
-
-
elseif(Input.touchCount==2)
-
{
-
Player_Move();
-
Player_Look();
-
Attack();
-
}
-
}
-
-
-
functionPlayer_Move()
-
{
-
switch(Input.GetTouch(0).phase)
-
{
-
caseTouchPhase.Began:
-
PO_X=Input.GetTouch(0).position.x;
-
PO_Y=Input.GetTouch(0).position.y;
-
PC_X=PO_X;
-
PC_Y=PO_Y;
-
-
varray=Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
-
if(Physics.Raycast(ray,hit))
-
{
-
if(hit.collider.gameObject.tag=="Enemies")
-
{
-
Focus=true;
-
Enemie=hit.transform.position;
-
}
-
elseif((PO_X>200||PO_Y>200)&&(PO_X<Screen.width-100||PO_Y>100))
-
{
-
Focus=false;
-
Camera.main.depth=-1;
-
}
-
}
-
break;
-
caseTouchPhase.Moved:
-
PM_X=Input.GetTouch(0).position.x;
-
PM_Y=Input.GetTouch(0).position.y;
-
if(PO_X<200&&PO_Y<200&&PO_X>0&&PO_Y>0)
-
{
-
PR_M=true;
-
}
-
elseif(Input.touchCount==1)
-
{
-
touchDeltaPosition=Input.GetTouch(0).deltaPosition;
-
-
if(Player_true.transform.localEulerAngles.x<=60||Player_true.transform.localEulerAngles.x>=310)
-
{
-
Player_true.transform.Rotate(Vector3(touchDeltaPosition.y,touchDeltaPosition.x,0)*Time.deltaTime*100*Speed_L,Space.World);
-
}
-
elseif(Player_true.transform.localEulerAngles.x<310&&Player_true.transform.localEulerAngles.x>200)
-
{
-
Player_true.transform.localEulerAngles.x=311;
-
}
-
elseif(Player_true.transform.localEulerAngles.x>60&&Player_true.transform.localEulerAngles.x<200)
-
{
-
Player_true.transform.localEulerAngles.x=59;
-
}
-
Player_true.transform.localEulerAngles.z=0;
-
}
-
break;
-
caseTouchPhase.Ended:
-
PO_X=0;
-
PO_Y=0;
-
PM_X=0;
-
PM_Y=0;
-
PC_X=0;
-
PC_Y=0;
-
PR_M=false;
-
Role.animation.Stop("Run");
-
Role.animation.Stop("Back");
-
Role.animation.Stop("Right");
-
Role.animation.Stop("Left");
-
Role.animation.PlayQueued("Wait",QueueMode.CompleteOthers);
-
break;
-
}
-
-
if(PR_M)
-
{
-
M_X=PM_X-PC_X;
-
M_Y=PM_Y-PC_Y;
-
-
Distance=Mathf.Sqrt((M_X*M_X)+(M_Y*M_Y));
-
-
Angles=Mathf.Atan2(M_X,M_Y)*Mathf.Rad2Deg;
-
-
if(Distance>=50)
-
{
-
PC_X=PC_X*15/16+PM_X/16;
-
PC_Y=PC_Y*15/16+PM_Y/16;
-
}
-
-
-
if(M_X>40)
-
{
-
M_X=40;
-
}
-
elseif(M_X<-40)
-
{
-
M_X=-40;
-
}
-
if(M_Y>50)
-
{
-
M_Y=50;
-
}
-
elseif(M_Y<-30)
-
{
-
M_Y=-30;
-
}
-
-
-
if(Angles>=-45&&Angles<=45)
-
{
-
Role.animation.CrossFade("Run");
-
if(Angles>=-20&&Angles<=20)
-
{
-
M_X=0;
-
}
-
}
-
elseif(Angles>=135||Angles<=-135)
-
{
-
Role.animation.CrossFade("Back");
-
if(Angles<=-160||Angles>=160)
-
{
-
M_X=0;
-
}
-
}
-
elseif(Angles>45&&Angles<135)
-
{
-
Role.animation.CrossFade("Right");
-
if(Angles>=70&&Angles<=110)
-
{
-
M_Y=0;
-
}
-
}
-
elseif(Angles>-135&&Angles<-45)
-
{
-
Role.animation.CrossFade("Left");
-
if(Angles>=-110&&Angles<=-70)
-
{
-
M_Y=0;
-
}
-
}
-
-
-
-
transform.localRotation=Quaternion.Euler(0,Player_true.transform.localEulerAngles.y,0);
-
-
-
-
-
transform.Translate(M_X*Time.deltaTime*Speed,0,M_Y*Time.deltaTime*Speed);
-
}
-
}
-
-
-
functionPlayer_Look()
-
{
-
switch(Input.GetTouch(1).phase)
-
{
-
caseTouchPhase.Began:
-
PT_X=Input.GetTouch(1).position.x;
-
PT_Y=Input.GetTouch(1).position.y;
-
M_X=PO_X-PT_X;
-
M_Y=PO_Y-PT_Y;
-
Distance=Mathf.Sqrt((M_X*M_X)+(M_Y*M_Y));
-
break;
-
caseTouchPhase.Moved:
-
PS_X=Input.GetTouch(1).position.x;
-
PS_Y=Input.GetTouch(1).position.y;
-
if(PR_M&&!Focus)
-
{
-
touchDeltaPosition=Input.GetTouch(1).deltaPosition;
-
Player_true.transform.Rotate(Vector3(0,touchDeltaPosition.x,0)*Time.deltaTime*160*Speed_L,Space.World);
-
Player_true.transform.Rotate(Vector3(touchDeltaPosition.y,0,0)*Time.deltaTime*90*Speed_L,Space.World);
-
Player_true.transform.localEulerAngles.z=0;
-
}
-
elseif((PO_X>200||PO_Y>200)&&(PT_X>200||PT_Y>200))
-
{
-
M_X=PS_X-PM_X;
-
M_Y=PS_Y-PM_Y;
-
Distance_D=Mathf.Sqrt((M_X*M_X)+(M_Y*M_Y));
-
if(Distance-Distance_D>20&&Camera.main.transform.localPosition.z<=0)
-
{
-
Camera.main.transform.localPosition.z+=0.1;
-
Camera_Record=Camera.main.transform.localPosition.z;
-
Distance=Distance_D;
-
}
-
elseif(Distance-Distance_D<-20&&Camera.main.transform.localPosition.z>=-4)
-
{
-
Camera.main.transform.localPosition.z-=0.1;
-
Camera_Record=Camera.main.transform.localPosition.z;
-
Distance=Distance_D;
-
}
-
}
-
break;
-
caseTouchPhase.Ended:
-
PT_X=0;
-
PT_Y=0;
-
PS_X=0;
-
PS_Y=0;
-
Distance=0;
-
Distance_D=0;
-
break;
-
}
-
}
-
-
-
functionAttack()
-
{
-
-
if(Input.GetTouch(0).position.y<100&&Input.GetTouch(0).position.x>Screen.width-100&&!(Role.animation.IsPlaying("Attack")))
-
{
-
Role.animation.Play("Attack");
-
Role.animation.CrossFadeQueued("Wait",0.3,QueueMode.CompleteOthers);
-
CreationTime=Time.time;
-
Attacking=true;
-
}
-
-
elseif(PR_M&&Input.GetTouch(1).position.y<100&&Input.GetTouch(1).position.x>Screen.width-100&&!(Role.animation.IsPlaying("Attack")))
-
{
-
PR_M=false;
-
Role.animation.CrossFadeQueued("Attack",0.3,QueueMode.PlayNow);
-
Role.animation.CrossFadeQueued("Wait",0.3,QueueMode.CompleteOthers);
-
CreationTime=Time.time;
-
Attacking=true;
-
}
-
}
-
-
functionOnGUI()
-
{
-
GUI.Box(Rect(0,Screen.height-200,200,200),"Rocker");
-
GUI.Box(Rect(Screen.width-50,0,50,50),"Quit");
-
GUI.Box(Rect(Screen.width-100,Screen.height-100,100,100),"Attack");
-
}
啊,好长,其实也不多,就300行+,上面有羽化的一些注释,大家可以看看这个脚本,Rocker是绑在Player上的,大家可以从上一张图看到,羽化见了两个Player,一个叫Player_True的物体其实是一个空物体里面放置了一些基本东西包括光和摄像机,旋转视角的时候就是旋转的Player_True,其中的好处只有用过的人才能了解吧~ ~。羽化使用了预设制作攻击,这是个权益之计,以后说不定会改,这里最多判断了两个点的触控情况,羽化是分别判断的,这是吸取了前一个游戏的经验,这样不会乱,因为移动,攻击,转视角全部如果写在一个判断里面会造成很多冲突,羽化深有体会。
3.视角限制设计
前面部分羽化用不了半天就完成了,后面的视角限制花了将近2天时间,当然个人能力有限也是原因吧。这是我这次博客的重头,如何运用射线,我们主要说说Physics.Raycast这个脚本的应用,在Unity帮助文档里面提到了,这里羽化尝试了下,最好使用Raycast
(origin :Vector3,direction :Vector3,out
hitInfo :RaycastHit,distance : float =Mathf.Infinity,layerMask
: int = kDefaultRaycastLayers),这个方法,别的不一定靠谱。。。有的地面会莫名其妙穿过去。
CameraZoom.js:
-
varUp:Transform;
-
privatevarForward:boolean=false;
-
privatevarBack:boolean=false;
-
-
functionUpdate()
-
{
-
-
varlayerMask=1<<2;
-
layerMask=~layerMask;
-
-
varhit:RaycastHit;
-
-
-
if(Physics.Raycast(transform.position,Camera.main.transform.TransformDirection(Vector3.forward),hit,(-Camera.main.transform.localPosition.z)))
-
{
-
Forward=true;
-
vardistanceToForward=hit.distance;
-
if(Camera.main.transform.localPosition.z<-0.5)
-
{
-
Camera.main.transform.localPosition.z+=0.05;
-
}
-
}
-
else
-
{
-
Forward=false;
-
}
-
-
-
if(Physics.Raycast(transform.position,Camera.main.transform.TransformDirection(Vector3.forward*(-1)),hit,0.2,layerMask))
-
{
-
Back=true;
-
vardistanceToBack=hit.distance;
-
if(distanceToBack>0.1)
-
{
-
Back=false;
-
}
-
}
-
-
-
if(Physics.Raycast(transform.position,-Vector3.up,hit,(-2)*Rocker.Camera_Record,layerMask))
-
{
-
vardistanceToGround=hit.distance;
-
-
}
-
if(distanceToGround<0.1)
-
{
-
Camera.main.transform.localPosition.z+=0.1;
-
}
-
elseif(Camera.main.transform.localPosition.z>Rocker.Camera_Record&&distanceToGround>0.2&&!Back&&!Forward)
-
{
-
Camera.main.transform.localPosition.z-=0.02;
-
Camera.main.transform.localPosition.y=0.6;
-
}
-
-
if(!Rocker.Focus)
-
{
-
transform.LookAt(Up);
-
}
-
}
-
-
functionOnTriggerStay(other:Collider)
-
{
-
if(Camera.main.transform.localPosition.z<-0.4)
-
{
-
Camera.main.transform.localPosition.z+=0.02;
-
}
-
Back=true;
-
}
-
-
functionOnTriggerExit(other:Collider)
-
{
-
Back=false;
-
}
首先,羽化开始认为只有一个射线就可以搞定了,结果一个射线什么都判断不了,后来羽化仔细想了想就写成了三个射线,加上一个判断,终于效果出现了,话说羽化在摄像机设置Collider,是怕一个不小心,玩家把整个地图看透了-0- 如果你想视角更舒畅点可以把other.attachedRigidbody的注释去掉。这里有个函数layerMask是判断射线穿过那个层的,以后肯定用得上,1<<2代码射线只能穿过前两层。
4.简单的战斗部分
战斗部分很简单,做一个攻击预设,触发攻击动作时就产生预设,在极短时间给怪物造成伤害。绝大多数代码都在移动部分了,这里看看一个简单的AI。
AI.js:
-
varrange=4;
-
varPlayer:Transform;
-
privatevarhealth=10;
-
-
functionUpdate()
-
{
-
Discover();
-
}
-
-
functionOnTriggerEnter(other:Collider)
-
{
-
if(other.attachedRigidbody)
-
{
-
if(other.gameObject.tag=="Attack")
-
{
-
Rocker.Test=10.2;
-
transform.Find("Small").animation.CrossFade("Hit");
-
transform.Find("Small").animation.CrossFadeQueued("Wait",0.3,QueueMode.CompleteOthers);
-
health--;
-
if(health<=0)
-
{
-
transform.Find("Small").animation.CrossFade("Dead");
-
Rocker.Focus=false;
-
Camera.main.depth=-1;
-
transform.tag="Dead";
-
}
-
}
-
}
-
}
-
-
functionDiscover()
-
{
-
varlayerMask=1<<3;
-
layerMask=~layerMask;
-
-
if(Vector3.Distance(transform.position,Player.position)>range)
-
{
-
returnfalse;
-
}
-
-
varhit:RaycastHit;
-
if(Physics.Linecast(transform.position,Player.position,hit,layerMask))
-
{
-
if(hit.collider.gameObject.tag=="Player"&&!(transform.Find("Small").animation.IsPlaying("Dead")))
-
{
-
transform.LookAt(Player);
-
returntrue;
-
}
-
else
-
{
-
returnfalse;
-
}
-
}
-
-
returntrue;
-
}
怪物在一定范围内会发现你,面朝向敌人,简单的AI,可以添加怪物行走等,这就看大家对自己什么要求了,当玩家点击怪物后会进入战斗视角,这时的移动时围绕怪物的,是不是很像Fable~ ~羽化的Demo就初步完成了,最后来张截图。
自己认为视角做得很棒,有什么不足还望指出~ ~
本文转自羽化:http://blog.csdn.net/libeifs/article/details/6696424
APK下载地址:
http://dl.dbank.com/c0bbqt1p13
分享到:
相关推荐
Unity3D第三人称视角,和博客是同步的,有需要请下载。
Unity UGUI第三人称视角手游 左侧控制移动,右侧控制视角和方向 (可根据自己需求修改)
Unity3D第三人称视角摄像头脚本,代码都有注释,选择target摄像头即可跟随
移动端第三人称控制 左手摇杆 右手相机(CSDN 动态调分了 现在降价)
Unity第三人称角色视角系统,方便好用,只需添加两个脚本就能完成你想要的功能
Unity UGUI 通过摇杆 joystick 控制角色移动(第三人称视角)包含资源和例子,要实现王者荣耀,英雄联盟手游第三人称跟随相机只需加 一句代码 **Vector3.Lerp()这一句代码** 或者直接**做成人物子物体**更简单粗暴
UNITY 第三人称 人物移动代码详解 UNITY 第三人称 人物移动代码详解
教您学会用unity3D用第三人称模式,控制角色,内含工程资源文件
(免积分下载)游戏场景精美,包含山谷房屋桌椅等等模型,鼠标控制小狐狸移动,有血条,有菜单有按钮等等,详情请看我发布的文章介绍
unity 第三人称相机跟随脚本
Unity3D官方第三人称角色控制工程文件
Learn Unity for Android Game Development 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除
Unity3D For Android.pdf
Unity第三人称视角解决方案.docx
unity android 照片读取保存 截取 拍照获取手机上的图片
Unity的一款很好用的插件 第三人称摄像机 内附案例场景 可自行研究学习
第三人称是视角意味着摄像机跟随着角色移动而不是在角色内移动,模拟阴影,像实时阴影和光照贴图,改善图像。
Unity3d第三人称控制Unity3d第三人称控制Unity3d第三人称控制
Unity3d第三人称游戏
Unity 3D第三人称视野简单实现,竖轴限定用途广泛。 很多新手没有思路去写一个第三人称的视角限定的相机控制脚本。本demo才用中文编写,简单易懂。 便于新手理解!!!