An Introduction to Game Engine and OO Design Patterns
你可能觉得 C# 的 Random 类提供的方法不够用。如果想提供一些特殊随机数产生方法,你可以用以下方法扩展它:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class extend_method_test{
//This is Extened Method, The first parameter beging with (this Type name, args)
public static bool NextBool(this System.Random random)
{
return random.NextDouble() > 0.5;
}
}
public class NewBehaviourScript : MonoBehaviour {
// Use this for initialization
void Start () {
System.Random rand = new System.Random();
print (rand.NextBool ());
}
// Update is called once per frame
void Update () {
}
}
扩展方法必须是静态类中的静态方法,它们的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。cs 编译器会自动将该方法编译到该类的方法表中。
当你需要对 C# 或 unity 的类做一些共性的扩展时,你仅需要将这些静态类的 cs 文件拖入项目编译。
一些常见的扩展方法应用。具体参考:c# 扩展方法奇思妙用
使用 继承机制 与 扩展方法机制 各有哪些优缺点?
lambda 表达式 是一个匿名函数,在 C# 中使用它来创建 delegates 或 expression tree 类型。通过使用 lambda 表达式,可以编写可作为参数传递或作为函数调用的值返回的本地函数。Lambda 表达式对编写 LINQ 查询表达式特别有用。
要创建一个lambda表达式,可以在lambda运算符左侧指定输入参数(如果有的话)=>
,然后将表达式或语句块放在另一侧。例如,lambda 表达式 x => x * x
指定一个已命名的参数 x 并返回 x 平方值。您可以将此表达式分配给委托类型,如以下示例所示:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public delegate int del(int i); //define delegate type
public class LambdaTest : MonoBehaviour {
// Use this for initialization
void Start () {
del myDelegate = x => x * x; //define anonymous function
int j = myDelegate(5); //j = 25
print (j);
}
}
1、表达式 Lambdas
语法
(input-parameters) => expression
例如:
(x, y) => x == y
2、语句 Lambdas
语法
(input-parameters) => { statement; }
例如:
delegate void TestDelegate(string s);
TestDelegate del = n => { string s = n + " World";
Console.WriteLine(s); };
通用代理与泛型
每次都定义代理多麻烦! 微软定义了 Func
和 Action
及其泛型代理,例如:
public delegate void Action<in T1, in T2>(
T1 arg1,
T2 arg2
)
这样,一个简单的三元匿名函数可以表达为:
Action<int, string, bool> sendToLog =
(value, description, doLog) =>
{
if (doLog) Debug.Log("Logging out "
+ value + " and "
+ description);
};
在 Unity 中典型应用场景如程序:
private IEnumerator waitThenCallback(float time, Action callback)
{
yield return new WaitForSeconds(time);
callback();
}
void Start()
{
splashScreen.show();
StartCoroutine(waitThenCallback(5, () =>
{ Debug.Log("Five seconds have passed!"); }));
}
函数回调 和 接口回调 的区别与联系?它们的适用场景?
更多参考微软手册 Anonymous Functions
Dotween 是 Unity 2D 方法使用的运动引擎,用于动画编程。
它通过对 Unity 类扩展,实现了如下功能,官方实例:
// Move a transform to position 1,2,3 in 1 second
transform.DOMove(new Vector3(1,2,3), 1);
// Scale the Y of a transform to 3 in 1 second
transform.DOScaleY(3, 1);
// Pause a transform's tween
transform.DOPause();
现在的任务是运用学到的知识实现上述功能。好难???
要实现 transform 类扩展,显然必须实现如下代码
public static class exciting_programming{
public static Transform DoMove(this Transform transform, Vector3 target, float time)
{
//ToDo What?
return transform;
}
}
问题是如何实现 transform 的 update 呢? 让我们来看一段代码:
using UnityEngine;
using System.Collections;
public static class exciting_programming{
// Construct a MonoBehaviour coroutine method !!!
public static IEnumerator DoMove(this MonoBehaviour mono, Transform trans, Vector3 target, float time) {
for (float f = 1f; f >= 0; f -= 0.1f) {
//just like call update()
Debug.Log (f);
yield return null;
}
}
public static Transform DoMove(this Transform transform, Vector3 target, float time)
{
MonoBehaviour mono = transform.GetComponents<MonoBehaviour> () [0];
mono.StartCoroutine (mono.DoMove(transform, target, time));
return transform;
}
}
public class NewBehaviourScript : MonoBehaviour {
// Use this for initialization
void Start () {
transform.DoMove (new Vector3 (0, 0, 0), 1.0f);
}
}
神奇的 coroutine 啊,程序竟然正确打印出 10 个时间了, 请解释上述代码!
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class exciting_programming{
public static IEnumerator DoMove(this MonoBehaviour mono, Transform trans, Vector3 target, float time, Action callback) {
Vector3 distance = target - trans.position;
for (float f = time; f >= 0.0f; f -= Time.deltaTime) {
//just like call update()
trans.Translate(distance * Time.deltaTime);
//Debug.Log (Time.deltaTime);
yield return null;
};
callback ();
}
public static Transform DoMove(this Transform transform, Vector3 target, float time)
{
MonoBehaviour mono = transform.GetComponents<MonoBehaviour> () [0];
mono.StartCoroutine (mono.DoMove(transform, target, time, () => {
MonoBehaviour.print("end of moving it!");
}));
return transform;
}
}
public class DoMoveIt : MonoBehaviour {
// Use this for initialization
void Start () {
transform.DoMove (new Vector3 (1.0f, 1.0f, 1.0f), 1.0f);
}
// Update is called once per frame
void Update () {
}
}
这个程序非常不错,使用了 方法扩展、协程、lambda 表达式 等技术。既然运动可以表达为协程,那么一个物体的运动如何管理起来?如果你做到了这一点,iTweent 的实现不是菜吗?
不知不觉间,你已拥有了做这样牛叉组件的能力,是不是有所感悟!