初级编程
Awake和Start的区别
- Awake会比Start更早调用。
- 如果取消激活脚本,Awake仍然会调用,但Start不会。(如果GameObject没有激活则两个都不会调用。)
- 两个函数都只会调用一次,即使取消激活再重新激活也不会多执行一次。
- 初始化放在Awake会更为保险。原因在于,例如A和B两个脚本的start函数中需要引用对方的变量。而假设B脚本中的变量b如果在Start进行初始化,那么A脚本的Start函数获取B脚本中的变量b,得到可能是未初始化的,那么可能引发空引用的错误。
- 对于第四点进行拓展,将两个变量的初始化全部放在Awake中进行的话,则不会有上面的情况。因为在调用某对象的变量之前一定会对其初始化。
点积和叉积
可以用于飞行模拟器,例如飞机的方向和竖直向上的方向的乘积小于0说明飞机在攀升。
A向量乘以B向量等于C向量
Transform和Rotate的方法
if(Input.GetKey(KeyCode.UpArrow))
transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
乘以Time.deltaTime可以使得它以每秒走多少米而不是每帧走多少米。
Rotate
if(Input.GetKey(KeyCode.RightArrow))
transform.Rotate(Vector3.up, turnSpeed * Time.deltaTime);
以某个轴为中心进行旋转
线性插值
在制作游戏时,有时可以在两个值之间进行线性插值。这是通过 Lerp 函数来完成的。线性插值会在两个给定值之间找到某个百分比的值。例如,我们可以在数字 3 和 5 之间按 50% 进行线性插值以得到数字 4。这是因为 4 是 3 和 5 之间距离的 50%。 在 Unity 中,有多个 Lerp 函数可用于不同类型。对于我们刚才使用的示例,与之等效的将是 Mathf.Lerp 函数,如下所示:
float result = Mathf.Lerp (3f, 5f, 0.5f);
Mathf.Lerp 函数接受 3 个 float 参数:一个 float 参数表示要进行插值的起始值,另一个 float 参数表示要进行插值的结束值,最后一个 float 参数表示要进行插值的距离。在此示例中,插值为 0.5,表示 50%。如果为 0,则函数将返回“from”值;如果为 1,则函数将返回“to”值。 Lerp 函数的其他示例包括 Color.Lerp 和 Vector3.Lerp。这些函数的工作方式与 Mathf.Lerp 完全相同,但是“from”和“to”值分别为 Color 和 Vector3 类型。在每个示例中,第三个参数仍然是一个 float 参数,表示要插值的大小。这些函数的结果是找到一种颜色(两种给定颜色的某种混合)以及一个矢量(占两个给定矢量之间的百分比)。 让我们看看另一个示例:
Vector3 from = new Vector3 (1f, 2f, 3f);
Vector3 to = new Vector3 (5f, 6f, 7f);
Vector3 result = Vector3.Lerp (from, to, 0.75f);
在此示例中,结果为 (4, 5, 6),因为 4 位于 1 到 5 之间的 75% 处,5 位于 2 到 6 之间的 75% 处,而 6 位于 3 到 7 之间的 75% 处。 使用 Color.Lerp 时适用同样的原理。在 Color 结构中,颜色由代表红色、蓝色、绿色和 Alpha 的 4 个 float 参数表示。使用 Lerp 时,与 Mathf.Lerp 和 Vector3.Lerp 一样,这些 float 数值将进行插值。
重点来了,上面那段都是简单的基础 在某些情况下,可使用 Lerp 函数使值随时间平滑。请考虑以下代码段:
void Update ()
{
light.intensity = Mathf.Lerp(light.intensity, 8f, 0.5f);
}
如果光的强度从 0 开始,则在第一次更新后,其值将设置为 4。下一帧会将其设置为 6,然后设置为 7,再然后设置为 7.5,依此类推。因此,经过几帧后,光强度将趋向于 8,但随着接近目标,其变化速率将减慢。请注意,这是在若干个帧的过程中发生的。
如果我们不希望与帧率有关,则可以使用以下代码:
void Update ()
{
light.intensity = Mathf.Lerp(light.intensity, 8f, 0.5f * Time.deltaTime);
}
这意味着强度变化将按每秒而不是每帧发生。 请注意,在对值进行平滑时,通常情况下最好使用 SmoothDamp 函数。仅当您确定想要的效果时,才应使用 Lerp 进行平滑。
Destroy可以用来销毁物体 也可以用来销毁物体上面的组件:
if(Input.GetKey(KeyCode.Space))
{
Destroy(GetComponent<MeshRenderer>());
}
}
OnMouseDown
OnMouseDown是个按鼠标之后会进行自动回调。
Invoke
Invoke 函数可用于安排在以后的时间进行方法调用。
void Start()
{
Invoke ("SpawnObject", 2);
}
void SpawnObject()
{
Instantiate(target, new Vector3(0, 2, 0), Quaternion.identity);
}
Invoke可实现在几秒之后,然后按照固定的间隔调用
void Start()
{
InvokeRepeating("SpawnObject", 2, 1);
}
void SpawnObject()
{
float x = Random.Range(-2.0f, 2.0f);
float z = Random.Range(-2.0f, 2.0f);
Instantiate(target, new Vector3(x, 2, z), Quaternion.identity);
}
枚举
enum Direction {North, East, South, West};
相当于多个int变量同时声明,但是其值不重要,重要的是它代表一个含义,例如东西南北的含义。 选自unity官方教程
创建属性
只读变量
public int health { get; }
可读可写变量
public int health { get; set; }
在此基础上,我们可以将get和set方法进行拓展:
public class Player
{
private int experience;
public int Experience
{
get
{
return experience;
}
set
{
experience = value;
}
}
比如我们想实现一个经验和等级的关系,就可以不需要声明函数而是对变量的属性进行修改:
public int Level
{
get
{
return experience / 1000;
}
set
{
experience = value * 1000;
}
}
有了以上代码之后,当我们想要获取玩家等级,会自动返回经验除以1000,当我们想要设置玩家的等级,那么我们将会对经验进行乘以1000的操作。 这样就可以实现变量与变量之间存在着一种数值上的等价关系。
静态
只补充一点,很多我们直接使用的方法都是静态方法,例如Input.getAxis(""),因为不需要实例化即可调用该方法。
重载
重载:即在一个类中,存在多个名字相同的函数,一个函数名承载了不同的函数,它们是同时共存的,返回值和参数可以均不同。 重写:子类对父类的函数进行了重新书写的过程,但是返回值和参数必须相同。
重载:
public class SomeClass
{
public int Add(int num1, int num2)
{
return num1 + num2;
}
public string Add(string str1, string str2)
{
return str1 + str2;
}
}
通用(泛型)
以下是一个简单的实现通用方法的例子:
public class SomeClass
{
public T GenericMethod<T>(T param)
{
return param;
}
}
void Start ()
{
SomeClass myClass = new SomeClass();
myClass.GenericMethod<int>(5);
}
通用类的例子:
public class GenericClass <T>
{
T item;
public void UpdateItem(T newItem)
{
item = newItem;
}
}
|