Unity中的C#编程-零基础(Unity2017)
01
什么是C#编程语言
人与机器之间的语言,C#脚本,C#源代码,C#源文件
Unity支持的俩种语言:C# Scripts
JavaScripts
02
安装设置IDE工具VS2017
Unity内置IDE工具:MonoDevelop
关于下载:百度搜索VS官网,下载免费的社区版本。
Unity指定编程工具:Edit -> Preferences(偏好设置) -> External Tools(外部工具) -> External Scripts Editor(外部脚本编辑器)
如果没有的话点击Browse -> 安装目录下的Microsoft Visual Studio -> Common7 -> IDE -> 选择devenv.exe
03
创建第一个C#代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//namespace 命名空间
public class NewBehaviourScript : MonoBehaviour { //public Class(声明一个类) NewBehaviourScript(类名) MonoBehaviour(继承自哪个类)
// Use this for initialzation //使用这个初始化
void Start () { //Start只会调用一次,一般会用来初始化2
print(1);
}
// Update is called once per frame //Update每一次都会被调用
void Update () {
print(2);
}
}
※ Start只会调用一次 Update会每帧调用 在游戏中大概是每秒调用50次也就是一秒50帧
04
场景的保存和脚本的保存
注意脚本的类型要保持一致,注意及时保存场景和脚本
05
关于单行注释和多行注释
单行注释: // 内容 只对这一行生效
多行注释: /* 内容 */ 对中间的多行生效
06
关于日志输出
日志输出就是控制台的输出
① print(); 只能在继承自MonoBehaviour类中使用
①和②都属于提示类,即日志输出的白色圆圈感叹号
② Debug.Log(); 任何黄静都可以使用,没有限制
③ Debug.LogWarning(); 警告 ③是黄色三角感叹号
④ Debug.LogError(); 错误 ④是红色圆圈感叹号
注释快捷键:Ctrl + k Ctrl + c
07
声明变量
变量的名字不能以数字开头
在Statr方法中声明变量 int hp = 100;
08
声明变量的第二种方法
先声明变量(变化的量),再给变量赋值,使用变量(print)之前,一定要初始化(即赋值)变量
双击日志文件中的错误信息可以直接在脚本中定位
声明变量的格式: 数据类型 + 变量名 小数在程序里叫做浮点类型
09
小数和整数数据类型
float hp = 3.4f;
浮点数的精度是表示精确到小数点后几位
010
其它数据类型
bool类型
bool isdie = false; bool值只有俩种类型,一种是True,一种是False
char c = 'c'; 字符类型,存取一个字符
string name = "SiKiisgay";
011
算数操作符加减乘除
+ - * /
float res = 3 + 6.4f; //多个数据类型相运算,返回结果的数据类型是最大的那个数据类型
012
比较运算符
>(大于) <(小于) >=(大于等于) <=(小于等于) ==(等于) !=(不等于)
int hp = 100;
bool res = hp>0; 操作数1(hp) 运算符(>) 操作数2(0)
print(res); 输出的结果为True
int hp = 100;
hp += 10;
print(hp); 日志文件输出的值为110
hp -= 10;
print(hp); 日志文件输出的值为100
int hp = 100;
hp++;
print(hp); 日志文件输出的值为101
hp--;
print(hp); 日志文件输出的值为100
013
if语句
if else 语句
014
数组的声明和使用
声明数组的格式: 类型[] 数组名 = {数组值}
int[] enemyHp = {100,80,20,60,50}; //数组的长度为5
通过索引来访问数组[0,1,2,3,4] 数组名[索引]
print(enemyHp[1]); //输出的值为80,并不是100,因为索引是从零开始的
015
数组的其他声明方式
int[] hp = {10,20,30,40,50,60,70,80,90};
int[] hp = new int[10];
int[] hp = new int[5] {1,2,3,4,5};
016
for循环
for(int i = 0;i < 10;i++){
print("创建敌人");
}
print的输出结果:
创建敌人
创建敌人
创建敌人
创建敌人
创建敌人
创建敌人
创建敌人
创建敌人
创建敌人
创建敌人
让大括号里的内容循环10次
018
方法的定义和调用
method 方法
返回值 方法名 (参数){
//方法体
}
void(空的返回值)
定义方法和调用方法
019
枚举类型
enum RoleType {
mag, //魔法师
soldier, //战士
Wizard //坦克
}
enum EnemyType {
type1, //敌人1
type2, //敌人2
type3 //敌人3
}
RoleType rt = RoleType.mag;
rt = RoleType.soldier;
EnemyType et = EenmyType.type1;
et = EnemyType.type2;
020
方法中参数的作用
方法 方法名 (参数) {方法体}
void OnTriggerEnter (Collider other) {
}
※通过参数来控制方法里面变化的东西(方法 方法名),例如(Vector3 pos),(Collider other)等等。
举个例子:
void CreateEnemy (Vector3 pos) {
敌人类型
位置
其他信息
}
然后在调用方法
CreateEnemy(new Vector3(1,5,5));
CreateEnemy(new Vector3(2,9,10));
CreateEnemy(new Vector3(3,9,12));
这三个敌人的位置信息就会不一样,其他信息相同
021
方法中的返回值
return; 是返回一个值的意思
举个例子:
void Add(int a,int b){
int res = a + b
}
然后,直接在方法中调用
Add(10,67); 这样直接调用是错误的,无法调用内部的res
正确方法是这样:
先定义一个方法:
int Add(int a,int b){
int res = a + b;
return res;
}
然后调用返回的值
int res = Add(10,67);
※同一个方法内的变量名不能相同,但不同变量中变量名可以相同,且返回的类型要与定义的类型匹配
022
类的创建、声明和构造
在Unity中创建脚本,就相当于在创建一个类,类与类可以继承。
举个例子
void Start () {
int hp = 100;
//利用类声明的变量,可以叫对象
Enemy enemy1 = new Enemy(); //构造对象
Enemy enemy = null;
print(enemy); //无法输出,因为没有emeny构造对象,可以赋一个空值null,null就是不存在的,空的
Enemy enemy007 = new Enmemy();
//如果想访问Enemy这个类中的字段,必须在Enemy类中字段前加上public
print(enemy007.name);
print(enemy007.hp);
//分别会输出默认值null和0
}
class Enenmy {
public string name;
public int hp; //加上public的字段才可以通过对象访问
}
023
类中的方法
API手册
024
创建脚本和附加脚本
脚本创建的俩种方式和给游戏体添加脚本的四种方法,一般前俩种比较常用。
025
Unity中脚本的基本结构
不同的类属于不同命名空间,举个例子,就像MonoBehaviour属于UnityEngine命名空间。
创建命名空间:
namespace MyGame {
class GameDate {
}
}
※要想在其他命名空间的类下使用GameDate类,必须先引入它的命名空间即using MyGame。
026
脚本中的变量的定义
public 和 priavte 定义的变量,叫属性,也叫字段,这俩个字被叫做访问修饰符
027
逻辑或运算符
数学运算符
/* 数学运算符
* + - * /
*
* 赋值运算符
* += -= *= /= %=
* a+=b ==> a = a+b
*
* 比较运算符
* >,<,>=,<=,==,!=
*
* 逻辑运算符(bool)
* && || !(取反)
*
*
*/
& 逻辑与操作 只有True和True的结果为True,只要有一个false,那么结果就为false
|| 逻辑或操作 只要有一个为True,那么结果为True
028
if变形和枚举类型的使用
enum HeroType { //枚举相当于创建一个类,应该在已有的类之外创建
Soldier,
Master,
Assassin,
Tank,
Shooter
}
HeroType heroType = HeroType.Soldier; //默认值为战士类型
if(heroType == Soldier){ //if语句后的括号可以不加,满足条件执行的是紧跟其后的语句
}
else if (heroType == Master) {
}
else if (heroType == Assassin) {
} //在if else if语句中只会执行一个条件
else if (heroType == Tank) {
}
else if (heroType == Shooter) {
}
这就是if else if语句和enum枚举类型的应用
029
if语句和switch语句的区别和联系
总的来说if比较灵活,功能可能比switch要强,但switch语句结构清晰
先说switch语句,举个例子:
enum HeroType {
Soldier,
Master,
Assassin,
Tank,
Shooter
}
switch (heroType) {
case HeroType.Soldier: //case语句可以合并起来,如:case HeroType.Soldier:
print("战士"); // case HeroType.Master:
break; // print("战士");
case HeroType.Master:
// print("法师");
print("法师");
// 如果满足俩个case其中的一个,就同时执行下面俩个
break;
case HeroType.Assassin:
print("刺客");
break;
case HeroType.Tank:
print("坦克");
break;
case HeroType.Shooter:
print("射手");
break; //这里也可以加默认的default:,注意默认前面不加case
}
再说一下if ,else if,else的灵活应用,这是switch语句不能实现的
if( hp >= 0 && hp <=80 ) {
print("可以使用所药品");
}
else if (hp > 80) {
print("只可以使用饮料和医疗箱")
}
030
for,while,do while 循环
for循环,举个例子:
销毁游戏体下的子物体得到子物体:Transform[] children = transform.GetConponent();
for(int i = 0;i < children.Length;i++) {
GameObejct.Destroy( children[i].gameObejct );
}
游戏体和它的子物体都消失了,怎么不删除游戏体呢?在for循环中加一个判断条件
if(chidren[i] != transform){ //transform指那个游戏物体
GameObject.Destroy(chilren[i].gameObject);
}
好了,有效果
while循环: while(){} 参数中的条件只要为True,就会一直执行循环体
int i = 0;
while(i < children.Length ) {
if(children[i] != transform){
GameObject.Destroy( children[i].gameObject );
}
i++;
}
while相当于对于for循环的拆分
do while循环:
int i = 0;
do{
if( children[i] != transform ){
GameObject.Destroy(children[i].gameObject);
}
i++;
} while( i < children.Length);
这是do while循环
031
foreach遍历(专门) Transform children = transform.GetComponent();
foreach (Transform t in children) {
if(t != transform ){ //transform指当前游戏物体,就是挂脚本的那个
Destroy(t.gameObject);
}
}
032
Transform t = GetComponent(); //获取Transform组件
Collider[] colliders = GetComponents(); //定义一个数组接受碰撞器
GetComponent加不加s有什么区别呢:加s是获取多个同种类型的组件,不加则是单一获取。
foreach( Collider c in collider ){
print(c);
}
他会输出我们创建的俩个碰撞器,即Box Collider和Sphere Collider
另一种方式则是拖拽赋值
GetComponent<>();也能获取到被禁用的组件
GetComponentInChildren(); //这种不加s的获取的只是第一个子物体的Transform组件
GetComponentsInChildren(); //这种加s获取的是所有的子物体的Transform组件
如果想获取到其他游戏体身上的组件怎么办:
public GameObject player; //首先要获取到这个游戏物体并拖拽赋值
Rigidbody rgd = player.GetComponent(): //下一步获取player身上的Rigidbody组件
033
组件的禁用和激活
举个例子:BoxCollider collider = GetComponent(); //获取到BoxCollider组件
collider.enable = false; //禁用BoxCollider组件,禁用后依然可以调用
访问组件里的属性:Rigidbody rgd = GetComponent(); //获取刚体组件
rgd.mass = 100; //访问刚体组件的质量属性,其他属性还有摩擦力,速度等等
034
获取游戏物体的四种方式 public GameObject gameObject这是一种
public GameObject mainCamera; //获取到主摄像机这个游戏物体
public Camera mainCamrea; //获取到这个游戏物体的组件,在Unity编辑器中要指定这个组件上的游戏物体
访问游戏体的子物体
transform.Find("游戏物体/游戏物体的子物体"); //通过transform访问,访问的是游戏物体下的子物体的Transform组件
transform.Find("游戏物体"); //访问游戏物体,访问的是游戏物体的Transform组件
如果路径不对他会返回null值
通过名字查找游戏物体,比较耗费性能,不推荐使用
GameObject.Find("Main Camera"); //通过名字查找游戏物体
GameObject go = GameObject.Find("Main Camera"); //取得查找到的游戏物体
通过标签查找游戏物体
GameObejct.FindWithTag("player"); //通过标签查找游戏物体
GameObject player = GameObject.FindWithTag("player"); //取得通过标签查找的游戏物体