Unity小记

来源:互联网 发布:黑马java培训怎么样 编辑:程序博客网 时间:2024/06/03 15:34
GDGeek工具集介绍:
FSM:方便开发的有限状态机库,特点是可以支持多层次的有限状态机结构
JsonFx:使用广泛的Json解析工具,GDGeek工具集中单独处理了JsonFx对IOS平台的兼容问题
Task:任务管理工具库,基于任务管理工具库游戏中的大部分动作都封装成任务。大大简化开发流程
Toolkits:保存了一些游戏开发中很有价值的代码片段
Tweener:对不同的几个补间动画库综合处理,既提供了可靠的效率又提供了多样性的插值方式。
Web:结合HTTP协议的非持续连接性的网络客户端框架
MVC编程模式:
Model(模型):表示应用程序核心(数据库记录列表)
View(视图):显示数据(数据库记录)
Controller(控制器):处理输入(写入数据库记录)
AddForce (x : float, y : float, z : float, mode : ForceMode.mode(mode取持续力Force、Acceleration或瞬间力Impulse、Velocitychange) 添加一个力到刚体。作为结果刚体将开始移动,可以消除脚本移动的抖动效果。 
具体用法老版本是rigidbody.addforce(),新版本是GetComponent(Rigidbody).AddForce() 或Getcomponent<Rigidbody>().AddForce(),记得先要给物体添加Rigibody属性。此外给刚体施加力一般写在固定更新函数FixedUpdate()中,2D刚体是Rigibody2D。

移动物体有几种方案:
1.直接改变物体的世界坐标或者相对坐标:gameobject.transform.Position += new Vector3(x,y,z);transform.Position += Input.GetAxis("Horizontal")*transform.right * speed * Time.deltaTime;该方法通常用于一次性或者短暂性移动
2.用Translate:把游戏对象移动相应的方向和距离,该方法常用于随着时间持续移动
  Vector3 mMovement = new Vector3(Input.acceleration.x*speed*Time.deltaTime,0);
  transform.Translate(mMovement); //acceleration.x 获取输入的加速度的X轴分量
3.给物体加上Rigibody属性,然后给一个力:GetComponent<Rigidbody>().AddForce(direction * speed);通常用于物理惯性移动比如子弹飞或者石头滚动等
  也可以给刚体一个速度:GetComponent<Rigidbody>().velocity = target.transform.TransformDirection(vector3.forward*20);
speed可以直接取GetComponent<Rigidbody>().velocity。

update()是每帧执行一次;
Time.deltaTime:游戏通常使用该值来产生与游戏帧速率无关的效果。Time.deltaTime = 1.0f / 帧率, 如果游戏卡,帧率低,那这个值就大;所以*Time.deltaTime以每秒钟10米的速度移动而不是每帧10米;update()里面timer += Time.deltaTime; if(timer > tTime){}使程序按需要的时间来执行;
FixedUpdate中使用Time.fixedDeltaTime,获取到的是在编辑器中设置的 固定值
Time.timeScale控制游戏速度,0时暂停,1正常,2双倍速度timeScale不会影响Update和LateUpdate的执行速度。因为FixedUpdate是根据时间来的,所以timeScale只会影响FixedUpdate的速度。粒子特效不受timeScale影响,相关博客http://www.xuanyusong.com/archives/2956


Lerp函数可以实现两种不同状态的平滑过度,位移,颜色,数学公司等许多都有实现该函数,参数大都是Lerp(ValueA,ValueB,SmoothParam,Time);如:Vector3.Lerp(CurrentPos, TargetPos,SmoothParam * Time.deltaTime);

Mathf.Abs():求绝对值。Mathf.Clamp(value,min,max):限制value变量的范围。更多数学函数参考:http://zhboy666666.iteye.com/blog/1679637

Character Controller:在使用摄像机游览场景的时候,需要控制摄像机不穿透场景中的物体,这需要用到碰撞。在unity物理引擎中有两类的情况可以检测到碰撞,一种是一方是刚体+碰撞器和另一方碰撞器碰撞(参加碰撞器和刚体),另一种就是Character Controller与其他的碰撞器碰撞的时候

在使用摄像机游览场景的时候,虽然需要去碰撞检测,但是一个特别的要求就是摄像机和其他物体碰撞之后不能对它们产生任何力的作用,同时摄像机本身也不需要受到模拟真实碰撞的反作用力,也就是说这个时候给摄像机挂载刚体属性还是不大适合的

这个时候Character Controller就被制作出来满足这种需求,Character Controller本身自带一个碰撞器,无需刚体即可完成触发(Trigger)和碰撞(Collision)功能。




<消息传递机制>
1.Gameobject.SendMessage:向自身的脚本中发送消息
2.Gameobject.BroadcastMessage:向自身及子物体的脚本中发送消息
3.Gameobject.SendMessageUpward("funcName",param,SendMessageOption.RequireReceiver);:向自身及父物体中发送消息
4.委托delegate: c#中 Delegate(委托)类似C和C++中的函数指针,具体:http://www.cnblogs.com/hyddd/archive/2009/07/26/1531538.html
一个委托的例子:在给立方体cube绑定EventDispatcher.cs脚本,其他物体(可多个)绑定Listen.cs脚本,
EventDispatcher.cs:
    public delegate void EventHandler(GameObject e);      public event EventHandler MouseOver;      void OnMouseOver () {      if (MouseOver != null)          MouseOver (this.gameObject);    } 
Listen.cs:
    void Start () {        EventDispatcher ev = GameObject.Find("Cube").GetComponent<EventDispatcher>();         ev.MouseOver += ListeningFunction;//Register the listener(and experience the beauty of overloaded operators!)     }    void ListeningFunction (GameObject e) {         this.transform.Rotate(20, 0, 0); // 'e' is the game object that dispatched the event         //e.GetComponent<EventDispatcher>().MouseOver -= ListeningFunction; //Remove the listener         Debug.Log("mouse is over: "+e);    }
当鼠标停留在事件发生器cube上时,监听的其他物体就会不断旋转

<Instantiate>
Instantiate(m_rocket, m_transform.position,m_transform.rotation):创建一个预设物,克隆原始物体(包括对象的层次和子物体),并设置位置和角度.
让预置体生在Tank的子节点上,只需要在Tank的脚本上进行如下操作:
  1.public Gameobject GoBullet,并把预置体拖到GoBullet上
  2.private Gameobject bullet;
  3.在start函数下:bullet = Instantiate(GoBullet); bullet.transform.parent = this.transform;
 4.设置时间lifetime后销毁,利用destroy();

但是子弹这种重复出现的物体如果每次都动态创建再销毁,对性能开销很大,应该应用缓存管理物体,一次创建并克隆多个子弹,但是设置为非活跃setActive(false),需要用的时候循环遍历对象列表找到非活跃的对象并设置为活跃状态

生成物体时播放粒子特效:
    foreach(ParticleSystem p in GetComponentsInChildren<ParticleSystem>())
    {
        p.Play();
    }

控制开火:target.SendMessage("OnStarFire");就会调用target对象脚本中的OnStartFire ()方法。
定义信号发生器:public SignalSender xx; 在组件属性面板的Receiver设置Action行为和receive接收者。当调用xx.Sendsignals(gameobj,gameobj)时,就会触发接收者receive中的Action方法

<collide>
collider有box collider、sphere collider、mesh collider等多种碰撞体,其中mesh collider是根据物体形状绘制的,最为精确,但是消耗性能也最高,慎用。
当collider组件勾选了Is Triger,脚本中的离开OnTriggerEnter()、停留OnTriggerStay()、离开OnTriggerExit()三个方法会被依次触发
同理加上Rigidbody组件后,OnCollisionEnter()、OnCollisionStay()、离开OnCollisionExit()会被触发,比如子弹打物体造成物体运动效果

<A>
w
<Ray>
RayCast(Vector3,Direction,distance,raylengh):
function Update () {    var hit:RaycastHit;    if(Physics.Raycast(transform.position,transform.forward,hit,8))    //射线长度8米,不指定时表示无限长    {        print("射线触碰了"+hit.collider.gameObject+"物体");    }}
射线检测可以用于检测子弹是否打击到物体,取代子弹物理碰撞检测,或者检测刀剑是否砍中敌人,并且触发流血特效等应用
示例:根据鼠标点击位置移动物体(引一条摄像机到鼠标点击位置pos=Input.mousePosition的射线,看落在哪个Collider,计算出位置)自动寻径
protected  void  SetDestination(){ var  ray  =  Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit  hit  = new RaycastHit();if (Physics.Raycast(ray,out hit)){if(particleClone!= null){GameObject.Destroy(particleClone);particleClone =  null;}Quaternion q = new Quaternion();q.SetLookRotation(hit.normal, Vector3.forward);         //四元数,由x,y,z和w四个分量组成一个四维空间。unity中基本本的旋转可以通过Transform.Rotate来实现,但是当我们希望对旋转角度进行一些计算的时候,就要用到四元数Quaternion了            particleClone = Instantiate(particle, hit.point, q);    //hit.point射线落点agent.destination  =  hit.point;    //agent  =  GetComponent<UnityEngine.AI.NavMeshAgent>();        }}



对于2D游戏,射线检测函数是bool LInecast(Vector2 start,Vector2 end,int LayerMask);当start和end的连线接触到碰撞器返回真。此函数只返回第一个碰撞器,要返回并报告射线检测的所有碰撞器则用LinecastOut().。2D游戏可以创捷一个名为ground的空物体在目标物体的正下方,利用Physics2D.Linecast(TragetTransform.position,ground.position,1<<LayerMask.NameToLayer("Ground"))向下发射射线来检测物体是否在地面上或者空中(LayerMask实际上是一个位码操作,在Unity3D中Layers一共有32层,当这个位为1时表示使用这个层,为0时表示不用这个层,1<<LayerMask.NameToLayer("Ground")这一句实际上表示射线查询只在Ground所在这个层级查找)。

<A>
w


<GUI>
Button()创建一个button,当点击时返回true,具体参考http://www.ceeger.com/Script/GUI/GUI.Button.html
GUI.RepeatButton在鼠标点击不松开时会重复执行
GUILayout:根据文本内容自动设置长度和位置,如.LabelGUI.Layout("XXX");
GUI.TextField:文本输入框,可以把输入文本赋值给一个变量,实时改变显示:String text = GUI.TextField(Rect(140,130,100,40),text);
GUI.Toggle:开关控件,bool toggle = GUI.Toggle(Rect(140,170,100.20),toggle,"Toggle");
GUI滑块,var float hSliderValue = 0.0; hSlideValue = GUI.HorizontalSlider(Rect(100,100,100,100),hSliderValue,startvalue0,endValue10); //还有垂直方向滑块类似
GUI.Toolbar:工具条,int toolbatInt = 0; String[] toolbarStrings = ["Toolbar1","Toolbar2","Toolbar3"]; toolbarInt = GUI.Toolbar(Rect(10,210,100,20),toolbarInt,toolbarStrings);
GUI.SelectionGrid:网格控件,用法和工具条一样,多一个参数表示每行最多几列,每次只能选中一个
GUI.Changed:GUI的变量,一个总开关,当GUI控件的状态发生变化,该值为真
GUI.BeginGroup(Rect()),GUI.EndGroup(),GUI群组,GUI群组中间的控件会以GUI群组的位置进行重新布局,比如Rect(0,0,0,0)的按钮将在群组位置左上角而不是屏幕左上角,可以嵌套使用组达到动态效果,比如血量变化的效果

设置一个按钮,当鼠标移动到按钮时能出现小标签提示:
function OnGUI(){if(GUI.Button(Rect(10,10,120,110),GUIConten("button按钮",“这是一个工具提示”))){print("用户单击了按钮");}GUI.label(Rect(10,120,100,20),GUI.tooltip);}
GUI动态窗口的实现:
#pragma strictvar windowShoworNot:boolean = true;var windowRect : Rect = Rect (10, 60, 120, 50);function OnGUI(){   windowShoworNot=GUI.Toggle(Rect(10,10,100,20),windowShoworNot,"窗口显示or Not");   if(windowShoworNot)      windowRect= GUI.Window(0,windowRect,MyWindowFunction,"我的窗口"); }function   MyWindowFunction(windowID : int){   if(GUI.Button(Rect(10,20,100,20),"窗口内按钮"))         print ("在窗口控件内被单击");            GUI.DragWindow(Rect(0,0,10000,10000));//窗口在一定范围内可拖动}

<Animator>
P
Protect Animator animator;public float DirectionDampTime = 0.25f;//if(animator.layerCount>=2) animator.SetLayerWeight(1,1);//设置默认动画层权重1AnimotorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);  //获取当前动画状态,参数代表层的索引处,0表示Base Layerif(stateInfo.IsName("Base Layer.Walk")){    if(Input.GetButton("Fire1"))        animator.SetBool("Jump",true);  //Jump是Base Layer层中添加的bool型动画参数    else        animator.SetBool("Jump",false);}float horizontal = Input.GetAxis("Horzontal");animator.SetFloat("Direction",horizontal,DirectionDampTime,Time.deltaTime);
Blend Tree:复合动画
IK手柄:使用脚本实现人物手抓球体的效果(动画控制器要勾选IK Pass):
protected Animator animator;private bool ikActive = false;public Transform rightHandObj = null;   //右手要抓取的目标物体void start(){    animator = GetComponent<Animator>();}void OnAnimatorIK() //Animator组件的回调函数,在调用内部IK系统前调用{    if (animator)    {        //animator.MatchTarget(position,rotation,AvatarTarget.RightHand,new MatchTargetWeightMask(new Vector3(1,1,1),0),startMatchTime,endMatchTime);        if(ikActive)        {            animator.SetIKPositionWeight(AvatarIKGoal.RightHand,1.0f);  //设置IK手柄的位置权重,AvatarIKGoal.RightHand为定义好的枚举值,表示右手            animator.SetIKRotationWeight(AvatarIKGoal.RightHand,1.0f);            if (rightHandObj)            {                animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandObj.position);                animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandObj.rotation);            }            else            {                animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 0.0f);                 animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 0.0f);            }            //animator.SetLookAtPosition(targetPosition);        }    }}
出现过Animator组件添加动画状态机后物体能正常播放动画但是无法移动的情况,经过排查最后发现添加的两个动画片段中误添加了Player:Rotation和Player:Anchored Rotation两个组件曲线导致角色位置固定在某处
更多状态机细节参考“http://blog.csdn.net/qq_34134078/article/details/53092653


<A>
w


动态加载资源:
private GameObject bullet;
 GoBullet = Resources.Load("Bullet") as GameObject;  //通过资源加载的方法,加载对象Bullet必须放在Resource文件夹下,用这种方法就不用把Gobullet声明成public并拖动Bullet到GoBullet下
协程:协同程序,即在主程序运行时同时开启另一段逻辑处理,来协同当前程序的执行,换句话说,开启协同程序就是开启一个线程,关键字如下:
IEnumerator func(); Yield return x; StartCoroutine(func());StopCoroutine("funcName");
注意Yield return 和return不一样,Yield语句是一种特殊类型的返回语句,不会终止该程序的执行,他可以确保函数在下次被执行时从Yield语句处开始,而不是从头开始。可以用Yield WaitForSeconds(3);来等待3秒执行,等待过程系统不会停在此处而是线下继续执行。
具体可以参考:http://blog.csdn.net/huang9012/article/details/38492937
数据结构最常用的是数组,List,字典,队列,其中字典是C++中的map,就是键值key和value一一对应的数据结构,游戏中比如通过下拉菜单选择区服角色时就需要用到字典
c#中字典dictionary的用法和用途:
  http://www.cnblogs.com/linzheng/archive/2010/12/13/1904709.html
  http://www.cnblogs.com/ccczqh/archive/2011/01/04/1925852.html 
c#中 Delegate(委托)类似C和C++中的函数指针,具体:http://www.cnblogs.com/hyddd/archive/2009/07/26/1531538.html
替换新的场景有不同情况:
1.把场景scene保存并设置好顺序,Application.Loadlevel(x),通常用于跳转不同地图,如Pokemon选择有卡或者脱卡后的页面跳转
2.场景做好后设置成预置体,放在Resources/Prefab文件下,Destroy(gameobject)销毁当前场景 ,通过Instantiate(Resources.Load("Prefab/" +xxx)) ad GameObject创建预置体并设置好位置信息来加载新的场景,通常用于UI的改变,如登陆界面->loading->UI
3.通过设置对象的活动状态来实现:gameObject1.SetActive(false);gameObject2.SetActive(true);通常用于同一场景中元素的替换,如五子棋界面跳转,万圣节场景元素依次出现
编辑物体的Inspector的某个组建属性方法:
1.直接面板改;
2.通过脚本GetComponent(Rigidbody).()获取并修改
3.在脚本里public MeshRenderer _mesh = null;;从自身属性面板拖动MeshRenderer组件进去或者创建一个名为对象比如cube拖过去,创建的对象要具有变量类型的属性比如MeshRenderer等才能拖过去,然后就可以在脚本里面_mesh.material.mainTexture = _texutres[value -1]; //material.mainTexture是材质的主纹理,是Material.Texture的一个接口实现。
截透明通道图:texture2D = new Texture2D(800,600,TextureFormat.ARGB32,false);
代码添加贴图:
GameObject myCute; void Start () {    myCute = GameObject.Find("Cube");    myCute.renderer.material.mainTexture = Resources.Load("images/zjy") as Texture;}


绘制纹理:
private var oneTexture:Texture2D;oneTexture = Resource.Load("Texture/Grass");if(oneTexture != null)    GUI.DrawTexture(Rect(110,20,120,120),oneTexture,ScaleMode.StretchToFill,true,0);


static function CreatePrimitive (type : PrimitiveType) : GameObject,创建一个带有基本网格渲染器和相应碰撞器的游戏物体,如:

var cube : GameObject = GameObject.CreatePrimitive(PrimitiveType.Cube);cube.transform.position = Vector3(0, 0.5, 0);

Shader着色器http://blog.csdn.net/poem_qianmo/article/category/2681301 和http://blog.csdn.net/zhuangyou123/article/details/26077783
对于游戏中对物体施加力使物体移动后,如果力大一点可能出现物体贴在平台比如梯子的边缘而不掉下去,解决此种问题可以在平台边缘加一个碰撞器,并在材质上指定添加一个摩擦力Friction为0的物理材质Physic Material即可
地图编辑器,六角形导航网格:Tile Based Map and Nav
============================================================================
<Input>
  1. // 手指刚触摸到屏幕的时候  
  2. Input.GetTouch(0).phase  == TouchPhase.Began;  
  3. // 手指在屏幕上移动  
  4. Input.GetTouch(0).phase  == TouchPhase.Moved;  
  5. // 手指触摸屏幕,但并未移动  
  6. Input.GetTouch(0).phase  == TouchPhase.Stationary;  
  7. // 手指从屏幕上移开,这是一个触控的最后状态  
  8. Input.GetTouch(0).phase  == TouchPhase.Ended;  
  9. // 系统取消追踪触控。这常发生在用户把屏幕放到脸上或者同时触控超过了5根手指,同样也是触控的最后一个状态  
  10. Input.GetTouch(0).phase  == TouchPhase.Canceled;  
unity常用事件响应函数:

OnMouseEnter  鼠标移入GUI控件或者碰撞时才响应

OnMouseOver     鼠标停留GUI控件或者碰撞时才响应

OnMouseExit       鼠标移出GUI控件或者碰撞时才响应

OnMouseDown  鼠标按下GUI控件或者碰撞时才响应  

OnMouseUp      鼠标释放GUI控件或者碰撞时才响应

OnTriggerEnter  当其他碰撞进入触发器的时候调用

OnTriggerExit    当其他碰撞离开触发器的时候调用

OnTriggerStar  当其他碰撞处于触发器的时候调用

OnCollisionEnter 当其碰撞或者刚体与其他碰撞器或者刚体发生碰撞响应

OnCollisionStar 当其碰撞或者刚体停留其他碰撞器或者刚体发生碰撞响应

OnCollisionExit  当其碰撞或者刚体离开其他碰撞器或者刚体发生响应

OnControllerColliderHit  当控制器移动时与碰撞体发生碰撞时调用

OnBecameVisible 对于任意一个相机可见时调用

OnBecameInVisible 对于任意一个相机不可见时调用

OnEnable 对象启用或者激活状态时调用

OnDisable 对象禁用或者取消激活时候调用

OnDestroy 脚本销毁时候调用

OnGUI  渲染GUI和处理GUI消息时调用

下面是Input类的成员变量:

下面是Input类的成员函数: 

 Input输入与控制详细看PDF《Unity 5.x从入门到精通》第二十章

GetKey和Getbutton区别:

(1)GetKey两种参数形式Input.GetKey("up")和Input.GetKey(KeyCode.UpArrow),参数是虚拟按键的映射键值,常用于需要检测按键数值范围

(2)GetButton:Input:GetButtonDown("Fire1"),即参数是虚拟按键的名称,常用于检测事件性按键比如开火,不需要关心按键范围

在OnGUI()函数里面 var e : Event = Event.current; if(e.isMouse && e.button == 0/1/2/>2)分别代表鼠标各按键,但是OnGUI函数一帧会被执行多次,所以会出现多次执行的情况;if(e.isMouse && e.clickCount ==2)代表用户双击了鼠标

-------------------------------------------

1. 移动平台上播放视频,提示错误error CS0246: The type or namespace name `MovieTexture' could not be found. Are you missing a using directive or an assembly reference?经测试以上的方式在IOS和Android设备中是无法播放视频的,在移动设备上我们需要使用另外一种方式来播放。movetecture这种方法在移动平台是没法使用的。有另外一种方法,用UI来播放:
using UnityEngine;using System.Collections; public class Test : MonoBehaviour { void OnGUI(){    if (GUI.Button (new Rect (20,10,200,50), "PLAY ControlMode.CancelOnTouch")) {       Handheld.PlayFullScreenMovie("test.mp4", Color.black, FullScreenMovieControlMode.CancelOnInput);} if (GUI.Button (new Rect (20,90,200,25), "PLAY ControlMode.Full")) {       Handheld.PlayFullScreenMovie("test.mp4", Color.black, FullScreenMovieControlMode.Full);} if (GUI.Button (new Rect (20,170,200,25), "PLAY ControlMode.Hidden")) {        Handheld.PlayFullScreenMovie("test.mp4", Color.black, FullScreenMovieControlMode.Hidden);} if (GUI.Button (new Rect (20,250,200,25), "PLAY ControlMode.Minimal")) {       Handheld.PlayFullScreenMovie("test.mp4", Color.black, FullScreenMovieControlMode.Minimal);} }


2.的

原创粉丝点击