【C#基础】unity中结构体的使用
结构体(Struct)是值类型数据结构,在栈上分配内存,可以包含字段,属性,方法,构造函数。结构体可以实现接口,但是不能继承。在Dots里有大量依靠Struct实现接口来定义Entities数据类型和实现逻辑。
一、结构体的基本使用
- 定义结构体
- 结构体初始化
- 结构体方法
- 结构体扩展方法
1.定义结构体
结构体一般用于小型的数据类型,下面定义一个双精度的三维坐标数据为例。
c
Public struct DoubleVec {}
2.结构体初始化
(1)通常通过构造函数对结构体进行初始化,也可以单独定义后赋值。
结构体
c
public struct DoubleVec
{
public double x;
public double y;
public double z;
//构造函数
public DoubleVec(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
初始化和单独赋值
c
DoubleVec doubleVec1;
DoubleVec doubleVec2;
void Start()
{
doubleVec1 = new DoubleVec(1, 1, 1);
doubleVec2.x = 3;
Debug.Log("doubleVec1.x=" + doubleVec1.x);
Debug.Log("doubleVec2.x=" + doubleVec2.x);
}
结果
c
doubleVec1.x=1
doubleVec2.x=3
(2)没有对结构体进行初始化或者赋值,直接调用结构体的字段
重新定义一个字段类型多的结构体
c
public struct DoubleVec
{
public float x;
public float y;
public double z;
public string name;
public Vector3 vec;
public bool bo;
public int[] ints;
}
直接使用字段
c
DoubleVec doubleVec2;
void Start()
{
Debug.Log("doubleVec2.y=" + doubleVec2.y);
Debug.Log("doubleVec2.vec=" + doubleVec2.vec);
Debug.Log("doubleVec2.name=" + doubleVec2.name);
Debug.Log("doubleVec2.ints=" + doubleVec2.ints);
Debug.Log("doubleVec2.bo=" + doubleVec2.bo);
Debug.Log("doubleVec2.x=" + doubleVec2.x);
}
结果
c
doubleVec2.y=0 //浮点类型初始为0
doubleVec2.vec=(0.00, 0.00, 0.00)//vecter初始为原点
doubleVec2.name= //字符串为空
doubleVec2.ints= //数组为空
doubleVec2.bo=False //bool为false
doubleVec2.x=0
(3)构造函数
实例构造函数:初始化字段信息,构造函数参数必须对没有字段进行赋值
静态构造函数:当结构体构造实例时,静态构造函数会自动调用一次;不带任何参数,不带修饰符。
c
public struct DoubleVec
{
public double x;
public double y;
public double z;
//构造函数
public DoubleVec(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
//静态构造函数
static DoubleVec()
{
Debug.Log("被调用");
}
}
3.结构体方法
- get方法
- 结构体传参方法
- 逻辑运算
(1)get方法
可以直接在结构体变量后使用,下面以求模长为例
c
DoubleVec doubleVec1;
void Start()
{
doubleVec1 = new DoubleVec(1, 1, 1);
//这里直接可以点出方法
double mag= doubleVec1.Magnitude;
Debug.Log("mag=" + mag);
}
创建的方法
c
public struct DoubleVec
{
public double x;
public double y;
public double z;
//构造函数
public DoubleVec(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
//必须用get方法给方法赋值
public double Magnitude {
get {return magnitude(); }
}
//求模长的方法
double magnitude()
{
double a = getLength(x, y);
double b = getLength(a, z);
return b;
double getLength(double a, double b)
{
return Math.Sqrt(a * a + b * b);
}
}
}
该方法只能使用结构体变量的字段进行逻辑处理,与结构体的字段关联
(2)结构体传参方法
可以在结构类型后面点出方法,传入参数进行逻辑处理,同样以求模长为例
c
DoubleVec doubleVec1;
void Start()
{
doubleVec1 = new DoubleVec(1, 1, 1);
//这里是同结构体类型点出方法,参数为结构体变量
double mag= DoubleVec.MagnitudeVec(doubleVec1);
Debug.Log("mag=" + mag);
}
创建方法
c
public struct DoubleVec
{
public double x;
public double y;
public double z;
//构造函数
public DoubleVec(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
//这里要用静态方法,参数与结构体本身的字段没有关系
public static double MagnitudeVec(DoubleVec vec)
{
return magnitude(vec);
}
//运算方法也要静态
static double magnitude(DoubleVec vec)
{
double a = getLength(vec.x, vec.y);
double b = getLength(a, vec.z);
return b;
double getLength(double a, double b)
{
return Math.Sqrt(a * a + b * b);
}
}
}
这种方法是很独立的,与结构体本身没有关联,只能算逻辑上的分类
(3)逻辑运算
这里的逻辑运算包括:加、减、乘、除、大于、小于、等于、不等于等。下面以实现加法为例。
c
DoubleVec doubleVec1;
DoubleVec doubleVec2;
void Start()
{
doubleVec1 = new DoubleVec(1, 1, 1);
doubleVec2 = new DoubleVec(2, 2, 2);
DoubleVec doubleVec3 = doubleVec1 + doubleVec2;
}
创建方法
c
public struct DoubleVec
{
public double x;
public double y;
public double z;
//构造函数
public DoubleVec(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
//使用operator运算符重载方法
//参数中必须有一个为DoubleVec
public static DoubleVec operator +(DoubleVec a, DoubleVec b)
{
return new DoubleVec(a.x + b.x, a.y + b.y, a.z + b.z);
}
}
(4)operator 运算符的用法
一元运算符
一个参变量,直接跟变量使用
c
//operator +
public static DoubleVec operator +(DoubleVec a)
{
return new DoubleVec(a.x , a.y , a.z );
}
//operator -
public static DoubleVec operator -(DoubleVec a)
{
return new DoubleVec(-a.x , -a.y , -a.z );
}
//operator ++
public static DoubleVec operator ++(DoubleVec a)
{
return new DoubleVec(a.x+1 , a.y+1 , a.z+1 );
}
//operator --
public static DoubleVec operator --(DoubleVec a)
{
return new DoubleVec(a.x-1 , a.y-1 , a.z-1 );
}
//operator !
public static bool operator !(DoubleVec a)
{
return true;
}
使用方法
c
doubleVec1 = new DoubleVec(1, 1, 1);
DoubleVec doubleVec3 = - doubleVec1;//对应operator +
doubleVec3 = +doubleVec1;//对应operator -
doubleVec3 = doubleVec1++;//对应operator ++
doubleVec3 = doubleVec1--;//对应operator --
bool bo = !doubleVec1;//对应operator !
二元运算符
需要两个变量进行运算
c
//operator +
public static DoubleVec operator +(DoubleVec a, DoubleVec b)
{
return new DoubleVec(a.x + b.x, a.y + b.y, a.z + b.z);
}
//也允许其中一个变量不是结构体的类型
public static DoubleVec operator +(DoubleVec a, double b)
{
return new DoubleVec(a.x + b, a.y + b, a.z + b);
}
//operator -
public static DoubleVec operator -(DoubleVec a, DoubleVec b)
{
return new DoubleVec(a.x - b.x, a.y - b.y, a.z - b.z);
}
//operator *
public static DoubleVec operator *(DoubleVec a, double b)
{
return new DoubleVec(a.x * b, a.y * b, a.z * b);
}
//operator /
public static DoubleVec operator /(DoubleVec a, double b)
{
return new DoubleVec(a.x / b, a.y / b, a.z / b);
}
使用方法
c
doubleVec1 = new DoubleVec(1, 1, 1);
doubleVec2 = new DoubleVec(2, 2, 2);
DoubleVec doubleVec3 = doubleVec1;
doubleVec3 = doubleVec1 + doubleVec2;//对应operator +
doubleVec3 = doubleVec1 - doubleVec2;//对应operator -
doubleVec3 = doubleVec1 + 1;//对应operator +
doubleVec3 = doubleVec1 * 1;//对应operator*
doubleVec3 = doubleVec1 / 1;//对应operator/
比较运算符
两个变量进行比较
c
//operator ==
public static bool operator == (DoubleVec a, DoubleVec b)
{
if (a.x==b.x&& a.y==b.y&&a.z==b.z)
{
return true;
}
else
{
return false;
}
}
//operator !=
public static bool operator !=(DoubleVec a, DoubleVec b)
{
if (a.x != b.x && a.y!= b.y && a.z != b.z)
{
return true;
}
else
{
return false;
}
}
//operator >
public static bool operator >(DoubleVec a, DoubleVec b)
{
double magA = a.magnitude();
double magB = b.magnitude();
if (magA> magB)
{
return true;
}
else
{
return false;
}
}
//operator <
public static bool operator <(DoubleVec a, DoubleVec b)
{
double magA = a.magnitude();
double magB = b.magnitude();
if (magA < magB)
{
return true;
}
else
{
return false;
}
}
//operator >=
public static bool operator >= (DoubleVec a, DoubleVec b)
{
double magA = a.magnitude();
double magB = b.magnitude();
if (magA >= magB)
{
return true;
}
else
{
return false;
}
}
//operator <=
public static bool operator <= (DoubleVec a, DoubleVec b)
{
double magA = a.magnitude();
double magB = b.magnitude();
if (magA <= magB)
{
return true;
}
else
{
return false;
}
}
使用方法
c#
bool _bool = doubleVec1 == doubleVec2;
_bool = doubleVec1 != doubleVec2;
_bool = doubleVec1 > doubleVec2;
_bool = doubleVec1 < doubleVec2;
_bool = doubleVec1 <= doubleVec2;
_bool = doubleVec1 >= doubleVec2;
4.扩展方法
扩展方法可以是对unity中的类,密封类和结构体中的方法进行扩展。也可以对自己创建的结构体和类进行扩展,不过感觉很多余。
创建没有继承的静态类
c#
public static class LearnExtention
{
}
添加静态扩展方法,第一个参数用this修饰,类型为需要扩展的类型,后面为需要扩展的发方法所需要的参数。
c
///对上文的结构体进行扩展,求单位向量
public static class LearnExtention
{
public static DoubleVec normalized(this DoubleVec doubleVec)
{
return doubleVec / doubleVec.Magnitude;
}
}
使用方法
c
doubleVec1 = new DoubleVec(2, 2, 2);
//在类型的变量后点出方法使用
doubleVec2 = doubleVec1.normalized();
//因为方法为静态的,所以可以直接使用
doubleVec2 = LearnExtention.normalized(doubleVec1);