- 最后登录
- 2014-10-23
- 注册时间
- 2011-7-19
- 阅读权限
- 90
- 积分
- 81303
 
- 纳金币
- -1
- 精华
- 11
|
Showing multiple graphs
Just one graph is a little boring. It would be nice if we had multiple graphs to show. All that's needed is different ways to compute p.y, the rest of the code can stay the same. Let's make this explicit by extracting the code that computes p.y and put it in its own method, which we'll call Linear. All this method does is mimic the mathematical function f(x) = x. We're making this method static because it doesn't require an object to function. All it needs is an input value.What does return do?Does it need to be static?
void Update () {
if(currentResolution != resolution){
CreatePoints();
}
for(int i = 0; i < resolution; i++){
Vector3 p = points.position;
p.y = Linear(p.x);
points.position = p;
Color c = points.color;
c.g = p.y;
points.color = c;
}
emitter.particles = points;
}
private static float Linear (float x) {
return x;
}
It's easy to add other mathematical functions by creating more methods and calling them instead of Linear. Let's add three new method. The first is Exponential, which calculates f(x) = x2. The second is Parabola, which calculates f(x) = (2x - 1)2. The third is Sine, which calculates f(x) = (sin(2πx) + 1) / 2.What's Mathf?
private static float Linear (float x) {
return x;
}
private static float Exponential (float x) {
return x * x;
}
private static float Parabola (float x){
x = 2f * x - 1f;
return x * x;
}
private static float Sine (float x){
return 0.5f + 0.5f * Mathf.Sin(2 * Mathf.PI * x);
}
Having to change the code each time we want to switch between these three options isn't very handy. Let's create an enumeration type which contains en entry for each function we want to show. We call it FunctionOption, but because we define it inside our class it's officially known as Grapher1.FunctionOption.
Add a public variable named function of the new type. This gives us a nice field in the inspector for selecting functions.
What's an enum?
using UnityEngine;
public class Grapher1 : MonoBehaviour {
public enum FunctionOption {
Linear,
Exponential,
Parabola,
Sine
}
public FunctionOption function;
public int resolution = 10;
private int currentResolution;
private Particle[] points;
private ParticleEmitter emitter;
// methods not shown in this example
}
Selecting a function in the inspector is nice, but it doesn't do anything yet. Each update, we need to decide which method to call based on the value of function. There are various ways to do this and we'll use an array of delegates.
We first define a delegate type for methods that have a single float as both input and output, which corresponds to our function methods. We call it FunctionDelegate. Then we add a static array named functionDelegates and fill it with delegates to our methods, in the same order that we named them in our enumeration.
What's a delegate?Why list the method names twice?
public class Grapher1 : MonoBehaviour {
public enum FunctionOption {
Linear,
Exponential,
Parabola,
Sine
}
private delegate float FunctionDelegate (float x);
private static FunctionDelegate[] functionDelegates = {
Linear,
Exponential,
Parabola,
Sine
};
public FunctionOption function;
public int resolution = 10;
private int currentResolution;
private Particle[] points;
private ParticleEmitter emitter;
// methods not shown in this example
}
Now we can select the desired delegate from the array based on our function variable, by casting it to an integer. We store this delegate in a temporary variable and use it to calculate the value of Y.
void Update () {
if(currentResolution != resolution){
CreatePoints();
}
FunctionDelegate f = functionDelegates[(int)function];
for(int i = 0; i < resolution; i++){
Vector3 p = points.position;
p.y = f(p.x);
points.position = p;
Color c = points.color;
c.g = p.y;
points.color = c;
}
emitter.particles = points;
}
Finally, we can change which function is graphed while in play mode!
Although we need to to recreate the graph each time we select another function, the rest of the time nothing really changes. So it's not required to compute the points each update. However, things change if we introduce time into the functions. As an example, let's change the Sine method so it calculates f(x) = (sin(2πx + Δ) + 1) / 2, where Δ is equal to the play time. This results in a slowly animating sine wave. Here's the entire script.
using UnityEngine;
public class Grapher1 : MonoBehaviour {
public enum FunctionOption {
Linear,
Exponential,
Parabola,
Sine
}
private delegate float FunctionDelegate (float x);
private static FunctionDelegate[] functionDelegates = {
Linear,
Exponential,
Parabola,
Sine
};
public FunctionOption function;
public int resolution = 10;
private int currentResolution;
private Particle[] points;
private ParticleEmitter emitter;
void Start () {
emitter = GetComponent< articleEmitter>();
CreatePoints();
}
private void CreatePoints () {
if(resolution < 2){
resolution = 2;
}
currentResolution = resolution;
emitter.ClearParticles();
emitter.Emit(resolution);
points = emitter.particles;
float increment = 1f / (resolution - 1);
for(int i = 0; i < resolution; i++){
float x = i * increment;
points.position = new Vector3(x, 0f, 0f);
points.color = new Color(x, 0f, 0f);
}
}
void Update () {
if(currentResolution != resolution){
CreatePoints();
}
FunctionDelegate f = functionDelegates[(int)function];
for(int i = 0; i < resolution; i++){
Vector3 p = points.position;
p.y = f(p.x);
points.position = p;
Color c = points.color;
c.g = p.y;
points.color = c;
}
emitter.particles = points;
}
private static float Linear (float x) {
return x;
}
private static float Exponential (float x) {
return x * x;
}
private static float Parabola (float x){
x = 2f * x - 1f;
return x * x;
}
private static float Sine (float x){
return 0.5f + 0.5f * Mathf.Sin(2 * Mathf.PI * x + Time.timeSinceLevelLoad);
}
}
|
|