DOTween 库详细用法教程

DOTween 是一个用于 Unity 的强大且灵活的动画库,它使用链式语法来创建和控制动画,使得代码更加简洁和易读。下面详细介绍 DOTween 的用法。

安装 DOTween

你可以通过 Unity 的包管理器来安装 DOTween。步骤如下:

打开 Unity 的 Package Manager(可以通过 Window -> Package Manager 打开)。
点击左上角的 “+” 按钮,然后选择 Add package from git URL。
在弹出的窗口中输入 DOTween 的 Git URL:https://github.com/Demigiant/dotween.git。
点击 Add 按钮完成安装。

基本用法

插值动画(Tweening)

使用 DOTween.To、DOTween.From、DOTween.ToX 等方法来创建动画,这些方法通常需要起始值、结束值、动画持续时间和更新频率。

1
2
DOTween.To(() => ump.fValue, fv => ump.fValue = fv, 1f, 3f);
DiffCopyInsert

这行代码的意思是从 ump.fValue 的当前值开始到 1f 的值,持续时间为 3 秒,每帧更新。ump.fValue 是一个属性或字段,fv => ump.fValue = fv 是一个回调函数,用于设置 ump.fValue 的值为动画计算出的新值。

链式语法

DOTween 的动画可以使用链式语法来添加更多的配置,例如 SetTarget、SetLink 等。

1
await tweener.SetTarget(ump).SetLink(fog).GetAwaiter();

这行代码首先设置了动画的目标对象为 ump,然后设置了动画的链接对象为 fog。链接对象的作用是当链接对象被销毁时,动画也会自动停止。GetAwaiter() 用于将动画变为异步等待对象。

等待动画完成

你可以使用 await 来等待动画完成。AwaitForComplete() 是一个扩展方法,用于等待 DOTween 动画完成。

1
await td.AwaitForComplete();

这行代码会暂停当前协程,直到动画 td 完成。

销毁对象

阅读全文 »

C# 集合(Collection)

集合(Collection)类是专门用于数据存储和检索的类。这些类提供了对栈(stack)、队列(queue)、列表(list)和哈希表(hash table)的支持。大多数集合类实现了相同的接口。

集合(Collection)类服务于不同的目的,如为元素动态分配内存,基于索引访问列表项等等。这些类创建 Object 类的对象的集合。在 C# 中,Object 类是所有数据类型的基类。

动态数组(ArrayList)

它代表了可被单独索引的对象的有序集合。
它基本上可以替代一个数组。但是,与数组不同的是,您可以使用索引在指定的位置添加和移除项目,动态数组会自动重新调整它的大小。它也允许在列表中进行动态内存分配、增加、搜索、排序各项。

基本结构

1
public class ArrayList : ICollection, IEnumerable, IList, ICloneable

实现接口:

  • IList:支持按索引访问元素。

  • ICollection:支持集合基本操作,如添加、删除和计数。

  • IEnumerable:支持通过枚举器遍历元素。

  • ICloneable:支持克隆 ArrayList。

特点

动态扩展

  • ArrayList 的容量可以根据需要自动调整,不需要指定固定大小。

  • 当添加的元素超过当前容量时,ArrayList 会自动增加容量(通常是原容量的两倍)。

非泛型集合

  • ArrayList 是非泛型集合,所有元素被存储为 object 类型。这意味着它可以存储任意类型的对象,但需要注意装箱(boxing)和拆箱(unboxing)的性能影响。

无序操作

  • 虽然元素存储顺序与添加顺序一致,但它并不提供内置排序功能。

线程安全

  • 默认不是线程安全的。如果需要线程安全的 ArrayList,可以使用 ArrayList.Synchronized 方法生成一个线程安全的版本。
    ArrayList 类的方法和属性

下表列出了 ArrayList 类的一些常用的 属性:

属性名称	类型	描述

Count	int	获取 ArrayList 中包含的元素数量。
Capacity	int	获取或设置 ArrayList 的容量(存储空间)。
IsFixedSize	bool	指示 ArrayList 是否具有固定大小。
IsReadOnly	bool	指示 ArrayList 是否为只读。
IsSynchronized	bool	指示 ArrayList 是否线程安全。
SyncRoot	object	获取可用于同步访问的对象。

下表列出了 ArrayList 类的一些常用的 方法:

方法名称 返回类型 描述

添加与插入	
 
Add(object value)	int	将对象添加到 ArrayList 的末尾,返回新元素的索引。
AddRange(ICollection c)	void	将指定集合的所有元素添加到 ArrayList 的末尾。
Insert(int index, object value)	void	在指定索引处插入对象。
InsertRange(int index, ICollection c)	void	在指定索引处插入指定集合的所有元素。

删除		

Remove(object value)	void	移除首次出现的指定对象。
RemoveAt(int index)	void	移除指定索引处的元素。
RemoveRange(int index, int count)	void	移除从指定索引开始的指定数量的元素。
Clear()	void	移除所有元素。

访问与查询		

Contains(object item)	bool	判断 ArrayList 是否包含指定对象。
IndexOf(object value)	int	获取指定对象首次出现的索引。
LastIndexOf(object value)	int	获取指定对象最后一次出现的索引。

排序与复制		

Sort()	void	按照默认顺序排序 ArrayList 中的元素。
Sort(IComparer comparer)	void	按照自定义比较器排序。
Reverse()	void	反转 ArrayList 中元素的顺序。
CopyTo(Array array)	void	将 ArrayList 的元素复制到指定数组中。

其他
    
GetRange(int index, int count)	ArrayList	获取从指定索引开始的指定数量的元素子集。
ToArray()	object[]	将 ArrayList 中的元素复制到数组中。
TrimToSize()	void	将容量调整为实际元素数量以节省内存。
阅读全文 »

C# 事件(Event)

C# 事件(Event)是一种成员,用于将特定的事件通知发送给订阅者。事件通常用于实现观察者模式,它允许一个对象将状态的变化通知其他对象,而不需要知道这些对象的细节。

事件(Event)

基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。

C# 中使用事件机制实现线程间的通信。

关键点

  • 声明委托:定义事件将使用的委托类型。委托是一个函数签名。

  • 声明事件:使用 event 关键字声明一个事件。

  • 触发事件:在适当的时候调用事件,通知所有订阅者。

  • 订阅和取消订阅事件:其他类可以通过 += 和 -= 运算符订阅和取消订阅事件。

通过事件使用委托

事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件。这被称为 发布器(publisher) 类。其他接受该事件的类被称为 订阅器(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。

发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。

订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。

声明事件(Event)

在类的内部声明事件,首先必须声明该事件的委托类型。例如:

1
public delegate void BoilerLogHandler(string status);

然后,声明事件本身,使用 event 关键字:

1
2
// 基于上面的委托定义事件
public event BoilerLogHandler BoilerEventLog;

上面的代码定义了一个名为 BoilerLogHandler 的委托和一个名为 BoilerEventLog 的事件,该事件在生成的时候会调用委托。

以下示例展示了如何在 C# 中使用事件:

> 实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using System;

namespace EventDemo
{
// 定义一个委托类型,用于事件处理程序
public delegate void NotifyEventHandler(object sender, EventArgs e);

// 发布者类
public class ProcessBusinessLogic
{
// 声明事件
public event NotifyEventHandler ProcessCompleted;

// 触发事件的方法
protected virtual void OnProcessCompleted(EventArgs e)
{
ProcessCompleted?.Invoke(this, e);
}

// 模拟业务逻辑过程并触发事件
public void StartProcess()
{
Console.WriteLine("Process Started!");

// 这里可以加入实际的业务逻辑

// 业务逻辑完成,触发事件
OnProcessCompleted(EventArgs.Empty);
}
}

// 订阅者类
public class EventSubscriber
{
public void Subscribe(ProcessBusinessLogic process)
{
process.ProcessCompleted += Process_ProcessCompleted;
}

private void Process_ProcessCompleted(object sender, EventArgs e)
{
Console.WriteLine("Process Completed!");
}
}

class Program
{
static void Main(string[] args)
{
ProcessBusinessLogic process = new ProcessBusinessLogic();
EventSubscriber subscriber = new EventSubscriber();

// 订阅事件
subscriber.Subscribe(process);

// 启动过程
process.StartProcess();

Console.ReadLine();
}
}
}
阅读全文 »

C# 委托(Delegate)

在 C# 中,委托(Delegate) 是一种类型安全的函数指针,它允许将方法作为参数传递给其他方法。

C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量,引用可在运行时被改变。

委托在 C# 中非常常见,用于事件处理、回调函数、LINQ 等操作。

所有的委托(Delegate)都派生自 System.Delegate 类。

声明委托(Delegate)

委托是一个引用类型,它定义了一个方法签名,可以用于存储指向该签名的方法。通过委托,你可以调用其他类中的方法。

委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。

声明委托的语法如下:

1
public delegate <return type> <delegate-name> <parameter list>

中文格式说明:

1
public delegate 返回类型 委托名(参数类型 参数名, ...);

例如以下代码,我们定义一个接受两个整数并返回一个整数的委托:

1
public delegate int MathOperation(int x, int y);

以下例子的委托可被用于引用任何一个带有一个单一的 string 参数的方法,并返回一个 int 类型变量。

1
public delegate int MyDelegate (string s);

实例化委托(Delegate)

一旦声明了委托类型,委托对象必须使用 new 关键字来创建,且与一个特定的方法有关。当创建委托时,传递到 new 语句的参数就像方法调用一样书写,但是不带有参数。例如:

1
2
3
4
public delegate void printString(string s);
...
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);

下面的实例演示了委托的声明、实例化和使用,该委托可用于引用带有一个整型参数的方法,并返回一个整型值。

> 实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;

delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}

public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}

static void Main(string[] args)
{
// 创建委托实例
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
// 使用委托对象调用方法
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}

当上面的代码被编译和执行时,它会产生下列结果:

1
2
Value of Num: 35
Value of Num: 175
阅读全文 »

C# 索引器(Indexer)

索引器(Indexer) 允许一个对象可以像数组一样使用下标的方式来访问。

当您为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array) 一样。您可以使用数组访问运算符 [ ] 来访问该类的的成员。

语法

一维索引器的语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
element-type this[int index]
{
// get 访问器
get
{
// 返回 index 指定的值
}

// set 访问器
set
{
// 设置 index 指定的值
}
}

索引器(Indexer)的用途

索引器的行为的声明在某种程度上类似于属性(property)。就像属性(property),您可使用 get 和 set 访问器来定义索引器。但是,属性返回或设置一个特定的数据成员,而索引器返回或设置对象实例的一个特定值。换句话说,它把实例数据分为更小的部分,并索引每个部分,获取或设置每个部分。

定义一个属性(property)包括提供属性名称。索引器定义的时候不带有名称,但带有 this 关键字,它指向对象实例。下面的实例演示了这个概念:

> 实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System;
namespace IndexerApplication
{
class IndexedNames
{
private string[] namelist = new string[size];
static public int size = 10;
public IndexedNames()
{
for (int i = 0; i < size; i++)
namelist[i] = "N. A.";
}
public string this[int index]
{
get
{
string tmp;

if( index >= 0 && index <= size-1 )
{
tmp = namelist[index];
}
else
{
tmp = "";
}

return ( tmp );
}
set
{
if( index >= 0 && index <= size-1 )
{
namelist[index] = value;
}
}
}

static void Main(string[] args)
{
IndexedNames names = new IndexedNames();
names[0] = "Zara";
names[1] = "Riz";
names[2] = "Nuha";
names[3] = "Asif";
names[4] = "Davinder";
names[5] = "Sunil";
names[6] = "Rubic";
for ( int i = 0; i < IndexedNames.size; i++ )
{
Console.WriteLine(names[i]);
}
Console.ReadKey();
}
}
}

当上面的代码被编译和执行时,它会产生下列结果:

1
2
3
4
5
6
7
8
9
10
Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.

重载索引器(Indexer)

索引器(Indexer)可被重载。索引器声明的时候也可带有多个参数,且每个参数可以是不同的类型。没有必要让索引器必须是整型的。C# 允许索引器可以是其他类型,例如,字符串类型。

阅读全文 »

C# 属性(Property)

C# 中的属性(Property)是类和结构体中用于封装数据的成员。它们提供了一种方式来定义类成员的访问和设置规则,通常用于隐藏字段(Fields)的内部实现细节,同时提供控制数据访问的机制。

属性可以看作是对字段的包装器,通常由 get 和 set 访问器组成。

属性(Property)不会确定存储位置。相反,它们具有可读写或计算它们值的 访问器(accessors)。

例如,有一个名为 Student 的类,带有 age、name 和 code 的私有域。我们不能在类的范围以外直接访问这些域,但是我们可以拥有访问这些私有域的属性。

基本语法

1
2
3
4
5
6
7
8
9
10
public class Person
{
private string name;

public string Name
{
get { return name; }
set { name = value; }
}
}

以上代码中,Name 属性封装了私有字段 name。get 访问器用于获取字段值,而 set 访问器用于设置字段值。

自动实现的属性

如果你只需要一个简单的属性,C# 允许使用自动实现的属性,这样你不需要显式地定义字段。

1
2
3
4
public class Person
{
public string Name { get; set; }
}

在这种情况下,编译器会自动为 Name 属性生成一个私有的匿名字段来存储值。

只读属性

如果你只需要一个只读属性,可以省略 set 访问器。

1
2
3
4
5
6
7
8
9
public class Person
{
public string Name { get; }

public Person(string name)
{
Name = name;
}
}

只写属性

类似地,如果你只需要一个只写属性,可以省略 get 访问器。

1
2
3
4
5
6
7
8
9
public class Person
{
private string name;

public string Name
{
set { name = value; }
}
}

自定义逻辑

你可以在 get 和 set 访问器中包含自定义的逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Person
{
private string name;

public string Name
{
get { return name; }
set
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("Name cannot be empty.");
name = value;
}
}
}

计算属性

阅读全文 »