Unity]初学者要注意的笔记

基本交互

Q、W、E、R指针交互

鼠右+QEWSAD 镜头交互(降升前后左右 平移)

Ctrl + Shift + N 新建空物体

Alt + Shift + N 新建空子物体

Ctrl +Alt+ F 选中物体移动到镜头前

Ctrl + Shift + F 选中物体与镜头完全对齐

F 聚焦选中物体,等同于双击物体sss

Alt + Shift + A 切换物体活动(active)状态

Ctrl + Shift + A 添加组件(component)

Project 及 Inspector 可以锁定

实战

分辨率适配

  1. 使用UGUI,设置如下:
    1. Camera组件下Projectiong设置成Orthographic采用正交。一般建立项目时选择2d即可
    2. Canvas组件下Canvas Render Mode设置成Screen space-Camera让canvas绑定摄像机。
    3. Canvas Scaler(Script)组件下UI Scale Mode设置成Scale With Screen Size缩放是根据屏幕来调整。
    4. 同组件下Reference Resolution设置成你设置的分辨率,比如iphone5:640*960iphone6:750*1334iphoneX:828*1792
    5. 同组件下Screen Match Mode设置成需要的情况,Match Width Or Height:根据宽高Expand:全拉伸Shink:整体缩放

​ 2.部分背景设为11361136 在iphone5,6上依然会有白边,目前解决方案是背景设为11381138。

​ 3.建议美术CG与背景出图大小为,1024*1024(不重要的背景可512*512通过拉伸显示)。

SpriteRenderer(场景_UI)和Image(Canvas_UI)的区别

两者差别不大,只是在绘制时有细微差别,结论是,ui不动的尽量用Image,而要游戏内的元素用SpriteRenderer,其实也就是直接把素材拖入场景

【注意】:代码中修改资源会导致资源永久改变

存初始值,在OnDisable()中修改回去;

脚本

声明

// - - - - - - 枚举
public enum Animal {Dog,Cat} // public也要写上
public Animal myAnimal;

// - - - - - - 整体类型
 [System.Serializable]
    public class SpeceShipComponent {
        public enum ShipComponentType
        {
           Weapon,
           Storage,
           Shield,
           Command,
           Power,
           Structural 
        }
        public ShipComponentType type;
        public int hitpoints = 0;
        public int armor = 0;
        
    }
    public SpeceShipComponent spc;//实例化SpeceShipComponent类型

找物体

GameObject.Find("Cube"); // FindGameObject可能被弃用
GameObject.WithTag("Player"); // FindGameObjectWithTag

显示与激活

public GameObject obj;
void start(){
  // 组件为enabled
  
  
  
  // 游戏对象为active
 	// obj.active = true;// 废弃
  obj.SetActive(true);
  obj.activeSelf.ToString();// 自己本身的激活状态 
  obj.activeInHierarcy.ToString();// 自己在层级菜单中激活状态
}
// 注意这两种不同的状态,比如一个物体的父节点active为false,即便自己active为ture也不显示

[RequireComponent(typeof(Rigidbody))] // 如果找不到这个组件就自己生成一个


OnEnable();// 组件对勾时调用
OnDisable();// 组件取消对勾时调用或游戏结束时
OnDestory();// 游戏结束时调用;

AnimationCurve // 运动曲线

Transform与坐标系

// 以下方法都在GameObject下的transform下
.Right();//xAxis
.Up();//yAxis
.Forward();//zAxis
.TransFormPoint();// 从自身变换到世界坐标
.TransFormDirection();// 自身坐标到世界坐标变换方向 
.localPosition; // 本身坐标
.position; // 世界坐标
.Translate(); // 改变世界
// 旋转 把当前对象只想目标对象
void RotateToTarge(Vector3 targetPos)
{
	Vector3 direction = (targetPos - this.transform.position).normalized;// 指向目标方向
	Quaternion targetRotation = Quaternion.LookRotation(direction);
	transform.rotation = Quaternion.RotateTowards(this.transform.rotation, targetRotation, 45 * Time.deltaTime);
}




键盘

Input.GetKeyDown(KeyCode.Space);

Debug相关

Debug.Log("",obj);// 信息或对象
Debug.LogWarning();
Debug.LogError();

// 画线
Vector3 top = new Vector3(2, 2, 2) + this.transform.position;
Vector3 bottom = new Vector3(-2, -2, -2) + this.transform.position;
Debug.DrawLine(top, bottom,Color.red);

Time类 Random类

// Time类
	.deltaTime 
	.captureFramerate // 游戏世界每秒帧率固定,这个在录屏时很有用
  .time //游戏开始时运行的时间,暂停不算
  .realtimeSinceStartup // 与.time类型,但是暂停不影响
    
// Random类
  .seed= //设置种子
  .value //返回0.0-1.0随机数
  .insideUnitCircle //半径为1圆形内随机点
  .insideUnitSphere //半径为1球体内随机点
  .onUnitSphere //半径为1球体表面随机点
  .rotation // 随机角度
  .rotationUniform // 随机角度(平均分布)
  .Range(min,max) // 在min->max之间随机数

Mathf类

	.Ceil() // 向上取整
  .Floor() // 向下取整
  .Round() // 基本四舍五入,特例:10.5(10)、11.5(12)点前偶数5舍,点前奇数5入
    
  .Sign() // 返回符号,0为正
  .clamp(value,min,max) 
  .clamp(value)
    
// 曲线变换
  .Lerp(a,b,t)// 插值
  .LerpAngle() //
  .MoveTowards(current,target,delta) // 给定速度求值
  .MoveTowardsAngle() //
  .SmoothStep()//同Lerp(),只是有淡入淡出
  .SmoothDamp()
  .SmoothDampAngle()
    
// 其他
  .InverseLerp()//根据当前值求百分比
  .Repeat() //重复
  .PingPong() //来回
  .GammaToLinearSpace() // 颜色上Gamma转线性
  .LinearToGammaSpace() // 颜色上线性转Gamma
  .PerlinNoise() // 噪声图 区间【0-10】     

3d数学基础

点积:求投影,得到的是,如果值为0那么两向量垂直

叉积:求垂直向量,得到的是向量,左手坐标系的方向

Vector3类

	.back .down .forward .left .one .right .up .zero // 静态向量
	.magnitude // 模
  .sqrMagnitude // 模平方
  .normalized // 单位向量
    
Vector3 v1 = new Vector3();
v1.normalized; // 值为v1的单位向量
Vector3.Normalize(v1); //同上,一样的
v1.Normalize(); // v1单位向量化


	Vector3.Angle(); // 两个夹角
 	Vector3.ClampMagnitude(); // 对向量的模进行限制
	Vector3.Cross(); // 叉积
	Vector3.Distance(); // 两点距离
	Vector3.Dot(); // 点积 如果值<0两向量反向
	Vector3.Lerp(); // 与Mathf相同
	Vector3.MoveTowards(); // 与Mathf相同
	Vector3.Cross(); // 叉积

	Vector3.OrthoNormalize(); //垂直单位向量 方便的定义自己的坐标轴,???没理解
	Vector3.Project(); // 将一个向量投射到另一个向量上的投影微量  
	Vector3.ProjectOnPlane(); // 将一个向量投射到另一个向量为法线的一个平面上的投影微量  
  Vector3.Reflect(); // 将一个向量投射到另一个向量为法线的一个平面上生成的反射向量

输入输出

Input类

	Input.mousePosition // 鼠标位置向量
  Input.GetMouseButton(0);//0:左键 1:右键

常用的方法函数

// -------------- Destory 销毁
DestroyImmediate(obj, true); // 立即删除obj,如果obj是资源的话,退出游戏也会永久删除

DontDestroyOnLoad(obj); // 切换场景不删除obj,
// tip1:如果是组件,那么有关这个组件的实体都会被保存下来
// tip2:如果是子节点,那么这个节点不会被保存下来,如果是父节点这个结点包括子结点都会被保存下来

// -------------- Instantiate生成
Instantiate(obj,Vector3);


// -------------- CompareTag 标签
obj.CompareTag("p1"); // 检测是不是"p1"tag 这个比 obj.tag == "p1"更高效

// -------------- SendMessage 消息推送
obj.BroadcastMessage("hide",false);
obj.SendMessage();
obj.SendMessageUpwards();

// -------------- Invoke 延迟执行
Invoke("create",2f);//延迟2s执行create函数
InvokeRepeating("createCube",2f,1f);//延迟2s执行create函数之后每1s重复一次
IsInvoking("createCube");// 是否有createCube程序执行中
CancelInvoke("createCube");// 取消createCube程序

// -------------- Coroutine 协程

void Start() {
  StartCoroutine(Timer()); // 开始协同程序
  StartCoroutine("Timer"); // 利用反射的方式也可以
  StopCoroutine(createCube());// 停止指定
  StopAllCoroutines(createCube());// 停止所有
}
IEnumerator Timer() {
    yield return new WaitForSeconds(1.0f); // 停止执行1秒
    doSomething();
  	for (int i = 0; i < 100; i++)
    {
    	// do something; 
      yield return null;// 停止当前帧
    }
   	doSomething2();
}
yield return WaitForEndOfFrame // 帧结束时,渲染前
yield return WaitForFixedUpdat
yield return Coroutine 

UGUI-Rect Transform

pivot 旋转中心轴

Anchors 是与父物体成比例关系的映射,取值0-1,不能超越父物体,根据父物体改变而影响自身

UGUI-事件

IEventSystemHandler事件接口:
Pointer 鼠标指针类:
IPointerEnterHandler:区域进入
IPointerExitHandler:区域移出
IPointerDownHandler:区域按下(可以移出范围,通过附加条件分左右键)
IPointerUpHandler:区域抬起
IPointerClickHandler:必须在物体本身上完成
Drag&Drop 拖拽类:
IBeginDragHandler:开始(drag大于阈值)
IInitializePotentialDragHandler:区域进入
IDragHandler:拖动中(持续调用)
IEndDragHandler:结束
IDropHandler:脚本放到接受物体的上
Select 点选类:
IUpdateSelectedHandler:区域进入
ISelectHandler:选中时
IDeselectHandler:取消选中时
Input 输入类:
IScrollHandler:鼠标滚轴
IMoveHandler:InputManager->Input.GetAxisRaw
IScrollHandler:InputManager->GetButton
ICancelHandler:InputManager->GetButton

// 拖拽类
public void OnDrop(PointerEventData eventData)
{
  eventData.pointerDrag.name;// 正在拖拽的物体
}
// 点选类
// 点选要其他地方处理下
public void OnPointerDown(PointerEventData eventData)
{
	EventSystem.current.SetSelectedGameObject(gameObject); //设置当前为物体选中状态        
}
public void OnSelect(PointerEventData eventData)
{
	eventData.selectedObject;//当前选中的物体
}

UGUI-组件

text组件,可以使用如下富文本

<b>text</b> <!--粗体-->
<i>text</i> <!--斜体-->
<size=12>text</size> <!--字号-->
<color=green>text</color> <!--指定颜色-->
<color=#00ff00ff>text</color> <!--自定义颜色-->

Button

public Button btn;
btn.onClick.AddListener(ClickEvent);// 添加一个点击事件
btn.onClick.RemoveListener(ClickEvent);// 删除一个点击事件

void ClickEvent(){
 // ... 
}

c#

int 等价System.Int32

bool 等价System.Boolean

structenum

var不用管是什么类型

以上继承于System.ValueTpey,而他又继承于System.Object,它是所有类的基类;

命名:方法首字母大写, 变量首字母**小写*,都使用驼峰命名法。

struct

struct Person
{
	public int age;
	private string name;
	internal string fname; // 包内使用
	protected string lasatName;
}
enum Days { Monday,Tuesday,Wenesday,Thursday,Friday,Saturday,Sunday}

Console.WriteLine(Days.Monday) // Monday
Console.WriteLine((int)Days.Monday) // 0
enum Days { Monday=2,Tuesday,Wenesday,Thursday,Friday,Saturday,Sunday}
Console.WriteLine((int)Days.Wenesday) // 4

enum

Enum E_EXP {
	foo,
	bar,
}

///强行转换
E_EXP x = (E_EXP)Enum.parse(typeof(E_EXP),"foo");

objcet、string、dynamic

	string s1 = "jiaowei"; 
	string s2 = "bigMan"; 
	string u = "\\\u0066\n"; // 输出\f<回车>
	string at = @"C:\Jiaowei\hello.cs"; // 加上@不会处理\转义
  //string format  规则:``
	string format = "asdfjklafd:{0},asdfj:{1}"
	Console.WriteLine(format,s1,s2) // asdfjklafd:jiaowei,asdfj:bigMan

class

class Person
{
		int age
    public int Age
    {
      get
      {
        return age+10;
      }
      set
      {
        age =value-10; // value指代使用的时候=右边赋值的值
      }
    }
}
abstract class Man{ // 抽象类不能被实例化,只能被继承
  
}

interface

interface ISuper
{
		int GetSuper();
}

抽象类与接口的区别:

抽象类是被写的为抽象的属性或方法一定要被继承者重写,而同时其他属性与方法可以被继承使用;

接口里的所有属性与方法都要被实现。

类型转换

隐式转换 显式转换

// == == == == == 隐式转换 从小范围到大;
int i = 10;
long l = i;// 隐式从int->long; 

//类的转换
CParent cp = new CChild();
class CParent
{}
class CChild : CParent
{}

// == == == == == 显式转换
double d = 10.05;
int i = (int)d;
CParent cp = new CChild();
try{
CChild cc = (CChild)cp;//类的转换
}
catch (Exception e)
{
 	Console.WriteLine(e.Message); 
}

cp is CParent;// True 判断是不是此类型

CChild cc2 = cp as CChild; // as 只使用于引用和可为空类型 不能使用在int、string等
Console.WriteLine(cc2 == null);// True 无法转换的时候会为空

字符串与数字

int i = 100;
string s = i.ToString();
int iFromS = Conver.ToInt32("100");//写非数字会报错
int iFromS2 = Int32.Parse("101");//写非数字会报错
int iFroms3;
bool succeed = Int32.TryParse("jkfls",out iFromS3)//写非数字不会给iFromS3赋值默认为0;
// IConveTible,TypeConventer 继承这些借口可以实现自己类里的一些转换

装箱拆箱 Nullable类型

此操作消耗资源,尽量避免

// 装箱 值->引用 开辟空间放入值
int iToBoxing = 100;
object iBoxed = iToBoxing;

// 拆箱 引用->值 从堆里拿出来放到栈上边
int iUnBoxing = (int)iBoxed; 


int? iNullable = null;// 可为空的类型
System.Nullable<int> iNullable2 = 100; // 与上句等价


int i1 = iNullable ?? 123;// ??为当前面为空时取?右边值
Console.WriteLine(i1);// 123
int i2 = iNullable ?? 123;
Console.WriteLine(i2);// 100

条件、循环


// && || 双符号指与js相似,从第一个条件开始计算,如果满足就不执行后面的,即会短路
if(condition1 || condition2 ){
  
}
// & | 单符号指每个条件都运算,不会短路
if(condition1 | condition2 ){
  
}

foreach(var a in arr){
  
}// 如要使用foreach arr必须使用IEnumerable接口 List<T>是可以的

集合类型

数组

// 数组 继承于System.Array
// 一维
int[] n = new int[5];
int[] n1 = new int[5]{1,2,3,4,5};
int[] n2 = new int[]{1,2,3,4,5};
int[] n3 = {1,2,3,4,5};
// 二维数组
string[,] names = new string[5,4];
string[,] names2 = {{"a","b"},{"c","d"}};
// 数组数组类型
byte [][] scores = new byte[5][];//每个长度可以不一样
int [][] number3 = {new int[]{1,2,3},new int[]{4,5,6,7}};//new int[]不能省略

// 有iEmunerable,IEmunerato 可以用foreach()

ArrayList和List

// 继承于System.Collection
ArrayList al = new ArrayList();
al.Add(5);
al.Add(100);
al.Add(5);
al.Remove(5); // 测试时从第一个开始删除
al.Add("jiaowei");
foreach (var e in al)
{
		Console.WriteLine(e);
}

List<int> intList = new List<int>();
intList.Add(100);
intList.AddRange(new int[] { 501, 502 });
Console.WriteLine(intList.Contains(200));// False
Console.WriteLine(intList.IndexOf(501);// 1
intList.Insert(1,100);

Hashtable 和 Dictionary

Hashtable ht = new Hashtable();
ht.Add(123, 321);
ht.Add("age", 12);
ht.Add("name", "jiaowei");
ht["age"] // 12
Console.WriteLine(ht["lover"]); // 为空,不报错  


Dictionary<string, string> d = new Dictionary<string, string>();
d.Add("name", "tom");
d.Add("lover","muji")
Console.WriteLine(d["age"]); // 报错 
// 字典类型在多线程中使用有风险,多线程中最好使用ConcurrentDictionary

SortedList<int, int> sl = new SortedList<int, int>(); // 排序列表,根据key(第一个值)排序

//stack 堆栈 先进后出 封口
//queue 队列 先进先出 不封口

面向对象-继承

class Animal{
  pulbic virtual void Bite()// virtual指可以被重写
  { 
    Console.WriteLine("Animal bite"); 
  }
  pulbic void BiteMan()// 没virtual相当说这个类的自己的方法
  { 
    Console.WriteLine("Animal bite man"); 
  }
}
sealed class dog:Animal// 如果加上sealed 就是这个类无法被继承
{
  public override void Bite() // 重写
  {
    Console.WriteLine("Dog bite"); 
  }
  public new void BiteMan() // 如果子类有同名的话,需要用new,指隐藏父类的方法,要不会重名
  {
    Console.WriteLine("Dog bite man"); 
  }
}

// 难点:构造函数、override/new


C# 运算符重载

// 类
class Complex
    {
        public int Number { get; set; }

        public static Complex operator +(Complex c1, Complex c2)
        {
            Complex c = new Complex();
            c.Number = c1.Number + c2.Number;
            return c;
        }
    }

// 主函数
Complex c1 = new Complex();
Complex c2 = new Complex();
c1.Number = 11;
c2.Number = 22;
Complex c3 = c1 + c2; // 重载+号
Console.WriteLine(c3.Number);

动态多态

委托

public delegate int NumRefDelegate(ref int num);//声明一个带引用参数委托
public delegate int SayHelloDelegate();//声明一个无参数委托
// 匿名方法 AnonymousMethod
NumRefDelegate nod = delegate(ref int num){
	return 2*num;
};
SayHelloDelegate sh = delegate{//无参数委托匿名方法的delegate加不加"()"都可以
  Console.WriteLine("Hello");
}


数据结构

// 数组回顾
int[] numC = new int[3];
float[] numD = new float[]{1.2f,2.4f,3.3f,4.4f};

// 泛型集合 非泛型集合
// NameSpace
System.Collections.Generic;
// ----------List<T>;
// List<T> 本质是数组,只是封装了很多方便的方法
List<int> num = new List<int>();
num.Add(1);// 增
num.RemoveAt(0);//删
num[0]=3;// 改
num[0];// 查
num.Count;// 长度
// ----------Dictionary<TKey,TValue>;
Dictionary<string,string> info = new Dictionary<string,string>();
info.Add("name","tom");// 增
info.Remove("name");//删
info["name"]="jerry";// 改
info["name"];// 查
info.Count;// 长度

foreach(var item in info.Keys)
{
  info[item];// 值
}


Json 操作

// 插件LitJson、unity自带JsonUtility

// ---------------JsonUtility
// 创建
public class Person {
  public string name
  public int age;
}
Person p1 = new Person();
p1.name = "tom";
p1.age = 25;
string jsonStr = JsonUtility.ToJson(p1);// 直接对象转换
// 解析
类型 实例名 = JsonUtility.FromJson<类型>();
// ---------------插件LitJson
// ----方法1
// 创建
string jsonStr2 = JsonMapper.ToJson(p1);// 直接对象转换
// 解析
类型 实例名 = JsonMapper.ToObject<类型>();
// ----方法2
// 创建
JsonData cjd = new JsonData();
cjd["name"] = "tom";
cjd["age"] = 12;
//{"name":"tom","age":12}


string jsonStr2 = JsonMapper.ToJson(p1);// 直接对象转换
// 解析
类型 实例名 = JsonMapper.ToObject<类型>();



时间

System.DateTime.Now.ToString();

可选参数

void CalculateSum(int a,int b,params int[] arr)
{
	int sum = a+b;
	//...
	return sum;
}

ref out传引用

void ChangeRef(ref int a){
	// 可以不赋值
}

void ChangeOut(out int a){
	a=99;// 必须赋值	
}

void main(){
	int a=1;
	int b;
	ChangeRef(a);//ok  
	ChangeOut(a);//ok  
	//ChangeRef(b);//error 没有初始化
	ChangeOut(b); //ok

}

评论