2012-11-05 22:52:28 liangZG_2011 阅读数 3961
  • Unity3D入门到精通-(4)Unity热更新

    本次系列课程的目标是让Unity3D初学者掌握C语言,Untiy调用lua脚本深入理解uLua框架实现原理,并根据项目的特点实现相应的热更新方案。 适合对象:Unity初学开发者,Unity中级开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    2207 人正在学习 去看看 张刚

关于Unity3D对象和脚本实例调用的顺序探究

我们先来看一些有趣Unity实例顺序的小实验。有图有真相!!

 

注:以上打印的代码语句如下:

    void Start () {
       print("-----" + this.transform.name);
    }
   

从以上的打印我们至少可以得出的实验结果!

 

总结:Unity从树形目录的最底端的最深层开始实例化对象,然后逐个向上实例!

 

 

 

 

 

我们再来实验下关于脚本生命周期的小实验:

 

关于脚本的生命周期网上和官方都有很多资源,这里主要实验是关于对象的实例顺序及对象依附脚本的执行顺序!

 

脚本代码:

public class GroupData : MonoBehaviour
{
 
    void Awake()
    {
       print("--" + this.transform.name+ "-------Awake-----------------");
    }
 
    // Use this for initialization
    void Start()
    {
       print("----Start-" + this.transform.name);
    }
 
    // Update is called once per frame
    void Update()
    {
 
    }
 
    void OnDestroy()
    {
       print("*******************"+ this.transform.name + "********Destroy!");
    }
}


 

运行效果图:

          初始化的状态

由以上的打印可以看出,在初始对象以及脚本的调用上,Unity的实例始终是按照树形结构从最底层开始加载调用,然后逐层向上!

终止状态:



奇妙的事情发生啦!  哈~ 在对象销毁的时候,Unity是优先Destroy上层的对象,再操作它的子对象(从上于下的顺序)销毁!

 





最后我们关注下,一个对象关联多个脚本时的输出情况,这里也关注初始化和销毁两个行为!

 

每个对象的脚本绑定形式:


三个脚本的打印形式如:

    

// Use this for initialization
      voidStart()
    {
       print("----Start-" + this.transform.name + ",class:GroupData");
    }
 
    // Update is called once per frame
    void Update()
    {
 
    }
 
    void OnDestroy()
    {
       print("*******************"+ this.transform.name + "********Destroy!" + ",class:GroupData");
    }

我们先从当个脚本的执行情况看看:



我们再交换下三个脚本的顺序,看看打印的情况:

 

总结:

初始化:对于同一对象绑定多个脚本,初始化加载总会从目录的最底层开始,再逐级向上!

销毁:也许是因为同级目录,所以销毁的顺序按目录层,从上到下依次执行!

 

最后我们看看多层多脚本的执行情况:



  总结:

    对于对象视图,依然从最底开始,再到单一对象的脚本视图,又从底部开始!

  个人来说这里有点小意外这里!!哈哈~~

以下为销毁效果图:


销毁的顺序跟我们上面的实验结果没有多大的相差!

假如:我们把Group20和Group210的脚本都减少一个,只放置一个脚本,看看脚本的执行情况!


以下是销毁的效果图:

 

我们试着按代码的思路去写的话我猜有可能是这样子的:

 

1.查找对象的脚本绑定,记录最大的脚本绑定层数

2.查找对象的分布层数,建立树形层级

3.对于加载过程,从脚本层数开始的最底端开始遍历整个对象分布的树形层

4.对于销毁过程,则反过来由对象视图的树形层开始,依然销毁对象的脚本,并且优先销毁最底层的父节点,依次向上!

 

仅为记录工作中的一些疑问,有不对的地方,欢迎大家指正,交流!谢谢理解!

 

2013-07-18 17:39:20 wyz365889 阅读数 5005
  • Unity3D入门到精通-(4)Unity热更新

    本次系列课程的目标是让Unity3D初学者掌握C语言,Untiy调用lua脚本深入理解uLua框架实现原理,并根据项目的特点实现相应的热更新方案。 适合对象:Unity初学开发者,Unity中级开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    2207 人正在学习 去看看 张刚

Unity3d脚本之间信息通信


在项目Hierarchy里面新建两个Cube


一.第一种通过获得绑定的对象底下的脚本直接获得方法接口

两个脚本:

1.Cube.cs

using UnityEngine;

using System.Collections;


public class Cube : MonoBehaviour {

public GameObject go1;     //绑定Cube2对象,即把上面建的Cube2拖到这个变量里面

void Start () {

Cube2 cube2=(Cube2)go1.GetComponent("Cube2");     //获得Cube2对象底下的Cube2脚本

cube2.ShowMesg();     //调用方法

}

}

2.Cube2.cs

using UnityEngine;

using System.Collections;

public class Cube2 : MonoBehaviour {

public void ShowMesg()

{

     print("wyyyys");

}

}


二.第二种通过SendMessage

1.Cube.cs

using UnityEngine;

using System.Collections;


public class Cube : MonoBehaviour {

public GameObject go1;     

void Start () {

go1.SendMessage("ShowMesg","wyz");

}

}

2.Cube2.cs

using UnityEngine;

using System.Collections;


public class Cube2 : MonoBehaviour {


public void ShowMesg(string sss)

{

     print("wyzxxxx"+sss);

}

}

2016-12-19 21:10:01 Lvxuebin 阅读数 444
  • Unity3D入门到精通-(4)Unity热更新

    本次系列课程的目标是让Unity3D初学者掌握C语言,Untiy调用lua脚本深入理解uLua框架实现原理,并根据项目的特点实现相应的热更新方案。 适合对象:Unity初学开发者,Unity中级开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    2207 人正在学习 去看看 张刚

Unity脚本概述

与其他常用的平台有所不同,Unity中的脚本程序如果要起作用,主要途径为将脚本附加到特定的游戏对象上。这样脚本中不同的方法在特定的情况下会被调用,实现特定的功能。
在Unity脚本中,各事件函数的功能和大体的执行顺序如下:
1、Awake

   Awake用于脚本唤醒。此方法为系统执行的第一个方法,用于脚本
   的初始化,在脚本的生命周期中只执行一次。

2、Start

   Start方法在Awake之后执行,在脚本的生命周期中只执行一次。
   由于Awake和Start函数的特性与c#中的构造函数类似(一般情况
   下,在脚本的生命周期中只执行一次),所以在Unity中也常用来
   初始化类的成员变量。
   这个方法在游戏场景加载时被调用,在该方法内可以写一些游戏场
   景初始化之类的代码。

3、FixedUpdate

   FixedUpdate用于固定频率更新。这个方法会在固定的物理时间
   步调调用一次。这里也是基本物理行为代码执行的地方。
   通常情况下下,FixedUpdate()比Update()更频繁地调用。
   当帧率较低时,在某一帧的时间间隔内比Update可能会被调用多
   次;而当帧率很高时,在某一帧的时间间隔内FixedUpdate可能
   根本不会调用。
   还有一点,在Unity中,若设置Time Scale值为0,可以实现动
   力学特性的暂停,即所有的FixedUpdate中的代码都不会执行。

4、Update

    Update用于正常更新,即用于帧更新后同步场景状态。此方法每
    帧都会由系统自动调用一次。大部分的游戏代码在这里执行,除
    了物理部分的代码。
    在使用Update()时,对于一些变量,如速度、移动距离等通常需
    要乘以Time.deltaTime来抵消帧率带来的影响,使物体状态的
    改变看起来比较均匀正常。而在FixedUpdate中,由于其更新频
    率固定,所以不需要采用Time.deltaTime来修正状态改变频
    率。 

5、LateUpdate

    LateUpdate用于延迟更新,此方法在Update()之后执行,每
    一帧调用一次。

6、OnGUI

    OnGUI用来绘制用户交互界面,每一帧会调用多次。其中,与布
    局(Layout)和重汇(Repaint)相关的事件会被优先处理,然
    后是键盘事件和鼠标事件。

7、OnDestroy

    OnDestroy在当前脚本被销毁时调用。若在脚本中动态分配了内
    存,可以再OnDestroy()中进行释放。    

    同时,开发人员在有需要的情况下,还可以重写一些处理特定事
    件的回调方法,这类方法一般以On前缀开头,如
    OnCollisionEnter方法(此方法在系统检测到碰撞开始时回
    调)等。

Unity官方提供的事件顺序图:

这里写图片描述

   1、继承自MonoBehaviour类
         Unity中所有挂载到游戏对象上的脚本中的类必须继承
         MonoBehaviour类(直接的或者间接地),
         MonoBehaviour定义了各种回调方法,如Start、
         Update等。
   2、类名字必须匹配文件名
        C#的类名需要手动编写,而且类名必须和文件名相同,否则当脚本挂载到游戏对象时,在控制台会报错。
   3、使用Awake或Start方法初始化
        用于初始化脚本的代码必须置于Awake或Start方法中。两
        者不同之处在于Awake在加载场景时运行;Start方法是在
        第一次调用Update或FixedUpdate方法之前被调用;
        Awake运行在所有Start方法之前。
   4、Unity脚本中的协同程序有不同的语法规则
        (1)协程的返回值必须是Enumerator。
        (2)协程的参数不能加关键字ref或out。
        (3)在C#脚本中,必须通过StartCoroutine来启动协
        程。
        (4)yield语句要用yield return 来代替。
        (5)在函数Update和FixedUpdate中,不能使用yield
        语句,但可以启动协程。
    5、只有满足特定情况变量才能显示在属性查看器中
         只有序列化的成员才能显示在属性查看器中,如果属性想
         在属性查看器中显示,其必须是public类型的。
    6、尽量避免使用构造函数
         不要在构造函数中初始化任何变量,要用Awake或Start
         方法来实现。即便是在编辑模式,Unity会自动调用构造
         函数。
    7、调试
         Unity中C#代码的调试与传统的C#调试有所不同。Unity
         自带了完善的调试功能,在Unity中的控制台
         (Console)中包含了当前的全部错误,双击这个错误,
         可以自动跳转到默认的脚本编辑器中,然后光标会在错误
         所对应的行首跳动。

Unity中的坐标系

   一般情况下,在Unity中,x轴为红色的轴表示左右,y轴为绿色的
   轴表示上下,z轴为蓝色的轴表示前后。  
2016-11-23 20:11:13 wzjssssssssss 阅读数 419
  • Unity3D入门到精通-(4)Unity热更新

    本次系列课程的目标是让Unity3D初学者掌握C语言,Untiy调用lua脚本深入理解uLua框架实现原理,并根据项目的特点实现相应的热更新方案。 适合对象:Unity初学开发者,Unity中级开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    2207 人正在学习 去看看 张刚
using UnityEngine;
using System.Collections;

public class reflect : MonoBehaviour {

    // 引入一个游戏场景中的对象(包括抽象对象,如Transform.,最后要在图形界面拖入对象)
    public GameObject muban;
    // Use this for initialization
    // 初始化调用
    void Start () {
        Debug.Log(muban.name);
    }

    //float ver = Input.GetAxis("Vertical");
    //transform.position += transform.forward * ver * 300;


    // Update is called once per frame
    // Vector3 三维向量类
    // 固定每一帧都会调用一次.
    void Update () {

        if (Input.GetKey(KeyCode.A)) // Input为一个类,GetKey() 为一个方法,如果用户输出为A ,则执行下列语句。
            transform.position += new Vector3(-1, 0, 0) * Time.deltaTime;  //Time.deltaTime:  假如FPS为60,Time.deltaTime = 1/60;
         // 与学过的东西好像不太一样,对象累加,x+(-1)*Time.deltaTime, y,z不变. 
    }



    // 当进入触发器的范围时触发调用此函数 与之还有 OnTriggerExit,OnTriggerStay 顾名思义  
    void OnTriggerEnter(Collider other)  // other: 触发器所挂载的对象。
    {
        Debug.Log(other.name);
        transform.position = new Vector3(0, 4, 0);
    }
}

触发器和碰撞机:

同属于Collider, 当不勾中 Is Trigger 时为碰撞机, 当触碰到碰撞机时会触发: OnCollisionEnter(Collision other)。
都属于区域触发,不同点就是一个不能穿过会发生碰撞 ,一个能够穿过。

关于 Rigidbody 的 velocity : 意为 速度, 属于Vector3类, Vector3 为一个空间坐标向量类。

Vector3 v3 = new Vector3(1,0,0); 实例化 一个空间向量,它可以进行四则运算。
如: Rigidbody.velocity +=v3; 表示在x轴上的值加上1. v3 * 15 则 为(15,0,0);
它只是表示了一个速度向量,但是实际速度应该为 velocity.magnitude吧? , 15*15+15*15的平方?
在Unity3D 中,距离单位都用米来表示, 这里用秒来表示 那么速度就为 21米/秒?

速度向量和距离向量,正负都表示世界方向, 速度向量中的值代表速度,距离向量中的值代表速度?

如 transform.position += new Vector(1,0,0); 即代表 将游戏对象当前x上的位置加上一个单位;

using UnityEngine;
using System.Collections;

public class ballScript : MonoBehaviour {

    Rigidbody rb;
    // Use this for initialization
    void Start () {
        // 一开始给ball某个方向上的速度
        rb = GetComponent<Rigidbody>();
        rb.velocity = new Vector3(0, 1, -1) * 15 ;
    }

    // Update is called once per frame
    void Update () {
        Vector3 v = rb.velocity;
        if (v.z == 0)
            v.z = 1;
        rb.velocity = v;
    }
    void OnTriggerEnter(Collider other) {
        Vector3 v = rb.velocity;
        if (other.name == "player") {
            if(v.z <= 0) {
                rb.velocity = new Vector3(0, 1, -1) * 15;
                Debug.Log(rb.velocity.x);
                Debug.Log(rb.velocity.y);
                Debug.Log(rb.velocity.z);
                Debug.Log(rb.velocity.magnitude);
            }
            else
            {
                rb.velocity = new Vector3(0, 1, 1) * 15;
            }

        }
    }

    void OnCollisionEnter(Collision other) {
        if (other.collider.tag == "Finish") {
            Destroy(other.gameObject);
        }
    }
}

第一天的学习心得:
一个游戏对象拥有许多的组件,我将其理解为一个特性, 比如新创建一个cube对象,开发者为其初始化了几个特性分别是:Mesh Filter(网格过滤器:即改变形状,正方形,圆形等,在引擎中形状都用网格表示),Collider (这个东西叫做碰撞机,如果没有它,则这个物体不能触碰到任何物体,那么它就可以引申出很多的属性,比如材质:木板?弹床?冰块等,材质又可以引申出许多属性 比如:摩擦力?弹性?) 与现实世界不同的就是碰撞机的大小可以改变,大于或者小于物体本身。,Mesh Renderer(网格渲染器:具体属性还不是很清楚待查看)。
以上为初始化属性。
当我们运行一个物体时,会发现它不会因为重力而往下坠落。 这是因为它没有这个属性。就像一个人它本身是有重力的,因为它有质量。但是开发者并没有为其初始化该特性(组件),这能够让我们够好得去开发。
为其添加一个刚体(Rigidbody: 它有 mass(质量),drag(我猜应该是物体的拉力)等)再运行这个物体就会掉落。我们想要发生碰撞的话就需要碰撞的两个物体都要 Collider 而且 一个物体要有刚体这个特性。

一个物体的具体行为则需要在脚本中实现然后将脚本拖给这个物体。 有趣的事情发生了, 当我们在脚本中编写一条属性时(public Rigidbody rb;),在Unity3D的图形界面的inspector中会出现这个属性,然后我们可以将场景中所有?相应类型的对象拖入到属性中,然后在脚本中就可以使用它了。

using UnityEngine;
using System.Collections;

public class player : MonoBehaviour {
    // -11.27
    // 
    // Use this for initialization
    // 砖块预设体
    public GameObject bricks;
    void Start () {
        // 循环创建brick
        //Instantiate(bricks, new Vector3(-0.5f, 0, 0),Quaternion.identity);
        float width = 1;
        float widthSpace = 0.5f;
        for (int i = 0; i < 13; i++) {
            for(int j = 0;j<4;j++)
                Instantiate(bricks, new Vector3(-0.5f, 6-j*2, 11.27f - i*2  ),Quaternion.identity);
        }
    }

    // Update is called once per frame
    void Update () {



                // 获取水平轴上的值 [-1,1]
                float hor = Input.GetAxis("Horizontal");
                // 移动player
                transform.position += new Vector3(0, 0, -1) * hor * 20 * Time.deltaTime;

        if (transform.position.z >= 11.27)
            transform.position = new Vector3(transform.position.x, transform.position.y, 11.27F);
        else if (transform.position.z <= -11.27)
            transform.position = new Vector3(transform.position.x, transform.position.y, -11.27F);

    }
}

打砖块脚本………………………

2014-05-13 10:12:45 lmzqm 阅读数 983
  • Unity3D入门到精通-(4)Unity热更新

    本次系列课程的目标是让Unity3D初学者掌握C语言,Untiy调用lua脚本深入理解uLua框架实现原理,并根据项目的特点实现相应的热更新方案。 适合对象:Unity初学开发者,Unity中级开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    2207 人正在学习 去看看 张刚

在本章中我们将学习的是Unity3D的脚本编程,Unity3d目前支持javascript,c#,Boo这三种脚本的开发!由于本人开发过C++所以就直接用C#来进行unity3d的脚本开发!在脚本开发的过程中我们很有必要来了解一下Unity对象的生命周期!

所谓的生命周期也就是说这个对象的执行顺序!只有对这个顺序能够很好的理解,才能更加便于我们的开发!因此花点时间了解下还是很有必要的哈!

 using UnityEngine;
 using System.Collections;
 public class FirstScript : MonoBehaviour{
    void Awake()
    {
       //这是进入后的第一个执行函数,只执行一次
    }
    void Start()
    {
       //这是第二个执行的函数,也只执行一次,一般用于初始化的操作
    }
 
    void Update()
    {
        //这是更新操作,一帧一帧的执行
    }
 
    void LateUpdate()
    {
         //这个函数在Update后执行
    }
 
    void FixedUpdate()
    {
         //这个函数在固定时间后执行默认为0.02
    }
 
    void OnGUI()
    { 
         //这是绘制函数,可以再场景中绘制一些控件什么的
    }
 
    void OnDestory()
    {
         //这是销毁函数
    }
}
首先一进入的时候是调用 void Awake()这个函数,这函数值执行一次,然后紧接着进入void Start();这函数也只执行一次,接着就进入Void Update();这个函数时一帧一桢的执行的,当Update()执行完后会马上执行voidLateUpdate();这个函数!

当然我们还有一些函数例如voidFixedUpdate();这是在固定的时间会执行一遍,还有就是OnGUI();这个函数会一直执行着,当然当我们销毁的时候会执行OnDestory()这个函数;

Ok,接着就让我们进入Unity3D脚本开发的世界吧!

1首先是创建对象

对于创建对象有两种方法可以使用,一种是通过用户的赋值来进行的,一种是直接通过代码来进行对象的创建。

这个我们在C#的文件中定义一下就可以啦!

例如:

         Public GameObject obj4;

         Public Texture texture;

这样在绑定这个脚本的文件的属性视图中将会出现

        

接下来我们要做的就是将我们需要的GameObject和对应的Texture拖入就可以使用啦!是不是想当的方便呢?呵呵。。。你也可以试试哈!

接下来我将通过代码来进行讲解!

首先和大家说下我们的目的是什么,我们通过一个按钮来创建一个cube,然后通过一个按钮来实现这个cube的旋转。Ok,直接上代码啦!

using UnityEngine;
using System.Collections;
 
public class cube : MonoBehaviour {
    private GameObject obj;
    void Awake()
    {
    }
 
    void Start(){};
 
    void OnGUI()
    {
         if(GuiLayout.Button(“creatobj”,GuiLayout.height(50),GuiLayout.width(100)))
        {
            obj =GameObject.CreatPrimitive(PrimitiveType.Cube);
        }
         if(GulLayout.Repeat (“Rotate”,GuiLayout.Height(50),GuiLayout.width(100)))
        {
            obj.tranfrom.Rotate(Vector3.up*Time.dalteTime*30);
        }
    }
 
    void OnDestory()
   {
 
   }

OK,这样的操作我们就通过代码来创建了对象啦!创建了对象我们就可以做我们自己想做的事情啦!

2 获得对象

         在我们的游戏开发的过程中获得当前的游戏对象是很重要的一个操作,例如当我们的主角运动的时候后面跟真的也要一起运动,这时候我们就需要获得其他的对象,然后让其跟着我们的主角一起运动,当然还有很多运用哈!这里只是简单的几个例子哈!

         首先我们在游戏对象视图中创建一个cube对象名字为cube2(保证这是一个独一无二的名字哈!)

         然后我们在工程视图中创建一个C#文件,并改名字为Main(在win下的快捷键是按F2就可以啦!),然后将该脚本绑定给摄像机。接下来我们双击Main文件,进行编辑脚本文件!

         在这个脚本中我们主要的操作是,我们有三个按钮,第一个按钮用于获取对象,第二个按钮用于旋转对象,第三个按钮用于销毁对象!

using UnityEngine;
using System.Collections;
public GetObj : Monobehaviour{
  Private GameObject obj;
  void Start()
 {
                           
 }
 
 void OnGUI()
 {
     if(GuiLayout.Button(“GetObject”,GuiLayout.Height(40),GuiLayout.Width(100)))
     {
       obj= GameObject.Find(“cube2”);
     }
 
     if(GuiLayout.RepeatButton(“Rotate”),GuiLayout.height(40),GuiLayout.width(100))
     {  
         obj.tranfrom.Rotate(Vector3.up*Time.deltaTime*30);
     }
 
     if(GuiLayout.Button(“Destory”),GuiLayout.height(40),GuiLayout.width(100))
     {
         Destory(obj);
      }
 }
 
 void OnDestory()
 {
 
 }
        
}

Obj = GameObject.Find();这样我们就可以获得对象啦!

谢谢大家对我博客支持,你们的支持是我的动力!希望大家一起奋斗哈!


Unity 游戏脚本

阅读数 659

没有更多推荐了,返回首页