如何使用脚本修改Unity中的粒子 VR开发资源

manew_JR 2017-07-13 11:40:15

原标题:如何使用脚本修改Unity中的粒子 VR开发资源

Unity 3D提供了一个巨大的API,它提供了操纵游戏中绝大多数对象的方法。然而,有些特性并不如您所希望的那样强大。举个例子,例如,部分系统类。比方说,你有一个粒子系统。您需要使用脚本修改粒子系统的形状半径。在快速浏览一下Unity  ParticleSystem的文档之后,您可以假设您可以使用分区ParticleSystem.shape.radius来改变粒子系统的半径。然而,当我们试图这样做的时候,问题就出现了。Unity给了我们一个错误,告诉我们这个部分。半径是只读的。这意味着它不能通过代码进行修改(至少在我看来是这样)。我们现在如何解决?这是我提出的解决方案。
 
 
如何使用脚本修改Unity中的粒子
以下是我为解决这个问题所采取的步骤。让我们开始使用序列化的对象。
 
使用序列化对象
老实说,我没有一个很好的方法来描述SerializedObject类。我能总结的最好方法是,它允许您访问通常无法访问或修改的组件模块。因此,我们可以使用这个类来访问我们的粒子系统的形状模块并对它做出改变。让我们来看看如何做到这一点。我假设你们已经建立了一个Unity项目包括一些你们想要操作的粒子系统。在我的例子中,我使用的是一个锥形的粒子系统。
 
1。选择您的ParticleSystem部分,并添加一个新的C#脚本,给它命名为ParticleScript.
2。将这些代码复制到您的脚本中(我已经尽可能多地注释了这段代码):
 
下面是代码:
 
 
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
using UnityEngine;
 
using System.Collections;
 
using UnityEditor; // Need this to access SerializedObject
 
public class ParticleScript : MonoBehaviour {
 
    SerializedObject thisParticle; // This will be our modifiable particle system
 
    bool isChanging; // Used as a flag for a coroutine
 
    //Set these values in the inspector. Will modify angle and radius of Particle System
 
    public float MAX_ANGLE, MIN_ANGLE, MAX_RADIUS, MIN_RADIUS, transitionSpeed;
 
    void Start ()
 
    {
 
        /* Initialize and Assign thisParticle as a SerializedObject that takes properties
 
         * from the ParticleSystem attached to this game object. */
 
        thisParticle = new SerializedObject (GetComponent<ParticleSystem>());
 
        thisParticle.FindProperty("ShapeModule.radius").floatValue = MAX_RADIUS;
 
        thisParticle.FindProperty("ShapeModule.angle").floatValue = MAX_ANGLE;
 
        thisParticle.ApplyModifiedProperties(); // This basically updates the particles with any changes that have been made
 
        isChanging = false;
 
    }
 
    void Update ()
 
    {
 
        if(Input.GetKeyDown(KeyCode.R) && !isChanging)
 
            StartCoroutine(ChangeRadius());
 
        else if(Input.GetKeyDown(KeyCode.A) && !isChanging)
 
            StartCoroutine(ChangeAngle());
 
    }
 
    IEnumerator ChangeRadius()
 
    {
 
        isChanging = true; // set true so user can't spam the coroutine
 
        //This code will make the radius smaller if the radius is at its maximum already
 
        if(thisParticle.FindProperty("ShapeModule.radius").floatValue >= MAX_RADIUS)
 
        {
 
            while(thisParticle.FindProperty("ShapeModule.radius").floatValue > MIN_RADIUS)
 
            {
 
                //grab the radius value and subtract it
 
                thisParticle.FindProperty("ShapeModule.radius").floatValue -= Time.deltaTime * transitionSpeed;
 
                thisParticle.ApplyModifiedProperties(); // This is used to apply the new radius value
 
                yield return null;
 
            }
 
        }
 
        //This code will make radius larger if radius is already at its minimum
 
        else if(thisParticle.FindProperty("ShapeModule.radius").floatValue <= MIN_RADIUS)
 
        {
 
            while(thisParticle.FindProperty("ShapeModule.radius").floatValue < MAX_RADIUS)
 
            {
 
                //grab the radius variable and increase it
 
                thisParticle.FindProperty("ShapeModule.radius").floatValue += Time.deltaTime * transitionSpeed;
 
                thisParticle.ApplyModifiedProperties(); // Apply new radius value
 
                yield return null;
 
            }
 
        }
 
        isChanging = false; // set to false so user can input again.
 
        yield return null;
 
    }
 
    IEnumerator ChangeAngle()
 
    {
 
        isChanging = true;
 
        //This code will make the angle smaller if the angle is at its maximum already
 
        if(thisParticle.FindProperty("ShapeModule.angle").floatValue >= MAX_ANGLE)
 
        {
 
            while(thisParticle.FindProperty("ShapeModule.angle").floatValue > MIN_ANGLE)
 
            {
 
                //grab angle value and subtract it
 
                thisParticle.FindProperty("ShapeModule.angle").floatValue -= Time.deltaTime * (transitionSpeed * 2);
 
                thisParticle.ApplyModifiedProperties(); // apply new value to angle
 
                yield return null;
 
            }
 
        }
 
        //This code will make angle larger if angle is already at its minimum
 
        else if(thisParticle.FindProperty("ShapeModule.angle").floatValue <= MIN_ANGLE)
 
        {
 
            while(thisParticle.FindProperty("ShapeModule.angle").floatValue < MAX_ANGLE)
 
            {
 
                // grab angle value and increase it
 
                thisParticle.FindProperty("ShapeModule.angle").floatValue += Time.deltaTime * (transitionSpeed * 2);
 
                thisParticle.ApplyModifiedProperties(); // apply new value to angle
 
                yield return null;
 
            }
 
        }
 
        isChanging = false;
 
        yield return null;
 
    }
 
}
 
使用序列化对象的下一步步骤:
现在您已经有了代码,接下来要做的是:
 
1。单击层次结构中的粒子系统,并在检查器中找到该分区的对象。您将注意到几个公共变量。为了快速测试,将您的变量设置为和我一样的:
 
 
 
2。现在,如果你运行你的游戏,按R或A,你应该看到半径或角度的变化,这取决于你按哪个键。请注意,由于我编写代码的方式,您只能一次更改一个变量。你可以很容易地修改它,这样你就可以同时运行两个coroutines。
 
我如何知道要修改的模块的名称?
当我第一次把序列化的对象弄乱时,我很难理解“ShapeModule.radius”从哪里来。文档包含这个字符串在SerializedObject.FindProperty()函数内部,但它没有解释从哪里得到该字符串。我发现,如果您在Unity中切换到Debug视图,您将能够看到与组件相关联的属性列表。要打开Debug视图,请单击检查器右上角的第三行图标,并选择“Debug”:
 
 
 
然后你会发现所有的组件分解成更复杂的部分:
 
 
您将注意到“Shape Module” 部分。如果你展开它,你会看到构成形状模块的所有变量,其中一些不会出现在正常视图中。在这里,您可以找到可以操作的变量。
 
 
 
现在,我可以说thisParticle.FindProperty(“ShapeModule.radius”)。floatValue = Time.deltaTime;
 
一种奇怪的格式是在“ShapeModule.radius”中。半径变量名是不可以大写的,即使它显示在检查器中的形状模块组件中。我试着用一个大写的半径变量名来执行我的代码,但这是行不通的。考虑到这一点,我将假定模块名称在必要时是大写的,但该模块的成员不是。
 
最后,当使用浮点数,布尔值等依赖于变量的类型。解决这个问题的最简单方法是在检查器中上下拖动这个值,看看它是否有小数。如果它有小数,则需要使用浮动值来修改值。如果没有,那么您将使用intValue。同样地,如果一个值显示为真或假,那么您将需要使用布尔值。因此,如果我在检查器中拖放半径,很快就会发现这个值中有小数。因此,我将希望使用
SerializedObject.FindProperty(“ShapeModule.radius”浮点数来修改该值。
 
结论
希望这篇文章能帮助你理解你在游戏中控制对象的其他方法。如果您发现Unity自身的库对您想要做的事情没有足够的能力解决,那么您可能需要尝试创建一个序列化的对象来访问您所需要的变量。
 
99VR视界二维码
热门推荐
Hot Recommended
在线客服