Unity-脚本

来源:互联网 发布:淘宝信誉度 编辑:程序博客网 时间:2024/05/22 11:40

脚本(Script)

事件功能

Unity详细回调时间表

MonoBehavior的详细回调时间表

定期的更新活动

Update在渲染帧之前以及在计算动画之前被调用。

void Update() {

}

在每次物理更新之前调用一个名为FixedUpdate单独事件函数。按固定时间间隔调用。(注意FixedUpdate与Update一样是在主线程进行回调的,Unity 在内部使用了一个委托队列来实现固定时间调用FixedUpdate,Update与FixedUpdate之间的调用有Unity根据算法生成的先后顺序,所以在FixedUpdata中修改变量并不用加锁,如此可见,在Update中使用死循环FixedUpdate会卡住,同理,如果在FixedUpdate中使用死循环Update也会一样卡住

void FixedUpdate() {

}

有时也可以在对场景中的所有对象调用UpdateFixedUpdate函数之后以及在计算所有动画之后的某个时间点进行其他更改。该LateUpdate功能,可用于这类情况。(通常用于摄像机的跟随)

void LateUpdate() {

}

初始化事件

所有的Awake都将在第一个Start被调用之前完成。这意味着Start函数中的代码可以利用之前已经在Awake阶段执行的其他初始化,Awake将在脚本的构造函数调用后立即在主线程被调用。

GUI事件

Unity具有用于在场景中的主要操作上呈现GUI控件并响应这些控件的点击的系统。该代码的处理方式与正常的帧更新有所不同,因此它应该放在OnGUI函数中,这将被定期调用。(注意,这是旧版的UI系统,这很慢,会导致游戏帧数下降,建议使用新的UGUI或者第三方的NGUI)

void OnGUI() {

    GUI.Label(labelRect, "Game Over");

}

您还可以检测出现在GameObject中的鼠标事件。这可以用于定位武器或显示当前在鼠标指针下的角色的信息。一组OnMouseXXX事件函数(例如,OnMouseOverOnMouseDown)可用于允许脚本使用鼠标对用户操作做出反应。例如,如果在指针在特定对象上方按下鼠标按钮,则该对象脚本中的OnMouseDown函数将被调用(如果存在,而且需要碰撞器)。


物理事件

物理引擎将通过调用该对象脚本的事件函数来报告对象的冲突。该OnCollisionEnterOnCollisionStayOnCollisionExit如接触时函数被调用,召开和破碎。当对象的对撞机被配置为触发器(即,对象机,只是简单地检测到什么东西进入而不是身体反应)时,将调用相应的OnTriggerEnterOnTriggerStayOnTriggerExit函数。如果在物理更新期间检测到多个联系人,则可以连续调用这些功能,因此将参数传递给提供冲突细节的功能(进入对象的位置等)的功能。

privatevoidOnCollisionEnter2D(Collision2Dcollision)

{

 

}

其他回调我将会在我的[Unity Tips中慢慢更新]

注:在Vs中右键可选择实现Unity事件函数。

以下是Unity官方手册上的一些脚本例子:

创建和销毁GameObject

一些游戏在场景中保持不变的对象数量,但是在游戏过程中创建和删除角色,珍宝和其他对象非常常见。在Unity中,可以使用创建现有对象的新副本的Instantiate函数创建一个GameObject 

public GameObject enemy;

 

void Start() {

    for (int i = 0; i < 5; i++) {

        Instantiate(enemy);

    }

}

 

请注意,制作副本的对象不一定存在于场景中。在编辑器中使用从"项目"面板拖动到public变量的预设体更为常见。另外,实例化一个GameObject将会复制原始文件中的所有组件。

还有一个Destroy(),在帧更新完成后或在短时间延迟后可选择地破坏对象:

void OnCollisionEnter(Collision otherObj) {

    if (otherObj.gameObject.tag == "Missile") {

        Destroy(gameObject,0.5f);

    }

}

 

请注意,Destroy函数可以破坏各个组件而不影响GameObject本身。一个常见的错误是写下如下:

 Destroy(this);

这将实际上只是销毁调用它的脚本组件,而不是摧毁脚本所附加的GameObject

随机选择元素

随机选择项目或值在很多游戏中很重要。这部分展示了如何使用Unity的内置随机函数来实现一些常见的游戏机制。

从数组中随机选择项

随机抽取数组元素可以选择零和数组最大索引值之间的随机整数(等于数组的长度减去一个)。这可以使用内置的Random.Range函数轻松完成:

varelement = myArray[Random.Range(0, myArray.Length)];//范围随机数

注意:Random.Range返回的值在[0,myArray)之间,即包括第一个数但不包括最后一个数。

选择不同概率的项目

例如,NPC在遇到玩家时可能会以几种不同的方式作出反应:

  • 50%的几率友好问候
  • 25%的几率逃跑
  • 20%的几率立即攻击
  • 5%的几率提供钱作为礼物

    你可以把这些不同的结果想象成一个纸条,把纸条分成不同的部分,每个部分占据了整条带子的一定长度。被占用的部分等于所选结果的概率。做出这样的选择相当于随机选取一条狭长的地带投掷一个飞镖,然后观察它落在哪个部分。

    在脚本中,纸条实际上是一组浮点数,用来表示不同项目的概率。

    随机点是通过将Random.value(会返回0.0到1.0之间的随机数)乘以数组中所有浮点数的总和获得的,它们不需要加起来为1,因为计算的是单个浮点值相对于浮点值和的相对大小。要查找点在纸条上的哪个区域,依次比较随机点与数组的值,如果随机点小于数组中的值,表明标中这个元素,如果大于,把随机点减去数组上的这个值,继续查找,直到找到正确的元素。下面是代码:

    floatChoose(float[]probs)

    {

     

    floattotal = 0;

     

    foreach (floateleminprobs)

    {

    total +=elem;

    }

     

    floatrandomPoint =Random.value *total;

     

    for (inti = 0;i < probs.Length;i++)

    {

    if (randomPoint <probs[i])

    {

    returni;

    }

    else

    {

    randomPoint -=probs[i];

    }

    }

    returnprobs.Length - 1;

    }

    注意:最后的返回语句是必需的,因为Random.value可以返回1这个的结果。在这种情况下,搜索将不会在任何地方找到随机点,所以这时可以返回一个您设定的特殊值。

    if (randomPoint <probs[i])

    注意:如果使用<=而不是<,可以不用加额外的返回语句,但偶尔您可能会需要选择一个概率是0的项目(可以把0概率设为最后一个项目)。

    加权连续随机值

    如果说,你要随机金币宝箱中发现的数量,并且您希望可能会在1100之间的任何数字中得到最终结果,但是让数字尽可能较低。如果使用浮点方法来实现这一点,需要您设置一个100个浮点数(即纸带上的部分),这是难以处理的;如果您不限于整数,而是希望在范围内使用任何类型的数字,则不可能使用该方法。

    一个更好的连续结果的方法是使用AnimationCurve(动画曲线)将"原始"随机值转换为"加权"; 通过绘制不同的曲线形状,您可以产生不同的权重。代码也更简单:

    publicAnimationCurvecurve;

     

    floatCurveWeightedRandom(AnimationCurvecurve)

    {

    returncurve.Evaluate(Random.value);

    }

     

    通过从Random.value读取来选择0到1之间的随机值。然后将其传递给curve.Evaluate(),将其视为水平坐标,并返回该水平位置处的曲线的相应垂直坐标。曲线的较平缓部分具有更大的被选择的机会,而较陡峭的部分的拾取机会较低。

    线性曲线,y=x

    该曲线在开始时较平缓,然后在最后更陡峭,因此它具有较低的价值机会,降低了高值的几率。

    这个曲线在开始和结束都很浅,使得接近两端的值更常见,而在中间陡峭,这将使这些值变得罕见。还要注意,用这个曲线,高度值已经向上移动:曲线底部为1,曲线顶部为10,这意味着曲线产生的值将在1-10范围内,而不是像以前的曲线那样的0-1。

    通过在您的一个脚本上定义一个公共AnimationCurve(动画曲线)变量,您将可以通过视觉视图查看和编辑曲线,而不需要计算值。

    这种技术产生浮点数。如果要计算整数结果 - 例如,您需要82个金件,而不是82.1214个金件,您可以将计算的值传递给像Mathf.RoundToInt()这样的函数进行转换。

    洗牌

    voidShuffle(int[]deck)

    {

    for (inti = 0;i < deck.Length;i++)

    {

    inttemp =deck[i];

    intrandomIndex =Random.Range(0,deck.Length);

    deck[i] =deck[randomIndex];

    deck[randomIndex] =temp;//随机交换

    }

    }

     

    选择一组不重复的项目

    一个常见的任务是从一个集合中随机选择一些项目,而不是多次挑选相同的项目。例如,您可能希望在随机生成点生成一些NPC,但确保在每个点只生成一个NPC。这可以通过顺序迭代项目来完成,为每个项目随机决定是否将其添加到所选择的那组集合中。

    例如,假设十个产生点可用,但只能选择五个。选择第一个项目的概率为5/100.5。如果第一个项目被选择,那么第二个项目的概率将是4/90.44(即仍然需要四个项目,有九个可供选择)。但是如果没有选择第一个,那么第二个的概率将为5/90.56(即,仍然需要五个,剩下九个可供选择)。这一直持续到集合包含所需的五个项目。您可以通过以下代码完成此操作:

    Transform[]ChooseSet(Transform[]spawnPoints,intnumRequired)

    {

    Transform[]result =newTransform[numRequired];

     

    intnumToChoose =numRequired;

     

    for (intnumLeft =spawnPoints.Length;numLeft > 0; numLeft--)

    {

     

    floatprob = (float)numToChoose / (float)numLeft;

     

    if (Random.value <=prob)

    {

    numToChoose--;

    result[numToChoose] =spawnPoints[numLeft - 1];

     

    if (numToChoose == 0)

    {

    break;

    }

    }

    }

    returnresult;

    }

    请注意,虽然这样选择是随机的,但所选集中的项目将与原始数组中的顺序相同,因此可能需要在使用前洗牌。

    空间随机点

    可以通过将Vector3的每个值设置为Random.value返回的值来选择立方体积中的随机点:

    varrandVec =Vector3(Random.value,Random.value,Random.value);

    这就给出了一个立方体内一个单位长度为1单位的点。这个立方体可以简单地通过将向量的X、Y和Z分量相乘,得到所需的值。如果其中一个坐标轴被设为零,那么这个点总是在一个平面内。例如,在"地面"上随机选取一个点时,通常是随机设置X和Z分量,并将Y分量设置为零。

    当需要的是一个球体内的点(例如,当你想要一个从原点到给定半径内的任意点的时候),你可以随机使用。内单位球乘以所需半径:

    Vector3randWithinRadius =Random.insideUnitSphere *radius;//insideUnitSphere返回半径是1的球内的点

    注意:如果将结果向量(vector3)的一个值设置为零,并不能再一个圆内得到一个较好的随机点。尽管这一点确实是随机的,并且在正确的半径范围内,但它的概率是严重偏向于圆的边缘的。因此点将会非常不均匀地分布。您应该为此任务使用Random.insideUnitCircle:

    varrandWithinCircle =Random.insideUnitCircle *radius;


原创粉丝点击