Unity编辑器界面:菜单栏,层级窗口,工程栏,对象的inspector窗口。
1.菜单栏
和大多数软件差不多,基本功能,文件读取,设置等等功能。
2.层级窗口
就是当前场景下所有的那些对象都在这儿,在Unity当中,万物都是对象(游戏体),都是一个object。
3.工程栏
该项目中的所有元素均在这儿,包括Assets文件,里面有各种prefabs还有其他脚本之类的。
4.Inspector窗口
点击任意一个对象,可以在unity编辑器的右边看到它的一些属性,包括组件,等等信息。
5.脚本代码:
1)脚本简介:脚本其实就相当于一个组件,在Unity-C#脚本当中,没有提供main函数的,所有的代码都只是继承与MonoBehavior的一个子类,并且文件名要和类名一致。脚本要附在游戏体上才可以运行,相当于给予游戏体一个灵魂,让它实现我们所需要的功能。
组件系统:对于任意一个游戏体,它最初是没有功能的,有功能的只是若干的unity组件(Unity底层好像也是C++开发的?)。在unity中,它的组件系统有声音播放器,脚本,摄像机,物体碰撞等等。为游戏体添加组件(component)才能实现对应的功能,这就是组件式编程。
2)关于实例化:在面向对象的变成当中,其中类是一个抽象的概念,我们进行各种比如运算操作时,都是需要具体的。比如说要三年级二班的班长去参加比赛,是要指定某个特定的人(班长),三年级二班是抽象的,班长是属于三年级二班具体的一个对象。实例化就相当于在要做运算操作前进行的C语言声明变量,比如说int a;a+=3;int a=3;int是抽象的一个数据类型,我们不可能对int进行操作,是对a操作的。而int a=3;和int a的区别在于,int a=3;是在内存已经开辟空间放a了,而int a仅仅是声明罢了,开辟了空间,但是a并没有在里面。
3)脚本执行顺序:实例化后最先执行的函数,执行一次--awake()-->OnEnable--》Start()-->Update().关键就是Start()和Update()两个函数,打开创建的C#脚本,一般都会自带这两个函数,其中Update()函数是每一帧都调用一次的。帧数的概念就是每一秒刷新多少次.如30FPS,就相当于每秒刷新30次.
4)脚本的序列化:大部分游戏都有一套"配置"系统,比如使用配置文件定义游戏中的角色生命值,移动速度值,在Unity中,一些简单的配置数值可以直接在脚本中暴露出来,然后在编辑器中方便的设置。默认只有继承自Mono Behavior的脚本才能序列化,并且只能序列化public类型的变量,且不能序列化属性。例如,public int id=0;public float m_Speed=0;其中m_会被自动省略,Inspector面板只会显示Speed=0;
6.预置文件prefabs
当某个组件要经常被重复使用时,我们可以先制定一个组件,并为其添加上对应的参数设置,然后把它设置成一个prefabs,就比较方便我们后续的使用啦。直接拖动至project窗口就可以设置成了,修改了prefab的某项参数,会自动同步到场景中去的,当然不放心也可以重新为场景中的游戏体添加prefab.关于prefab的实例化,不能使用new,而是要用到instantiate(object original);Instantiate函数实例化是将original对象的所有子物体和子组件完全复制,成为一个新的对象。这个新的对象拥有与源对象完全一样的东西,包括坐标值等。
7.C#基本语法,概念:
一:基本概念
1)数据类型:
在使用任意一个对象前,必须声明这个对象的类型,如整型,浮点型,字符型,每个类型表示所占内存的大小,如int类型就是4个字节.关于浮点型,C#默认是double型,但是一般来说float就可以了,例如float somevar=01f;
| 值类型:包括int char float bool等内置类型,还有结构类型:struct 枚举类型:enum | 引用类型:class 和委托delegate |
区别:在内存中的存储方式不同 | 栈中静态分配 | 堆中动态分配 |
有了类型,就会有类型的转换,其中包括隐式,显式转换。隐式转换:一般指的是从占低字节的数据类型如short转换为int,因为是从低-->高,所以不会丢失信息。显式转换:这个就是强制转换了,就是反过来从高字节的数据类型转换成低字节的数据类型,所以有可能存在信息的丢失。例如:
short x=10;
int y;
x=(short)y;
2)标识符(名称)与关键字:
标识符,也就是各种类型,方法,变量对象的名称.命名规则:必须以字母或者下划线开头,并区分大小写,不能和关键字一样。
关键字:系统自身设定的比如说int a;int为整型数据的关键字,a为标识符.
3)语句与表达式
语句:程序是由若干条语句组成的,一条完整的程序指令成为语句,以分号结尾。例如int a;这就是一条语句。
表达式:能够计算出值的语句叫做表达式,通常用赋值符号”=“进行操作。例如
int first;//语句
first=10;//表达式
int second=first;//表达式
4)变量和常量
变量:创建一个变量就是声明这个变量是这类型的,可以在任意时候改变其赋值,但在使用局部变量前,一定要先赋值。
常量:关键字const,并在声明时就赋值,之后再也不能改变它的值了。
5)枚举
枚举特殊的值类型,可以看作是常量列表
enum FRUIT
{
Apple=0,
Banana,//值为1
Cherry,//值为2
}
FRUIT fruit=FRUIT.Apple;//当前的水果类型为苹果
6)数学操作符:+, -, *, /, %
7)关系操作符:==,!=,>,>=,<=,<,<=.经常与if搭配,作用是比较两个值的大小,返回的是bool类型。
8)逻辑操作符:&&,||,!,用于多个表达式的符合语句,如果作为if判断的条件,只有返回值为ture时,才会执行后续的代码。
9)方法:方法也叫做函数。
C#语言中,常用的就是顺序语句,分支语句,循环语句三种语句。在分支语句中,分为有条件分支和无条件分支,遇到函数时,先执行函数然后再返回。在函数中,涉及到的参数的引用问题,包括形参(函数的参数)和实参(调用者传过来的参数)。一般来说,在函数内部使用的是实参的副本,也即是形参,所以在函数内部改变的只是形参的大小,不会影响实参;如果想改变实参,则需要添加ref和out标识符。例如:
void Chang(ref int a )//表示引用的是变量本身,而不是创建副本
int a=0;
Chang(ref a);
ref和out 的区别:out是必须在方法内部先初始化变量再使用它。
10)递归:在方法中调用当前方法本身,这叫做递归,如果没有中止条件,递归调用将会无限循环下去,因此递归一定要有结束条件。
11)条件分支语句:if,else,switch。
switch(fruit)
{
case 0:
--
break;
case 1:
--
break;
case 2:
--
break;
}
12)循环语句
三要素:循环控制变量的初始值,循环判断条件,控制变量的变化(循环结束条件)。涉及到的两个退出循环语句的关键字break和continue,break是退出整个大循环,continue是退出当前这一层循环。
13)三元操作符:格式:条件表达式?表达式1:表达式2.在?前的表达式如果成立,则返回表达式1,否则返回表达式2.
例如:
int a=50,b=100;
int max=a>b?a:b;//max的值为100。
14)预处理:#define,定义在using前,且不需要分号。
二:面向对象编程
1.类:
类是面向对象编程的基本元素,它是对现实世界的抽象,即可以将每一个事物看作是一种类型。类里面的成员包括,属性,字段,方法。
成员定义:
- public----成员可以由任何代码访问
- private----成员只能由类中的代码访问(如果没有使用任何关键字,默认使用这个关键字)
- internal----成员定只能由义他的程序集(命名空间)内部的代码访问
- protected----成员只能由类或派生类的代码访问
- protect和internal也可以结合使用 protected internal ,表示它们只能由项目中派生类的代码来访问
- 用static关键字修饰,则表示它们是类的静态成员,而不是对象的实例成员,所以无论是属性,字段还是方法,只能由类本身来调用,而不能由类的对象来调用。
1)字段:可以理解为类的一个私有变量,通常采用readonly和static关键字来修饰。
class MyClass
{
public readonly int MyInt = 2017;//表示这个字段只能在 执行构造函数的过程中赋值,或者由 初始化语句赋值
}
class MyClass
{
public static int MyInt;
}
2)属性:可以理解为类的一个公有变量,通常都是公有的,属性有get 和 set 两个方法,set 设置属性的值,get 获取属性的值。
3)方法:方法分为实例方法和静态方法,就是如果是静态的只能由类本身来调用,并且只能调用静态字段,不允许调用非静态字段 。
public class Player//其中public是作用域,继承自父类的所有子类都可以使用这个类。class是关键字,表示类,Player是类的名称。
{
public int id{get;set;}//类的成员属性
private string name=string.Empty;//类的成员变量
public Player()//类的构造函数,名称与类名一致,实例化时该函数会被自动调用。
{
}
public void Init(){}//类的成员函数
}
C#中采用new实例化类的对象,并保证类的对象一定是引用类型的。引用类型和内置类型的区别主要是,引用类型在没有使用new分配之前的值都为null,使用new为其分配内存后,引用类型的值是指保存对象数据的内存地址而不是对象的数据本身。例如:
Player player=new Player();//实例化Player对象,player的值指向一块内存地址
player.Init();//调用公有成员函数
Player playercopy=player;//指的是playercopy和player指向同一块内存地址
playercopy.id=2;//这时player.id的值也为2.
playercopy=null;//说明playercopy的指针和player指向的不一样了,此时对player 的值没有任何影响
player=null;//player的值为null,C#中有垃圾回收机制,当程序执行到对象的作用域以外没有任何变量引用到实例化对象时,对象会被系统自动地删除。
2.this关键字
在每个类的方法当中,都可以使用this关键字指向当前对象。有时this是可以省略的,但当需要返回值是自身当前对象时,就可以用return this;了。
3.面向对象的核心:封装,继承和多态。
1)封装:每个对象都包含有它能进行操作的所有信息,这个特性称为封装。这样的方法包含在类中,通过类的实例来实现。public protected,internal,private决定类或者类成员的可见性,如果不加修饰符,则默认是private。在C#中,可以用成员属性对成员变量进行封装,通过set和get方式将属性设置为可写或者只读,set方式有一个隐藏的参数value,它指向属性的参数,。只使用get方式的属性,即意味着只读。
2)继承:指每一个类都可以继承另一个类(称为父类)的全部成员属性和方法,并进行扩展,重写父类的方法或者添加新的成员变量和方法(在父类中用virtual关键字来表示该方法是虚方法,可以被子类重写)。子类可以继承所有父类当中非私有的部分,显然,私有财产还是不能乱动的,就是你现有的财产,一部分继承自你父亲的,(当然父亲还有一些私房钱),一部分是你自己自立更生得来的。继承破坏了封装性,使得父类变化时,子类也会变化。需要注意的是私有的成员是不能继承的。
3)多态:指的是将子类转为父类不需要显式的类型转换,被转为父类的对象仍然可以执行真正子类的重载方法。子类中用override关键字来重写父类中用virtual关键字修饰的方法。
4.静态成员:
在定义类的成员属性或者方法时加上static,即表示它是一个静态成员,它不能被的对象引用,它的值会被所有对象共享。不能在静态方法中调用非静态的属性或方法。
5.异常处理:throw关键字来抛出异常。如throw new System.DivideByZeroException();//所有异常的基类是System.Exception。用关键字try语句块会捕获throw的异常状态,然后再catch语句块获取异常信息,finally语句块是可选的,无论是否发生异常,程序都会进行到这,适合做一些资源的清理
三:字符串
在C#当中,字符串使用string关键字声明的一个字符数组string str1="apple orange banana",它也是一个对象,封装了所有字符串的操作如比较(String.Compare()是这个类调用的,不是对象),插入(str1.Insert()),删除str1.Remove()和查找str1.IndexOf('字符',位置)。字符串是不可以被修改的,所有字符串修改的结果只能保存至另一个字符串当中。虽然String 是引用类型,但是String的比较和赋值都是按值传递的,它的使用几乎和值类型的使用一致,初始化空字符串的方式:
string str1 =string.Empty;//比较常用
string str2="";//比较少用
if(string.IsNullOrEmpty(str1)){}//推荐的判断字符串是否为空的方式.
当然,字符串还有很多各种各样其他的对字符串操作的函数。
四:数组
数组就相当于一个容器,将一连串相同类型的数据按顺序保存起来,有一维的数组还有多维的。同样的,对于数值类型的数据默认初始值为0,而引用类型默认为null,索引从0开始。
int[] array1=new int[2];//声明了一个存放整型数据的数组array1,里面有两个元素,分别是array1[0]=0,array1[1]=0,
//声明数组同时赋值
int[] array2=new int[]{1,9,5,7,3};
//另一种声明方式
int[] array3={1,2,3,4,5,6}
//声明二维数组:注意[,]里面有逗号
int[,] multiArray=new int[2,3];
//声明二维数组并且同时给值
int[,] multiArray2={{1,2,3},{4,5,6}};//其中multiArray2[0,0]=1;multiArray2[0,1]=2;multiArray2[0,2]=3;multiArray2[1,0]=4;multiArray2[1,1]=5;multiArray2[1,2]=6;可以看作是2x1的列向量每个向量3维。
数组是从抽象基类array派生的引用类型。由于此类型实现了IEnumerable接口的IEnumerator,因此可以对C#中的所有数组使用foreach迭代。
五:基本I/O操作
I/O操作主要针对计算机文件的创建和修改,在游戏中,最常见的功能是将游戏记录写入一个文件当中,并可以随时读取,这个过程主要包括创建文件,读写文件和删除文件。
1.写文件:写文件即是将数据存入到一个文件的过程。例如
string file="d:\\test.dat";//首先利用字符串定义存储文件的存储路径和文件名
string[] data = new string[2];//创建一个string数组保存两条数据。
data[0]="第一条信息";
data[1]="第二条信息";
//将两条数据写入C盘的test.dat文件当中,利用System.IO.File.WriteAllLines(file,data);
System.IO.File.WriteAllLines(file,data);
2.读文件:和写文件同样的操作,不过要先判断文件是否存在。
System.IO.File.Exists(file);
//先定义文件的存储地址
string file="d:\\test.dat"
//判断文件是否存在。
if(System.IO.File.Exists(file))
//定义用于存放数据的数组
string[] data = new string[2]
data=System.IO.File.ReadAllLines(file,data);
3.删除文件:IO.File.Delete()
4.二进制的读写:
无论时int,float或是其他的数据类型,都可以将其转换成byte(字节)存入到数组当中,然后写入到文件中,读取回来时再转为正确的数据类型使用。
六.泛型:
1.C#的泛型和C++的模板由很多相似之处,其作用是最大限度地重用代码,保护类型安全性以及提高性能。比如说定义了一个交换函数Swap。
static void Swap<T>(ref lhs, ref rhs)//交换两个变量的值,类型是泛型参数T
{
T temp;
temp=lhs;
lhs=rhs;
rhs=temp;
}
int a=1,b=2;
Swap<int>(ref a,ref b);//T的类型是int,可以省略,交换了a和b的值.
string s1="abc";
string s2="xyz";
Swap(ref s1,ref s2);//T的类型是string ,交换了s1和s2的值.
当泛型的参数类型为对象时,则必须使用泛型约束,告诉编译器该泛型参数属于哪个类型以便调用该对象的成员。
static T Create<T>()where T :BaseClass,new()//约束泛型参数继承BaseClass
2.List的常见操作
C#的System.Collection.Generic提供了大量的泛型库,主要是对集合操作算法的各种实现,比较常用的是List和Dictionary等,List实现的是对线性数组的管理,Dictionary实现的是键值对应字典结构数据集合。需要注意的是,初始化泛型集合的时候,建议根据需要预先分配好一定的内存空间,否者再连续插入新元素的过程中,泛型集合内部会不断重新申请内存,对性能有一定影响。
List<int> list =new List<int>(100);//预先分配100个int内存空间.
此外,List还能实现很多便利的操作,如在数组中查找,排序等(如果元素是内置类型的,直接sort,list.Sort()就行;如果是引用类型,就要用到ICompare()接口或者Lambda表达式)。如
public class PlayerCompare :IComparer<Player>
{}
七.委托:
1.在C#中,委托就像C语言中的函数指针,可以将函数作为参数传递,比较典型的应用实例如创建回调函数。委托的使用方法:首先要用delegate关键字声明一个委托函数,并且定义它的返回值和参数列表。在定义调用委托的地方,并不确定将来委托函数会做什么,通常这样的程序设计会更加的模块化,减少代码耦合性,重用性更强.
2.Lambda,泛型委托,Action和Func
八.反射和特性
反射指程序在运行过程中获取运行时的相关信息,包括Assembly(程序集),Modules(模块),Type(类型),Methods(方法),Fields(成员变量),Properties(属性)等。反射使用的库:using System.Reflection。