日志分类:游戏开发

[Unity3D]脚本中Start()和Awake()的区别

时间:2014年03月04日作者:小侃评论次数:0

Unity3D初学者经常把Awake和Start混淆。

简单说明一下,Awake在MonoBehavior创建后就立刻调用,Start将在MonoBehavior创建后在该帧Update之前,在该Monobehavior.enabled == true的情况下执行。

[javascript] 

  1. void Awake (){
  2. }
  3. //初始化函数,在游戏开始时系统自动调用。一般用来创建变量之类的东西。
  4. void Start(){
  5. }
  6. //初始化函数,在所有Awake函数运行完之后(一般是这样,但不一定),在所有Update函数前系统自动条用。一般用来给变量赋值。

我们通常书写的脚本,并不会定义[ExecuteInEditMode]这个Attribute,所以Awake和Start都只有在Runtime中才会执行。

 

例1:

 

[javascript]

  1. public class Test : MonoBehaviour {
  2.     void Awake () {
  3.         Debug.Log(“Awake”);
  4.         enabled = false;
  5.     }
  6.     void Start () {
  7.         Debug.Log(“Start”);
  8.     }
  9. }

 

以上代码,在Awake中我们调用了enabled = false; 禁止了这个MonoBehavior的update。由于Start, Update, PostUpdate等属于runtime行为的一部分,这段代码将使Start不会被调用到。

在游戏过程中,若有另外一组代码有如下调用:

[javascript]

  1. Test test = go.GetComponent<Test>();
  2. test.enabled = true;

这个时候,若该MonoBehavior之前并没有触发过Start函数,将会在这段代码执行后触发。

例2:

player.cs

[javascript] 

  1. private Transform handAnchor = null;
  2. void Awake () { handAnchor = transform.Find(“hand_anchor”); }
  3. // void Start () { handAnchor = transform.Find(“hand_anchor”); }
  4. void GetWeapon ( GameObject go ) {
  5.     if ( handAnchor == null ) {
  6.         Debug.LogError(“handAnchor is null”);
  7.         return;
  8.     }
  9.     go.transform.parent = handAnchor;
  10. }

other.cs

 

[javascript] 

  1. GameObject go = new GameObject(“player”);
  2. player pl = go.AddComponent<player>(); // Awake invoke right after this!
  3. pl.GetWeapon(weaponGO);

 

以上代码中,我们在player Awake的时候去为handAnchor赋值。如果我们将这步操作放在Start里,那么在other.cs中,当执行GetWeapon的时候就会出现handAnchor是null reference.

总结:我们尽量将其他Object的reference设置等事情放在Awake处理。然后将这些reference的Object的赋值设置放在Start()中来完成。
当MonoBehavior有定义[ExecuteInEditMode]时

当我们为MonoBehavior定义了[ExecuteInEditMode]后,我们还需要关心Awake和Start在编辑器中的执行状况。

当该MonoBehavior在编辑器中被赋于给GameObject的时候,Awake, Start 将被执行。
当Play按钮被按下游戏开始以后,Awake, Start 将被执行。
当Play按钮停止后,Awake, Start将再次被执行。
当在编辑器中打开包含有该MonoBehavior的场景的时候,Awake, Start将被执行。

值得注意的是,不要用这种方式来设定一些临时变量的存储(private, protected)。因为一旦我们触发Unity3D的代码编译,这些变量所存储的内容将被清为默认值。

 

下面再来看看Unity圣典中的解释。

Awake()

当一个脚本实例被载入时Awake被调用。

Awake用于在游戏开始之前初始化变量或游戏状态。在脚本整个生命周期内它仅被调用一次.Awake在所有对象被初始化之后调用,所以你可以安全的与其他对象对话或用诸如 GameObject.FindWithTag 这样的函数搜索它们。每个游戏物体上的Awke以随机的顺序被调用。因此,你应该用Awake来设置脚本间的引用,并用Start来传递信息。Awake总是在Start之前被调用。它不能用来执行协同程序。
Start()

Start仅在Update函数第一次被调用前调用。Start在behaviour的生命周期中只被调用一次。它和Awake的不同是Start只在脚本实例被启用时调用。
你可以按需调整延迟初始化代码。Awake总是在Start之前执行。这允许你协调初始化顺序。

MonoBehaviour类Invoke, Coroutine

时间:2014年02月18日作者:小侃评论次数:0

MonoBehaviour概述

MonoBehaviour 表示一个单一的行为。Unity中用户对游戏对象的操作被分割成若干个单一行为。每个单一行为都作为一个MonoBehaviour类来封装。再生成每个MonoBehaviour类的实例,并作为组件嵌入游戏对象。然后按照一定的顺序(从下到上)调用每个对象的重载方法来实现游戏对象的全部行为。

 

创建

在菜单Assets->create中选择javascript活C# script创建一个脚本类。Unity规定:这些类都必须继承自MonoBehaviour。javascript 的脚本类自动继承MonoBehaviour,c#脚本类必须显式继承这个类。

 

特别之处

继承自MonoBehaviour的类,不需要自己创建它的实例,也不能自己创建(如 new 类名)。因为所有从MonoBehaviour继承过来的类,unity都会自动创建实例,并且调用被重载的方法,如我们经常用到的Awake,Start, Update等。而普通类,就可以用new来创建实例了。

 

异步函数

在一个方法执行时调用另一个方法。而被调用的方法或者其中的某些语句不是立刻执行,而是过一段时间后才执行。

MonoBehaviour提供了两种异步方法

调用(Invoke)

协程(Coroutine)

 

 

调用(Invoke)

function Invoke (methodName: string, time : float) : void

functionInvokeRepeating (methodName : String,time : float, repeatRate : float) : void

function CancelInvoke () : void

function IsInvoking (methodName: string) : bool

 

协程(Coroutine)

function StartCoroutine (routine: IEnumerator) : Coroutine

function StartCoroutine (methodName: string, value : object = null) :

function StopCoroutine (methodName: string) : void

function StopAllCoroutines () : void

 

协程介绍

协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈,局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。线程与协同程序的主要区别在于,一个具有多线程的程序可以同时运行几个线程,而协同程序却需要彼此协作地运行。就是说,一个具有多个协同程序的程序在任何时刻只能运行一 个协同程序,并且正在运行的协同程序只会在其显示地挂起时,它的执行才会暂停。

 

Unity中协程

一个协同程序在执行过程中,可以在任意位置使用yield语句。yield的返回值控制何时恢复协同程序向下执行。协同程序在对象自有帧执行过程中堪称优秀。协同程序在性能上没有更多的开销。StartCoroutine函数是立刻返回的,但是yield可以延迟结果。直到协同程序执行完毕。

 

function StartCoroutine (routine: IEnumerator) : Coroutine

参数表:IEnumerator

IEnumerator是枚举数接口。函数需要一个实现了这个接口的YieldInstruction对象。可以创建一个WaitForSeconds对象,在它的构造函数中传入挂起时间。

返回值:Coroutine

只用来表示一个协同程序实例的引用。没有任何暴露的变量和函数。一个coroutine是一个函数,它能在中断完成前挂起执行。

 

function StartCoroutine (methodName: string, value : object = null) : Coroutine

直接传入一函数名,开销大些。

 

比较

Invoke方法:执行没有被挂起,相当于设置完被调用函数的执行时间后即时向下执行。应用到没隔一段时间执行某个函数很方便。

Coroutine方法:新开一条执行序列(跟新建线程差不多)并挂起,等待中断指令结束。开销不大。当需要挂起当前执行时使用。比如Player死了一条命后消失,再过1.5秒后重新出现,就可以用将协同程序挂起。

gameObject.renderer.enabled= false;

yieldWaitForSeconds(1.5f);

gameObject.renderer.enabled= true;

Unity引擎中的HotKeys

时间:2014年02月18日作者:小侃评论次数:0

好久都没有更新博客了,最近在忙于整理一些东西,所以就疏远了更新的进度了。下面弄了2张截图,是有关Unity3d的hotkeys组合。

第一幅截图是window下的unity3d中引擎的快捷操作键。

第二幅截图是Mac下unity3d引擎中的操作快捷键。

至于,我们在玩游戏时的操作快捷方式,是可以再游戏开发中进行设置的。这个就不细说了,大家也都清楚的!有机会,会在以后的博客中进行详述的。

标签:,,分类:游戏开发

Unity3D Student 教程观看笔记整理

时间:2014年02月18日作者:小侃评论次数:0

一.Unity3D Student教程基础 1.工程 Unity的工程文件实际上是有一个文件夹下的所有文件组成的.在Unity下你必须在一整个文件夹下进行工作.这个文件夹,一个是assets,一个Library.在运行的时候会有一个临时文件夹[temporary]的文件夹.

2.场景 你可以放你所看到的一切.每个场景新建的话都会有一个住摄像机.场景视图中你可以通过手型工具进行导航监视.手型可以让你进行拖拽平移视图.按下alt来旋转视图.按下ctrl来缩放视图(mac是command键). 注意:如果你奥查找的物件没有在视图中,你可以在层次面板中选中这个物件,把鼠标放到场景视图中,按F键.在场景视图中会让选中的物件居中.搜索物件.

3.层次面板 层次面板中列举了游戏场景中所有的物件,而且还负责着组织物件之间的”父子关系”!你可以通过层次面板搜索到场景视图中看到的物件.

4.游戏视图 Unity一个很不错的特性就是让你很直观的编译和测试游戏. 如果想要摄像机从某个角度进行拍摄,并让游戏视图和场景视图看上去一样,首先我们选择”主摄像机”,在选择游戏物件菜单中的对齐到视图(Align with View). 注意:在测试状态中你可以对游戏场景的各个熟悉进行修改.他只会在这种状态下体现出修改后的效果,但是任何做出的编辑和改变,都不会被保存.在||中你额可以在暂停状态检查游戏的性能数据等.Gizmos是一般来说是一些较小的2D的信息展示用的标志(如光源图标).我们也可以通过自定义脚本来控制Gizmo的展示形式.

5.工程面板 我们编译的资源都在这里了.

6.游戏物件 目前我们知道的即时物件存在与当前场景中的一些东西.存放在层次面板中.

7.组件 你可以通过组件菜单来为不同的物体添加各种各样的组件.

8.资源导入 a.直接双击导入. b.通过资源菜单导入 为不同的平台制作不同的贴图. 导入和导出资源. 在里面可以选择自己想要导入的资源!

9.光源 有三种光源. 直射光,点光源,聚光灯

10.摄像机 当你通过场景视图看到的场景并不一定和游戏视图中的一样.一般来说游戏视图展示的才是摄像机的视野.一般游戏中,摄像机都会绑定在某个物件上.通过控制物件的移动来控制摄像机的移动.我们可以让摄像机成为某个物件的子物件.也可以创建一个脚本来控制摄像机和某个物件之间的关系.摄像机往往也是玩家在游戏场景中听到声音的位置.所以,我们要记住摄像机所在的位置.会影响到场景中不同音频源的声音大小.这取决于听者和声源之间的距离. 在主摄像机旁边的声音将会听上去小声一些.在游戏过程中,我们可以通过脚本控制哪个摄像机需要被激活.

二.Unity3D Student 教程 初学者 1.如何使用重力? 给组件添加一个刚体组件.我们可以给碰撞器添加不用的物理材质,让他具有不同的物理效果.

2.碰撞检测基础知识 我们建一个脚本,来编写我们的逻辑.在OnCollistionEnter函数中,添加逻辑代码. 在这个函数中我们可以传递参数进行碰撞物体的检测. 检测用户输入的代码应该放入到Update函数中,因为用户随时可能发生,你应该在游戏每帧执行时检测他.

3.预制件 预制件就是一个被存为模版的物件.你可以通过这个预制件克隆出来很多相同属性设置的物件实体.

4.销毁指令 如果想从场景中移出任何物件(即销毁对象),应该在脚本中使用Destroy方法!方法中传的是我们要销毁的对象.这个脚本执行过程就会在层次面板的内容中找到这个名字的物件然后销毁他.

5.实例化 如果你想在场景中动态的创建物件,这时就需要使用脚本命令Instantiate来动态实例化物件.

6.做一个简单的计时器

7.移动基础 transfrom-空间信息组件 包含”位置”,”旋转”,”缩放”. 这里需要记住在监视面板上调整变量的值不会改变脚本中的值.

8.施加力 一个有刚体的物件,需要通过施加力使其运动.因为物件在游戏过程中一直受到物理引擎的影响,使用普通的平移会和物理引擎的控制产生冲突. 我们可以对其施加一个力或者Constant Force 恒定力,使其运动.可以对物件使用多次的力.

9.材质 如果你想修改物件的外观时,便需要掌握材质.

10.声音 播放声音需要注意两点:监听器和音源组件.一般而言监视器会是摄像机的一个组件.

11.关节 固定关节,枢纽关节.在这个链接的过程中,如果没有给物体添加刚体,就不能进行关节的相关操作.

12.输入 unity中的输入有另外一种类型Axis-轴.鼠标是左键0,右键1,键盘是其他,在-1和1之间进行变换.

13.触发器 如果不想让碰撞检测影响物件移动,但是有想检测到碰撞.那么你应该使用Trigger-触发器.触发器经常被用来检测一个物件是否可经过空间中的某个区域.Is Trgger用处是可以用这中方式碰撞不被玩家”看见”,用来检测某个物件是否在某个特定的区域.

14.GUI Text图形界面文本 GUI是一种用于展示游戏状态的常用方式.加空字符进行类型数值类型的转换.

Unity3d之MonoBehaviour的可重写函数整理

时间:2014年02月18日作者:小侃评论次数:0

Update

当MonoBehaviour启用时,其Update在每一帧被调用。

LateUpdate

当Behaviour启用时,其LateUpdate在每一帧被调用。

FixedUpdate

当MonoBehaviour启用时,其 FixedUpdate 在每一帧被调用。

Awake

当一个脚本实例被载入时Awake被调用。

Start

Start仅在Update函数第一次被调用前调用。

Reset

重置为默认值。

OnMouseEnter

当鼠标进入到GUIElement(GUI元素)或Collider(碰撞体)中时调用OnMouseEnter。

OnMouseOver

当鼠标悬浮在GUIElement(GUI元素)或Collider(碰撞体)上时调用 OnMouseOver .

OnMouseExit

当鼠标移出GUIElement(GUI元素)或Collider(碰撞体)上时调用OnMouseExit。

OnMouseDown

当鼠标在GUIElement(GUI元素)或Collider(碰撞体)上点击时调用OnMouseDown。

OnMouseUp

当用户释放鼠标按钮时调用OnMouseUp。

OnMouseUpAsButton

OnMouseUpAsButton只有当鼠标在同一个GUIElement或Collider按下,在释放时调用。

OnMouseDrag

当用户鼠标拖拽GUIElement(GUI元素)或Collider(碰撞体)时调用 OnMouseDrag 。

OnTriggerEnter

当Collider(碰撞体)进入trigger(触发器)时调用OnTriggerEnter。

OnTriggerExit

当Collider(碰撞体)停止触发trigger(触发器)时调用OnTriggerExit。

OnTriggerStay

当碰撞体接触触发器时,OnTriggerStay将在每一帧被调用。

OnCollisionEnter

当此collider/rigidbody触发另一个rigidbody/collider时,OnCollisionEnter将被调用。

OnCollisionExit

当此collider/rigidbody停止触发另一个rigidbody/collider时,OnCollisionExit将被调用。

OnCollisionStay

当此collider/rigidbody触发另一个rigidbody/collider时,OnCollisionStay将会在每一帧被调用。

OnControllerColliderHit

在移动的时,当controller碰撞到collider时OnControllerColliderHit被调用。

OnJointBreak

当附在同一对象上的关节被断开时调用。

OnParticleCollision

当粒子碰到collider时被调用。

OnBecameVisible

当renderer(渲染器)在任何相机上可见时调用OnBecameVisible。

OnBecameInvisible

当renderer(渲染器)在任何相机上都不可见时调用OnBecameInvisible。

OnLevelWasLoaded

当一个新关卡被载入时此函数被调用。

OnEnable

当对象变为可用或激活状态时此函数被调用。

OnDisable

当对象变为不可用或非激活状态时此函数被调用。

OnDestroy

当MonoBehaviour将被销毁时,这个函数被调用。

OnPreCull

在相机消隐场景之前被调用。

OnPreRender

在相机渲染场景之前被调用。

OnPostRender

在相机完成场景渲染之后被调用。

OnRenderObject

在相机场景渲染完成后被调用。

OnWillRenderObject

如果对象可见每个相机都会调用它。

OnGUI

渲染和处理GUI事件时调用。

OnRenderImage

当完成所有渲染图片后被调用,用来渲染图片后期效果。

OnDrawGizmosSelected

如果你想在物体被选中时绘制gizmos,执行这个函数。

OnDrawGizmos

如果你想绘制可被点选的gizmos,执行这个函数。

OnApplicationPause

当玩家暂停时发送到所有的游戏物体。

OnApplicationFocus

当玩家获得或失去焦点时发送给所有游戏物体。

OnApplicationQuit

在应用退出之前发送给所有的游戏物体。

OnPlayerConnected

当一个新玩家成功连接时在服务器上被调用。

OnServerInitialized

当Network.InitializeServer被调用并完成时,在服务器上调用这个函数。

OnConnectedToServer

当你成功连接到服务器时,在客户端调用。

OnPlayerDisconnected

当一个玩家从服务器上断开时在服务器端调用。

OnDisconnectedFromServer

当失去连接或从服务器端断开时在客户端调用。

OnFailedToConnect

当一个连接因为某些原因失败时在客户端调用。

OnFailedToConnectToMasterServer

当报告事件来自主服务器时在客户端或服务器端调用。

OnMasterServerEvent

当报告事件来自主服务器时在客户端或服务器端调用。

OnNetworkInstantiate

当一个物体使用Network.Instantiate进行网络初始化时调用。

OnSerializeNetworkView

在一个网络视图脚本中,用于自定义变量同步。