0%

C#基礎

用于记录C#的基础知识,部分来源于unity官方视频

  • 循环

while(条件){}

do{ } while(条件); 语句是先执行再判断,因此程序至少会运行一次。

for(条件){}

  • 常用函数/方法比较

Awake() 即使没有启用脚本也会执行

Start()

Update() 每帧调用一次,适用范围:non-physics objects, simple timers, receiving input

FixedUpdate() 固定时间调用一次,适用范围:physics (rigidbody) objects, 推荐使用力来定义位移

启动与禁用组件 Component.enabled

平移 transform.Translate(Vector3 是移动的方向)

旋转 transform.Rotate(Vector3 是旋转的轴)

平移和旋转作用于局部轴(local axis)而非世界轴(world axis)

GetKey 引用的是按键的固定名字

GetButton 引用的是代表按键的字符串,具体指代哪个按键可以修改

以”Jump”为例

  1. 当空格未按下时:GetButtonDown:False GetButton:False GetButtonUp:False
  2. 当按下空格时: GetButtonDown:True GetButton:True GetButtonUp:False
  3. 按住空格:GetButtonDown:False GetButton:True GetButtonUp:False
  4. 松开空格时:GetButtonDown:False GetButton:False GetButtonUp:True

实例 Instantiate, 常用于克隆prefab, 默认返回gameobject类型,也可以通过强制转换成rigidbody来让物体具有物理效果

  • 向量

向量长度:Vector3.magnitude

判断两个向量是否是垂直:点积(dot products) Vector3.Dot(VectorA,VectorB)

求与两个向量垂直的向量:叉积(cross products) Vector3.Cross(VectorA,VectorB)

unity采用左手坐标系

  • 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
    //Inventory.cs 一个用于管理item的类
    public class Inventory : MonoBehaviour
    {
    //Stuff是Inventory的子类
    public class Stuff
    {
    //子类中的变量
    public int projectileA;
    public int projectileB;
    public int projectileC;
    public float fuel;

    //构造函数
    public Stuff(int prA, int prB, int prC)
    {
    projectileA = prA;
    projectileB = prB;
    projectileC = prC;
    }
    //构造函数
    public Stuff(int prA, float fu)
    {
    projectileA = prA;
    fuel = fu;
    }
    //使用构造函数创建类的实例
    public Stuff myStuff = new Stuff(1,2,3);
    public Stuff myOtherStuff = new Stuff(1, 5.0);

    }

    }
  • 属性

适用于从类之外的代码访问这个类的成员变量。

属性可以当作变量,也可以封装为成员变量,即字段(field)。

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
//Player.cs 我们希望能通过其他脚本使用玩家的经验值
public class Player
{
private int experience; //声明字段(field)

//属性的名称推荐以大写字母开头,内部含有set和get两个访问器(accessor)
public int Experience
{
get
{
//返回所封装的字段,当get不存在时,experience为write only
return experience;
}
set
{
//通过关键字value给字段赋值,当set不存在时,experience为readonly
experience = value;
}
}

public int Level
{
//使用set访问器启动协同程序??
get
{
return experience/1000;
}
set
{
experience = value * 1000;
}
}

//简写
public int Health {get; set;}
}
1
2
3
4
5
6
7
8
9
10
11
//Game.cs 通过属性Experience来访问字段experience
public class Game : MonoBehaviour
{
void Start()
{
Player myPlayer = new Player();

myPlayer.Experience = 5;
int x = myPlayer.Experience;
}
}
  • 静态 Statics

静态成员,例如变量和方法,是跨类的所有实例共享的成员。

可以直接通过类访问,无需先对类的对象进行实例化。例如Input.GetButton()就是一个静态方法。

通常, 成员变量对于类的每一个对象都是唯一的,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Game.cs 在Game类中创建了敌人,并计数
public class Game
{
void Start()
{
Enemy enemy1 = new Enemy();
Enemy enemy2 = new Enemy();
Enemy enemy3 = new Enemy();

//统计Enemy类实例化了多少个对象
int x = Enemy.enemyCount;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
//Enemy.cs
public class Enemy
{
//enemyCount属于类本身,而不属于任何一个实例
public static int enemyCount = 0;

//Enemy类的构造函数,每次调用Enemy类,计数器+1
public Enemy()
{
enemycount++;
}
}
  • 方法重载(method overloading)

overloading is a process by which you can give a single method multiple definitions.

1
2
3
4
5
6
7
8
9
10
11
12
13
//SomeClass.cs
public class SomeClass
{
public int Add(int num1, int num2)
{
return num1 + num2;
}

public string Add(string str1, string str2)
{
return str1 + str2;
}
}
  • 泛型(generics)

当不知道对象的类型时,使用泛型,比如GetComponent就是一种泛型方法

1
2
3
4
5
6
7
8
9
10
11
//SomeClass.cs
public class SomeClass
{
//<T>是泛型参数,after the methods name or before the normal parameters
//可以代表任意类型
//前面的T叫做方法的返回类型(return type),后面的T叫做方法的参数类型(arguement type)
public T GenericMethod<T>(T param)
{
return param;
}
}
1
2
3
4
5
6
7
8
9
10
//SomeOtherClass.cs 用于使用上面创建的泛型方法
public class SomeOtherClass : MonoBehaviour
{
void Start()
{
SomeClass myClass = new SomeClass();

myClass.GenericMethod<int>(5);
}
}
1
2
3
4
5
6
7
8
9
10
11
//GenericClass.cs this class uses a generic type of T
public class GenericClass<T>
{
//类型为T的成员变量
T item;
//
public void UpdateItem(T newItem)
{
item = newItem;
}
}
1
2
3
4
5
6
7
8
9
10
//GenericClassExample.cs 实例化上面的类
public class GenericClassExample : MonoBehaviour
{
void Start()
{
//为T指定一个类型并实例化
GenericClass<int> myClass = new GenericClass<int>();
myClass.UpdateItem(5);
}
}
  • 列表

列表List类似一个动态数组,也是一个泛型类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//创建一个名为ages的List,当按空格时随机生成一个年龄,当按Q时随机删除一个

public class ListExample : MonoBehaviour
{
public List<int> ages = new List<int>();

void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
ages.Add(Random.Range(1,100));
}

if(Input.GetKeyDown(KeyCode.Q))
{
ages.Remove(Random.Range(1,ages.Count));
}
}
}
  • 继承(inheritance)

通常看到的 public class Player : MonoBehaviour {} 表示MonoBehaviour是Player的父类

  • 多态(polymorphism)
  • 接口(interface)

接口的好处在于可以跨越不同的类去定义通用的功能

1
2
3
4
5
6
7
//damageInterface.cs

//接口名通常以大写字母I开头,后面的单词表示能做什么
public interface IDamageable
{
void Damage(); //接口内部只负责声明方法,变量
}
1
2
3
4
5
6
7
8
// wall.cs
public wall : MonoBehaviour, IDamageable
{
public void Damage()
{

}
}
1
2
3
4
5
6
7
8
//car.cs
public car : MonoBehaviour, IDamageable
{
public void Damage()
{

}
}
  • 协同程序(coroutines)

协同程序可视为按时间间隔执行的程序,好处是可以实现update()函数的功能,提高代码的效率

1
2
//

  • 四元数(quaternion)

in Unity, a transforms rotation is stored as a quaternion.

  • 委托(delegates)

一个委托可以代表多个方法,好处是方便在游戏中动态控制需要调用哪些函数,或者是同时调用多个函数

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
//MulticaseScript.cs
public class MulticastScript : MonoBheaviour
{
delegate void MultiDelegate(); //创建委托类型
MultiDelegate myMultiDelegate; //声明成员变量

void start()
{
myMultiDelegate += PowerUp;
myMultiDelegate += TurnRed;

if(myMultiDelegate != null)
{
myMultiDelegate(); //此时这里同时调用两个函数
}
}

void PowerUp()
{
print("aaaaaaaaaaaa");
}

void TurnRed()
{
GetComponent<Renderer>().material.color = Color.red;
}
}
  • 事件

事件属于一种特殊的委托,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//EventManager.cs 这个例子的脚本挂载到主相机上

public class EventManager : MonoBheaviour
{
public delegate void ClickAction();
public static event ClickAction OnClicked; //创建事件变量

void OnGUI()
{
if() //当在游戏画面中点击按钮的时候调用这个事件
{
if(OnClicked != null)
OnClicked();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//ObjectA.cs 脚本挂载到物体A上

public class ObjectA : MonoBheaviour
{
void OnEable()
{
EventManager.OnClicked += MethodName; //当事件触发时,调用订阅了这个事件的方法
}

void OnDisable()
{
EventManager.OnClicked -= MethodName; //退订,防止内存泄漏
}

void MethodName() {}
}
  • 补充技巧

用于调试程序 Debug.Log( );

绘制项目中的对象 OnDrawGizmos() {定义颜色和要绘制的对象}

测试游戏运行时的性能影响 profiler工具

  • 代码规范
  • Uinty Documentation Scipting API

如何查看官方文档,这里以GameObject为例:

Inherits from:Object (继承自Object)

Description:Base class for all entities in Unity Scenes.

Properties:

transform:(通过gameObject.transform来访问,并能看到这属性是只读的。这里的gameObject相当于是GameObject的一个实例。或者直接用transform来访问。区别是什么不知道)

Public Methods:

SetActive:(通过gameObject.SetActive()来调用这个方法)

Static Methods:

Find:(通过GameObject.Find()来调用这个方法)

Inherited Members 继承自Object的一些东西

Properties:

name:(通过gameObject.name或者name来访问)

Public Methods:

ToString:(通过gameObject.ToString()或者ToString()来调用方法)

Static Methods:

Destory:(通过Destroy()或者Object.Destroy()或者GameObject.Destroy()来调用方法。)

总结:对于Properties和Public Methods,先实例化类,再通过实例去调用和访问。对于Static Methods无须实例化,因此可以以类的名字.方法名字去调用。

  • 相关频道推荐

Brackeys:

GameDevHQ/Jonathan: C#初中高级教程

Sebastian Lague: 涉及的范围很广,需要一定基础

  • 还未解决的问题

类中的静态变量和字段都可以用于在外面访问,有什么区别?

序列化 [SerializeField] 好像是把成员变量进行存贮的方法,在加载脚本的时候变量的值会自动被赋值