千锋Unity学习笔记

学习笔记:【千锋合集】史上最全Unity3D全套入门教程|匠心之作

文章目录

  • 初级
    • 1.0数学
      • 1.0点乘叉乘
        • 1.点乘:
      • 2.叉乘:
      • 2.0Mathf
      • 3.0Vector
      • 4.0旋转
    • 2.0组件
    • 3.0调试Debog
    • 4.0时间
    • 5.0Application
    • 6.0场景
        • 1.0两个类
          • 1.2场景类
          • 1.2场景管理类
        • 2.0异步加载
    • 7.0Transform
    • 8.0按键Input
          • 1.点击
          • 2.水平轴虚拟按键
          • 3.触屏
    • 9.0音效视频
      • 1.音频
      • 2.视频
    • 10.0移动
      • 1.0移动
      • 2.0**Vector.forward **和 **transform.foward**的区别
    • 11.0射线
    • 12.0画线
      • 1.Line Renderer组件
      • 2.trail Renderer组件
    • 13.0动画
      • 16.1常用
      • 16.2StateMachineBehaviour
      • 16.3IK**反向动力学**
        • 1.0头IK
        • 2.0手脚IK
        • 3.0IK位置/旋转调节小技巧
    • 14.0NAV寻路导航
    • 15.0UI
      • 1.0常用组件
      • 2.0虚拟摇杆
      • 3.0虚拟摇杆2
    • 16实用属性(Attribute)
    • 17数据存储
      • 一、PlayerPrefs
      • 二、TextAsset
      • 三、Json
        • json创建
        • json解析
      • 四、XML存储
        • 1.XML的创建
        • 2.XML的写入
          • Character Controller组件写入xml(作业)
        • 3.XML的读取
        • 4.XML的更新
        • 5.XML的删除
    • 18SQLite数据库
      • 软件:SqliteManager
      • SQL语法:
          • **增**
      • 编程实现增删改查
        • 步骤(共9步):
        • 整体代码:
    • 19优化
    • 20协同程序与WWW
    • 21Shader
      • 基础
      • shader:
      • 代码:
  • 进阶

初级

1.0数学

1.0点乘叉乘

1.点乘:

定义:a·b=|a|·|b|cos 【注:粗体小写字母表示向量,表示向量a,b的夹角,取值范围为[0,180]】

注:看到公式,我们即可知道点乘过后得到的是一个标量,而不是一个向量。 而且可以通过这个去计算两个点之间的夹角及方向;

Unity项目中的应用

     1:通过点乘,我们可以计算出两个点之前的前后所属位置,当a·b>0;角度值在0到90度之间,可想而知及b点在a点的前方,反之a·b<0;角度值在90到180度之间,可想而知b点在a点的后方

     2:可以根据点乘计算两个向量之间的夹角;= arccos(a·b / (|a|·|b|))

代码:

`c#
   /// 
    /// 点乘
    /// 
    /// 
    /// 
    private void TestDot(Transform a,Transform b) 
    {
        //一个物体的坐标点也是有方向的  是和原点作为参考系
     Vector3 vecAObj = a.transform.position;
     Vector3 vecBObj = b.transform.position;
    float dotResult = Vector3.Dot(vecAObj.normalized, vecBObj.normalized);
    float radians = Mathf.Acos(dotResult);
  
    float angle = radians * Mathf.Rad2Deg;  //将弧度转化为角度
    Debug.Log("Vector3.Dot两个向量的角度为--------->" + angle);
    Debug.Log("Vector3.Angle两个向量的角度为--------->" + Vector3.Angle(vecAObj, vecBObj));

    Vector3 vecAPoint = a.transform.forward;
    Vector3 vecBPoint = b.transform.position - a.transform.position;
    float dotResult2 = Vector3.Dot(vecAPoint.normalized, vecBPoint.normalized);
    if (dotResult2 > 0)
    {
        Debug.Log("b点在a点的前方-------->");
    }
    else {
        Debug.Log("b点在a点的后方----------->");
    }
    float radians2 = Mathf.Acos(dotResult2);
    float angle2 = radians2 * Mathf.Rad2Deg;
    Debug.Log("该两个点的角度值为---------->" + angle2);
}

Vector3.Dot也叫点积,它返回1个-1.0~1.0之间的一个值,表示返回进行Dot计算的两个向量之间的夹角的余弦值(Cos弧度角).要注意的是能进行Dot计算的前提是两个向量首先要变成单位向量!

Vector3.Cross表示求两个向量的叉积。

弧度的定义

角(弧度)=弧长/半径

圆的周长是半径的2π倍,所以一个周角(360度)是2π弧度。半圆的长度是半径的π倍,所以一个平角(180度)是π弧度

1.正切值与角度的换算

float angel = Mathf.Atan(y/x)*180/π;

2.余弦值与角度的换算

float angel =Mathf.Cos(π/180*constAngel);

2.叉乘:

定义:c = a x b,其中a b c均为向量

几何意义是:得到一个与这两个向量都垂直的向量

性质1:c⊥a,c⊥b,即向量c与向量a,b所在平面垂直

性质2:模长|c| = |a||b| sin

Unity项目中的应用:

1.根据叉乘得到a,b向量的相对位置,和顺时针或逆时针方位。

简单的说: 点乘判断角度,叉乘判断方向。
形象的说: 当一个敌人在你身后的时候,叉乘可以判断你是往左转还是往右转更好的转向敌人,点乘得到你当前的面朝向的方向和你到敌人的方向的所成的角度大小。

  /// 
    /// 叉乘
    /// 
    private void TestCross(Transform a, Transform b) 
    {
        Vector3 vecAobj = a.transform.forward;
        Vector3 vecBObj = b.transform.position - a.transform.position;
        Vector3 crossC = Vector3.Cross(vecAobj.normalized, vecBObj.normalized);
        float radians = Mathf.Asin(Vector3.Distance(Vector3.zero, crossC));
        float angle = radians * Mathf.Rad2Deg;
        Debug.Log("该两个点的角度值为---------->" + angle);
        if (crossC.y > 0)
        {
            Debug.Log("b在A的顺时针方向");
            // 由此可以用来判断我A点是向左转还是右转可以更快的找到B点。
            //此处的顺时针和逆时针是指更快的速度找到对应点。 琢磨下 应该就清楚这里指什么意思了
        }
        else {
            Debug.Log("b在A的逆时针方向");
        }
    }

2.0Mathf

Mathf.Abs绝对值

计算并返回指定参数 f 绝对值。

Mathf.Acos反余弦

static function Acos (f : float) : float

就是arccosX值域[0,л], 定义域[-1,1]

*如cos(a) = b,则arccos(b) = a;*

arccosX : [-1,1] -> [0,л]

以弧度为单位计算并返回参数 f 中指定的数字的反余弦值。

得到的是弧度,不是度。

Mathf.Approximately近似

static function Approximately (a : float, b: float) : bool

比较两个浮点数值,看它们是否非常接近, 由于浮点数值不精确,不建议使用等于来比较它们。例如,1.0==10.0/10.0也许不会返回true。

public class example : MonoBehaviour {
            publicvoid Awake() {
               if(Mathf.Approximately(1.0F, 10.0F / 10.0F))
            print("same");
      }
}

Mathf.Asin反正弦

static function Asin (f : float) : float

以弧度为单位计算并返回参数 f 中指定的数字的反正弦值。

Mathf.Atan2反正切

static function Atan2 (y : float, x :float) : float

以弧度为单位计算并返回 y/x 的反正切值。返回值表示相对直角三角形对角的角,其中 x 是临边边长,而 y 是对边边长。

返回值是在x轴和一个二维向量开始于0个结束在(x,y)处之间的角。

public class example : MonoBehaviour {
            publicTransform target;    
   voidUpdate() {
         Vector3 relative = transform.InverseTransformPoint(target.position);
         floatangle = Mathf.Atan2(relative.x, relative.z) * Mathf.Rad2Deg;
         transform.Rotate(0,angle, 0);
   }
}

Mathf.Atan反正切

static function Atan (f : float) :float

计算并返回参数 f 中指定的数字的反正切值。返回值介于负二分之 pi 与正二分之 pi 之间。

Mathf.CeilToInt最小整数

static function CeilToInt (f : float) : int

返回最小的整数大于或等于f。

Mathf.Ceil上限值

static function Ceil (f : float) : float

返回 f 指定数字或表达式的上限值。数字的上限值是大于等于该数字的最接近的整数。

Mathf.Clamp01限制0~1

static function Clamp01 (value : float) :float

限制value在0,1之间并返回value。如果value小于0,返回0。如果value大于1,返回1,否则返回value 。

Mathf.Clamp限制

static function Clamp (value : float, min :float, max : float) : float

限制value的值在min和max之间, 如果value小于min,返回min。 如果value大于max,返回max,否则返回value

static function Clamp (value : int, min :int, max : int) : int

限制value的值在min和max之间,并返回value。

Mathf.ClosestPowerOfTwo最近的二次方

static function ClosestPowerOfTwo (value :int) : int

返回距离value最近的2的次方数。

Mathf.Cos余弦

static function Cos (f : float) : float

返回由参数 f 指定的角的余弦值(介于 -1.0 与 1.0 之间的值)。

Mathf.Deg2Rad度转弧度(degree度)

static var Deg2Rad : float

度到弧度的转化常量。(只读)

这等于(PI * 2) / 360。

弧度的定义

角(弧度)=弧长/半径

圆的周长是半径的2π倍,所以一个周角(360度)是2π弧度。半圆的长度是半径的π倍,所以一个平角(180度)是π弧度

Mathf.Rad2Deg 弧度转度

static var Rad2Deg : float

弧度到度的转化常量。(只读)

这等于 360 / (PI * 2)。

Mathf.DeltaAngle增量角

static function DeltaAngle (current :float, target : float) : float

计算给定的两个角之间最短的差异。

// Prints 90

Debug.Log(Mathf.DeltaAngle(1080,90));

Mathf.Epsilon小正数

static var Epsilon : float

一个很小的浮点数值。(只读)

最小的浮点值,不同于0。

以下规则:

  • anyValue + Epsilon = anyValue

  • anyValue - Epsilon = anyValue

  • 0 + Epsilon = Epsilon

  • 0 - Epsilon = -Epsilon

一个在任意数和Epsilon的之间值将导致在任意数发生截断误差。

public class example : MonoBehaviour {
 boolisEqual(float a, float b) {   
        if(a >= b - Mathf.Epsilon && a <= b + Mathf.Epsilon)                                        return true;
        else
           return false;
     }
}

Mathf.Exp指数

static function Exp (power : float) : float

返回 e 的 power 次方的值。

Mathf.FloorToInt最大整数

static function FloorToInt (f : float) :int

返回最大的整数,小于或等于f。

Mathf.Floor下限值

static function Floor (f : float) : float

返回参数 f 中指定的数字或表达式的下限值。下限值是小于等于指定数字或表达式的最接近的整数。

Mathf.Infinity正无穷

static var Infinity : float

表示正无穷,也就是无穷大,∞ (只读)

Mathf.InverseLerp反插值

计算两个值之间的Lerp参数。也就是value在from和to之间的比例值。

//现在参数是3/5

float parameter =Mathf.InverseLerp(walkSpeed, runSpeed, speed);

Mathf.IsPowerOfTwo是否2的幂

static function IsPowerOfTwo (value : int): bool

如果该值是2的幂,返回true。

// prints false

Debug.Log(Mathf.IsPowerOfTwo(7));

// prints true

Debug.Log(Mathf.IsPowerOfTwo(32));

Mathf.LerpAngle插值角度

static function LerpAngle (a : float, b :float, t : float) : float

和Lerp的原理一样,当他们环绕360度确保插值正确。

a和b是代表度数。

public class example : MonoBehaviour {
   publicfloat minAngle = 0.0F;
   publicfloat maxAngle = 90.0F;
 void Update() {
 floatangle = Mathf.LerpAngle(minAngle, maxAngle, Time.time);
 transform.eulerAngles= new Vector3(0, angle, 0);    
   }
}

Mathf.Lerp插值

static function Lerp (from : float, to :float, t : float) : float

基于浮点数t返回a到b之间的插值,t限制在0~1之间。

当t = 0返回from,当t = 1 返回to。当t = 0.5 返回from和to的平均值。

Mathf.Log10基数10的对数

static function Log10 (f : float) : float

返回f的对数,基数为10。

Mathf.Log对数

static function Log (f : float, p : float): float

返回参数 f 的对数。

// logarithm of 6 in base 2

//以2为底6的对数

// prints 2.584963

print(Mathf.Log(6, 2));

Mathf.Max最大值

static function Max (a : float, b : float): float

static function Max (params values :float[]) : float

返回两个或更多值中最大的值。

Mathf.Min最小值

static function Min (a : float, b : float): float

static function Min (params values :float[]) : float

返回两个或更多值中最小的值。

Mathf.MoveTowardsAngle移动角

static function MoveTowardsAngle (current :float, target : float, maxDelta : float) : float

像MoveTowards,但是当它们环绕360度确保插值正确。

变量current和target是作为度数。为优化原因,maxDelta负值的不被支持,可能引起振荡。从target角推开current,添加180度角代替。

Mathf.MoveTowards移向

static function MoveTowards (current :float, target : float, maxDelta : float) : float

改变一个当前值向目标值靠近。

这实际上和 Mathf.Lerp相同,而是该函数将确保我们的速度不会超过maxDelta。maxDelta为负值将目标从推离。

Mathf.NegativeInfinity负无穷

static var NegativeInfinity : float

表示负无穷,也就是无穷小,-∞(只读)

Mathf.NextPowerOfTwo下个2的幂

Mathf.PingPong乒乓

static function PingPong (t : float, length: float) : float

0到length之间往返。t值永远不会大于length的值,也永远不会小于0。

The returned value will move back and forthbetween 0 and length.

返回值将在0和length之间来回移动。

Mathf.PI圆周率

static var PI : float

PI(读pai)的值,也就是圆周率(π)的值3.14159265358979323846…(只读)

Mathf.Pow次方

static function Pow (f : float, p : float): float

计算并返回 f 的 p 次方。

Mathf.Repeat重复

static function Repeat (t : float, length :float) : float

循环数值t,0到length之间。t值永远不会大于length的值,也永远不会小于0。

这是类似于模运算符,但可以使用浮点数。

public class example : MonoBehaviour {
void Update() {   
transform.position= new Vector3(Mathf.Repeat(Time.time,3),transform.position.y,transform.position.z);
    
            }

}

Mathf.RoundToInt四舍五入到整数

static function RoundToInt (f : float) :int

返回 f 指定的值四舍五入到最近的整数。

如果数字末尾是.5,因此它是在两个整数中间,不管是偶数或是奇数,将返回偶数。

Mathf.Round四舍五入

static function Round (f : float) : float

返回浮点数 f 进行四舍五入最接近的整数。

如果数字末尾是.5,因此它是在两个整数中间,不管是偶数或是奇数,将返回偶数。

Mathf.Sign符号

static function Sign (f : float) : float

返回 f 的符号。

当 f 为正或为0返回1,为负返回-1。

Mathf.Sin正弦

static function Sin (f : float) : float

计算并返回以弧度为单位指定的角 f 的正弦值。

Mathf.SmoothDampAngle平滑阻尼角度

static function SmoothDampAngle (current :float, target : float, ref currentVelocity : float, smoothTime : float,maxSpeed : float = Mathf.Infinity, deltaTime : float = Time.deltaTime) : float

参数

current

当前的位置。

target

我们试图达到的位置。

currentVelocity

当前速度,这个值在你访问这个函数的时候会被随时修改。

smoothTime

the target faster.

要到达目标位置的近似时间,实际到达目标时要快一些。

maxSpeed

可选参数,允许你限制的最大速度。

deltaTime

上次调用该函数到现在的时间。缺省为Time.deltaTime。

随着时间的推移逐渐改变一个给定的角度到期望的角度。

这个值通过一些弹簧减震器类似的功能被平滑。这个函数可以用来平滑任何一种值,位置,颜色,标量。最常见的是平滑一个跟随摄像机。

//一个简单的平滑跟随摄像机

//跟随目标的朝向

public class example : MonoBehaviour {
    
            publicTransform target;
            publicfloat smooth = 0.3F;
            publicfloat distance = 5.0F;
            privatefloat yVelocity = 0.0F; 
            
void Update(){
//从目前的y角度变换到目标y角度
floatyAngle = Mathf.SmoothDampAngle(transform.eulerAngles.y, target.eulerAngles.y,ref yVelocity, smooth);
//target的位置
             Vector3position = target.position;
//然后,新角度之后的距离偏移
             position+= Quaternion.Euler(0, yAngle, 0) * new Vector3(0, 0, -distance);
//应用位置
             transform.position= position;
//看向目标
             transform.LookAt(target);

     }

}

Mathf.SmoothDamp平滑阻尼

static function SmoothDamp (current :float, target : float, ref currentVelocity : float, smoothTime : float,maxSpeed : float = Mathf.Infinity, deltaTime : float = Time.deltaTime) : float

参数

current

当前的位置。

target

我们试图达到的位置。

currentVelocity

当前速度,这个值在你访问这个函数的时候会被随时修改。

smoothTime

要到达目标位置的近似时间,实际到达目标时要快一些。

maxSpeed

可选参数,允许你限制的最大速度。

deltaTime

上次调用该函数到现在的时间。缺省为Time.deltaTime。

描述

随着时间的推移逐渐改变一个值到期望值。

这个值就像被一个不会崩溃的弹簧减振器一样被平滑。这个函数可以用来平滑任何类型的值,位置,颜色,标量。

public class example : MonoBehaviour {

            publicTransform target;   
            publicfloat smoothTime = 0.3F;   
            privatefloat yVelocity = 0.0F;
    
            voidUpdate() {
            
floatnewPosition = 
Mathf.SmoothDamp(transform.position.y, target.position.y,refyVelocity, smoothTime);
    
transform.position= new Vector3(transform.position.x, newPosition, transform.position.z);   
    }
}

Mathf.SmoothStep平滑插值

static function SmoothStep (from : float,to : float, t : float) : float

和lerp类似,在最小和最大值之间的插值,并在限制处渐入渐出。

public class example : MonoBehaviour {

            publicfloat minimum = 10.0F;
            publicfloat maximum = 20.0F;
  void Update() {
transform.position= new Vector3(Mathf.SmoothStep(minimum, maximum, Time.time), 0, 0);       }
}

Mathf.Sqrt平方根

static function Sqrt (f : float) : float

计算并返回 f 的平方根。

Mathf.Tan正切

static function Tan (f : float) : float

计算并返回以弧度为单位 f 指定角度的正切值。

3.0Vector

Vector3是结构体,里面有三个变量x,y,z。可以代表向量,坐标,旋转,缩放

Vector3 v=new Vector3(1,1,1);//创建结构体

v=Vector3.zero;//创建结构体

v=Vector3.one;//创建结构体

v.x=0;//修改结构体

Debug.Log(Vector3.Angle(v,v2));//计算两个向量夹角

Debug.Log(Vector3.Distance(v,v2));//计算两个点距离

Debug.Log(Vector3.Dot(v,v2));//计算点乘

Debug.Log(Vector3.Cross(v,v2));//计算叉乘

Debug.Log(Vector3.Lerp(Vector3.zero,Vector3.one,0.5f));//插值 结果是0.5,0.5,0.5

Debug.Log(Vector3.Lerp(Vector3.zero,Vector3.one,0.8f));//插值 结果是0.8,0.8,0.8

//插值就是在两个向量里面做了比例计算

Debug.Log(v.mangnitude);//模

Debug.Log(v.normalized);//单位向量

//向量转换为四元数
Quaternion Qua = Quaternion.LookRotation(new(Vector3(horizontal, 0 , vertical)));
//lerp过去
Transform.Rotation = Quaternion.Lerp(Transform.Rotation , Qua , Time.DeltaTime * TurnSpeed);

4.0旋转

Quaternion(四元数),在unity中用于角度的旋转。

Euler函数:返回一个旋转角度,绕z轴旋转z度,绕x轴旋转x度,绕y轴旋转y度(像这样的顺序)。

Quaternion.Euler(new Vector3(0,90,0))表示绕y轴旋转90度

Quaternion.Euler(new Vector3(90,90,90))表示绕xyz轴各旋转90度

1.我们让transform的y轴旋转90度如下

transform.rotation = Quaternion.Euler(new Vector3(0,90,0));

2.Quaternion*Vector3的意思是让Vector3向量旋转了Quaternion度

//旋转:欧拉角,四元数
Vector3 rotate = new Vector3(0, 30,0);
Quaternion quaternion =Quaternion.identity; 

quaternion = quaternion.Euler(rotate); //角转为四元数

otate = quaternion.eulerAngles; //数转为欧拉角

quaternion =Quaternion.LookRotation(new Vector3(0,0,0)); //看向一个物体

2.0组件

public GameObject Cube;
void start{
//拿到当前脚本所挂载的游戏物体//
GameObject go=this.gameObject; 
//名称
Debug.Log(gameObject.name);
//tag
Debug.Log(gameObject.tag); 
//layer
Debug.Log(gameObject.layer); 
//立方体的名称
Debug.Log(Cube.name); 
//当前真正的激活状态
Debug.Log(Cube.activelnHierarchy); 
//当前自身激活状态
Debug.Log(Cube.activeSelf);
//获取Transform组件
Transform trans = this.transform; Debug.Log(transform.position);
//获取其他组件
BoxCollider bc = GetComponent<BoxCollider>(; 
//获取当前物体的子物体身上的某个组件
GetComponentlnChildren<CapsuleCollider>(bc); 
//获取当前物体的父物体身上的某个组件
GetComponentlnParent<BoxCollider>(); 
//添加一个组件
gameObject.AddComponent<AudioSource>();
                                           
GameObject test = GameObject.Find("Test"); 
                                           
//通过游戏标签来获取游戏物体
test=GameObject.FindWithTag("Enemy"); test.SetActive(false);

Debug.Log(test.name);

//通过预设体来实例化一个游戏物体
GameObject go=Instantiate(Prefab,Vector3.zero,Quaternion.identity); 
//销毁
Destroy(go);
}

3.0调试Debog

void Start(){

Debug.Log("test");

Debug.LogWarning("testDebog2");

Debug.LogError("test3");
}

void Update() {

//绘制一条线 起点,终点
Debug.DrawLine(new Vector3(1, 0, 0), new Vector3(1, 1,0),Color.blue);

//绘制一条射线起点,射线
Debug.DrawRay(new Vector3(1,0, 0), new Vector3(1,1,0),Color.red); 
}

4.0时间

void Start(

{
Debug.Log(Time.time);//游戏开始到现在所花的时间

Debug.Log(Time.timeScale); //时间缩放值

Debug.Log(Time.fixedDeltaTime); //固定时间间隔
}

//60帧1/60 120 1/120Unity

void Update() }

timer +=Time.deltaTime;//上一帧到这一帧所用的游戏时间

Debug.Log(Time.deltaTime); 

if(timer>3){//如果大于3秒

Debug.Log("大于3秒了"); }

} 

5.0Application

数据库会使用

void Start()

{

//游戏数据文件夹路径(只读,加密压缩)
//当前工程下的Asses文件夹,仅限编辑器使用,导出后不可用
Debug.Log(Application.dataPath+"/新建文本文档.txt"); 

//持久化文件夹路径,各个平台都可用,手游
Debug.Log(Application.persistentDataPath); 

//StreamingAssets文件夹路径(只读,配置文件) 要创建文件,流路径,各个平台都可以,一般编译器下使用
Debug.Log(Application.streamingAssetsPath); 

//临时文件夹
Debug.Log(Application.temporaryCachePath); 

//控制是否在后台运行
Debug.Log(Application.runlnBackground); 

//打开url
Application.OpenURL("https://space.bilibili.com/67744423"); 

//退出游戏
Application.Quit(); 
    
//截屏
ScreenCapture.CaptureScreenshot("Assets/Pic");

//Assets文件夹
Debug.Log(Application.DatePath);

   
}


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-46dZ21g6-1673715707029)(D:\Study\Unity\图片\Application2.png)]

6.0场景

1.0两个类
1.2场景类
using UnityEngine.SceneManagement;
public class SceneTest:MonoBehaviour
void Start({
//两个类,场景类,场景管理类
//场景跳转
SceneManager.LoadScene("MyScene");
//获取当前场景
Scene scene = SceneManager.GetActiveScene();
//场景名称
Debug.Log(scene.name);
//场景是否已经加载
Debug.Log(scene.isLoaded);
//场景路径
Debug.Log(scene.path);
//场景索引
Debug.Log(scene.buildIndex);
GameObject[]gos = scene.GetRootGameObjects();
Debug.Log(gos.Length);
}

千锋Unity学习笔记_第1张图片

1.2场景管理类
//场景管理类
//创建新场景
Scene newScene = SceneManager.CreateScene("newScene");
UnityEngine.SceneManagement.Scene newscene = SceneManager.CreateScene("newscene");
//已加载场景个数
Debug.Log(SceneManager.sceneCount);
//卸载场景
SceneManager.UnloadSceneAsync(newScene);
//加载场景
//在当前场景添加MyScene
SceneManager.LoadScene("MyScene",LoadSceneMode.Additive);
//关闭当前场景,加载MyScene
SceneManager.LoadScene("MyScene",LoadSceneMode.Single);
2.0异步加载
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class IeScene : MonoBehaviour
{
AsyncOperation Operation;

IEnumerator loadscene()协程
{
    Operation = SceneManager.LoadSceneAsync("NewScene");//协程方法用来异步加载场景
    Operation.allowSceneActivation = false;//加载完场景不要自动跳转
    yield return Operation;
}
void Update()
{
    if (Input.GetKeyDown(KeyCode.A))
    {
        StartCoroutine(loadscene());//按下A开始加载
    }
    if (Input.GetKeyDown(KeyCode.Space))//按下空格场景跳转
    {
        Operation.allowSceneActivation = true;
    }
    Debug.Log(Operation.progress);//输出加载进度0-0.9
 }
}

7.0Transform

//获取位置
Debug.Log(transform.position);
Debug.Log(transform.localPosition);
//获取旋转
Debug.Log(transform.rotation);
Debug.Log(transform.localRotation);
Debug.Log(transform.eulerAngles);
Debug.Log(transform.localEulerAngles);
//获取缩放
Debug.Log(transform.localScale);
//向量
Debug.Log(transform.forward);
Debug.Log(transform.right);
Debug.Log(transform.up);

//父子关系
//获取父物体
transform.parent.gameObject
//子物体个数
//Debug.Log(transform.childCount);
//解除与子物体的父子关系
transform.DetachChildren(;
//获取子物体
Transform trans transform.Find("Child");
trans transform.GetChild(0);
//判断一个物体是不是另外一个物体的子物体
bool res trans.IsChildof(transform);
Debug.Log(res);
//设置为父物体
trans.SetParent(transform);

void Update() {
//时时刻刻看向000点
transform.LookAt(Vector3.zero);
//旋转
transform.Rotate(Vector3.up,1); 
//绕某个物体旋转
transform.RotateAround(Vector3.zero,Vector3.up,speed) 
//移动
transform.Translate(Vector3.forward * speed);
}                         

8.0按键Input

1.点击
void Update0{
//鼠标的点击
//按下鼠标0左键1右键2滚轮
if (lnput.GetMouseButtonDown(O)) {:Debug.Log("按下了鼠标左键");}
//持续按下鼠标
if (lnput.GetMouseButton(o))
Debug.Log("持续按下鼠标左键");
//抬起鼠标
if (lnput.GetMouseButtonUp(O)){Debug.Log("抬起了鼠标左键");
//按下键盘按键
if (lnput.GetKeyDown(KeyCode.A))
Debug.Log("按下了A");
//持续按下按键
if (Input.GetKey(KeyCode.A))
Debug.Log("持续按下A");}
//抬起键盘按键
// "a" 跟 KeyCode.A 一样
if (lnput.GetKeyUp("a")){
Debug.Log("松开了A");
    
}

抬起事件:Input.GetMouseButtonUp()

void Update()
    {
        if (Input.GetMouseButtonUp(0))
        {
            print("鼠标左键抬起!");
        }
        if (Input.GetMouseButtonUp(1))
        {
            print("鼠标右键抬起!");
        }
        if (Input.GetMouseButtonUp(2))
        {
            print("鼠标中键抬起!");
        }
        if (Input.GetMouseButtonUp(3))
        {
            print("鼠标侧键抬起!");
        }
    }
    
    

长按事件:Input.GetMouseButton()

private float timer = 0;

    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            timer += Time.deltaTime;
        }
        else if (Input.GetMouseButtonUp(0) && timer != 0)
        {
            print("鼠标左键长按" + timer + "秒!");
            timer = 0;
        }
        if (Input.GetMouseButton(1))
        {
            timer += Time.deltaTime;
        }
        else if (Input.GetMouseButtonUp(1) && timer != 0)
        {
            print("鼠标右键长按" + timer + "秒!");
            timer = 0;
        }
    }

GetButtonDown的用法:
\1. 通过 Edit-Project settings-Input打开InputManager
\2. 设置图片中四项中的任意一项或多项,设置内容如下:

千锋Unity学习笔记_第2张图片

数字(代表键盘上的数字键),字母(代表键盘上的字母),
mouse 0(鼠标左键),![QQ截图20221201235305](…/MDPicture/QQ截图20221201235305.png
mouse 1(鼠标右键),
mouse 2(代表鼠标中键),除上面提到的几种以外
\3. 注意Type项,选择Key or Mouse Button项

备注:其它的输入均会被认为是错误输入,unity软件会自动清空

个人比较习惯:如果使用键盘输入使用Input.GetKeyDown(KeyCode.K) 和如果使用鼠标输入使用Input.GetMouseButtonDown(0)​,原因是这两种比较直接,一眼就可以看出是键盘输入还是鼠标输入,不像input.getbuttondown(“”)还需要到InputManager中去设置

Input.getButtonDown兼有Input.GetKeyDown(0)和Input.getMouseButtonDown(0)两种功能,就是使用的时候有点绕,需要到InputManger设置

2.水平轴虚拟按键

手动设置的按键

void update() 
{
//获取水平轴 -1.0 ~ 1.0
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Debug.Log(horizontal + "" +vertical);*/
//虚拟按键
if (Input.GetButtonDown("Jump"))
{
Debug.Log("按下空格");
}
if (Input.GetButton(" Jump"))
{
Debug.Log("持续按空格");
}
if (lnput.GetButtonUp(" Jump"))
{
Debug.Log("抬起空格");
}
}
3.触屏
void Start()
{
//开启多点触摸
lnput.multiTouchEnabled = true;
}

void Update()
//判断单点触摸
if (Input.touchCount == 1){
//触摸对象
Touch touch = Input.touches[0];
//触摸位置
Debug.Log(touch.position);
//触摸阶段
switch (touch.phase)
case TouchPhase.Began:break;
case TouchPhase.Moved:
break;
case TouchPhase.Stationary:
break;
case TouchPhase.Ended:
break;
case TouchPhase.Canceled:
break;

//判断多点触摸
if (Input.touchCount == 2){
Touch touch = lnput.touches[0];Touch touch1  lnput.touches[1];
}
}

9.0音效视频

1.音频

暂停和停止播放不一样哦;

暂停后继续播放;停止和开始播放;

void Update()
{
//按空格切换声音的播放和暂停
if (Input.GetKeyDown(KeyCode.Space))
   {
 //如果当前正在播放声音
     if (player.isPlaying)
       {
         //暂停
         player.Pause();
         //停止
         player.Stop();
       } 
      else{          
       //继续
       //player.UnPause();
       //开始播放
       player.Play();
        }
    }
}

2.视频

using UnityEngine.Video;//要引用

public class VideoTest : MonoBehaviour
{
  private VideoPlayer player; 

  void Start()
  {
  player = GetComponent<VideoPlayer>(); 
  }
  void Update0
  {
    if (Input.GetMouseButtonDown(0))
      {
        player.Paluse();
       }
   }
}

10.0移动

1.0移动

private CharacterController characterController;
    float horizontal;
    float vertical;
    // Start is called before the first frame update
    void Start()
    {
        characterController = GetComponent<CharacterController>();
    }

// Update is called once per frame
void Update()
{
    horizontal = Input.GetAxis("Horizontal");
    vertical = Input.GetAxis("Vertical");
    Vector3 dir = new Vector3(horizontal, 0, vertical);//获取移动方向
    Debug.DrawRay(transform.position,dir,Color.red);
    characterController.SimpleMove(dir);//受重力影响
    characterController.Move(dir);//不受中力影响
}
void Update0
{
    //水平轴
    float horizontal = Input.GetAxis("Horizontal");
    //垂直轴
    float vertical = Input.GetAxis("Vertical");
    //向量
    Vector3 dir = new Vector3(horizontal, 0, vertical);
    //当用户按下了方向键
    if (dir != Vector3.zero)
    {
    //面向向量
    transform.rotation = Quaternion.LookRotation(dir);
    //播放跑步动画
    animator.SetBool("IsRun", true);
    //朝向前方移动
    transform.Translate(Vector3.forward* 2 * Time.deltaTime);//Vector3.forward
    } 
    else
    {
    //播放站立动画
    animator. SetBool("IsRun", false);
    }
}

2.0**Vector.forward **和 transform.foward的区别

(34条消息) Unity3d vector3.forward和transform.forward的区别!_卡鲁洛斯的博客-CSDN博客_unity transform.forward

transform.position 本身就是世界坐标。

1、transform.position+= vector3.forward

等于是在世界坐标的z轴前进。

2、transform.position+=transform.forward

等于是物体自身坐标系的z轴前进。

3、transform.translate(vector3.forward,space.self)

等于是自身坐标系的z轴前进。

效果等同于2。

4、transform.translate(transform.forward,space.self)

上面出现的奇葩结果就是这个用法引起的,建议不是特殊需要别用这个用法。

5、transform.translate(vector3.forward,space.world)

等于是让物体沿着世界坐标的z轴前进。

效果等同于1。

6、transform.translate(transform.forward,space.world)

等于是让物体沿着“物体自身坐标z轴在世界坐标上的方向”前进(等同与物体沿着自身z轴前进)。

效果等同于2。

11.0射线

unity射线使用方法详解_学习使我快乐13的博客-CSDN博客_unity 射线

void Start()
{
//方式1
Ray ray = new Ray(Vector3.zero, Vector3.up);
}

void Update(){
    if (Input.GetMouseButtonDown(0))
    {
      //按下鼠标左键发射射线
      Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
      //声明一个碰撞信息类
      RaycastHit hit;
      //碰撞检测
      bool res = Physics.Raycast(ray, out hit);
      //如果碰撞到的情况下,hit就有内容了
      if (res == true)
      {
      Debug.Log(hit.point);
      transform.position = hit.point;
      }
      //多检测
      RaycastHit hits = Physics.RaycastAll(ray, 100, 1<<10);
    }
}

12.0画线

1.Line Renderer组件

2.trail Renderer组件

制作拖尾特效;

千锋Unity学习笔记_第3张图片

13.0动画

16.1常用

private void update()
{
//动画参数名称可以转换为一个ID【int】
int id = Animator.StringToHash( "CanMove" ) ;
Debug.Log ( "ID : " +id) ;
//设置或读取动画参数
ani.SetBool( "CanMove" , true) ;
//【使用HashD进行参数的设置或读取,效率更高】
ani.SetBool( id, true);
// ani.SetFloat() 
//ani.GetFloat()
// ani.SetInteger()
// ani.GetInteger()
// ani.SetTrigger()【触发参数】无get
bool isTrans = ani.IsINTransion(0)//是否过渡状态
bool isFire =  ani.GetCurrentAnimatorStsteIn(0).IsName("Fire");//获取当前动画状态,是不是fire 
//按下方向键左键
if( input.GetKeyDown (KeyCode. LeftArrow))
{

}

16.2StateMachineBehaviour

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DyingState : StateMachineBehaviour
{
    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
       //进入当前状态的时候调用一次 
    }

    // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        //当前状态的时候每帧执行一次 
    }

    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        //离开当前状态的时候调用一次 
    }

    // OnStateMove is called right after Animator.OnAnimatorMove()
    override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // Implement code that processes and affects root motion
        //移动的时候调用,烘焙到姿势
    }

    // OnStateIK is called right after Animator.OnAnimatorIK()
    //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that sets up animation IK (inverse kinematics)
    //}
}

16.3IK反向动力学

(47条消息) Unity动画系统详解8:IK是什么?_大智_洪流学堂的博客-CSDN博客

Unity中IK能设置的部位就是5个,分别是:头、左右手、左右脚。

1.0头IK
public void SetLookAtPosition(Vector3 lookAtPosition);
public void SetLookAtWeight(float weight, 
                            float bodyWeight = 0.0f,
                            float headWeight = 1.0f, 
                            float eyesWeight = 0.0f, 
                            float clampWeight = 0.5f);
//设置IK的权重,这个IK会和原来的动画进行混合。如果权重为1,则完全用IK的位置旋转;如果权重为0,则完全用原来动画中的位置和旋转。**至少要设置第一个参数,后面的几个参数都有默认值,但是你也要了解所有参数的含义:
//Weight 全局权重,后面所有参数的系数
//bodyWeight 身体权重,身体参与LookAt的程度,一般是0
//headWeight 头部权重,头部参与LookAt的权重,一般是1
//eyesWeight 眼睛权重,眼睛参与LookAt的权重,一般是0(一般没有眼睛部分的骨骼)
//clampWeight 权重的限制。0代表没有限制(脖子可能看起来和断了一样),1代表完全限制(头几乎不会动,像是固定住了)。0.5代表可能范围的一半(180度)

设置IK的权重,这个IK会和原来的动画进行混合。如果权重为1,则完全用IK的位置旋转;如果权重为0,则完全用原来动画中的位置和旋转。**至少要设置第一个参数,后面的几个参数都有默认值

1、需要勾选对应Layer的IK Pass选项(在Layer的设置里)。
2、代码需要写在OnAnimatorIK这个事件方法里面。

void OnAnimatorIK(int layerIndex)
{
    _animator.SetLookAtPosition(pos);
    _animator.SetLookAtWeight(1);
}
2.0手脚IK
public void SetIKPosition(AvatarIKGoal goal, Vector3 goalPosition);
public void SetIKRotation(AvatarIKGoal goal, Quaternion goalRotation);

goal AvatarIKGoal枚举类型,包含:

  • LeftFoot 左脚
  • RightFoot 右脚
  • LeftHand 左手
  • RightHand 右手

goalPosition/goalRotation IK目标位置/旋转

同样还有设置权重的API:

public void SetIKPositionWeight(AvatarIKGoal goal, float value);
public void SetIKRotationWeight(AvatarIKGoal goal, float value);

常见的设置手部IK的代码是(一般需要4行代码设置一个部位):

void OnAnimatorIK(int layerIndex)
{
    _animator.SetIKPosition(AvatarIKGoal.LeftHand, position);
    _animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, 1);

    _animator.SetIKRotation(AvatarIKGoal.LeftHand, rotation);
    _animator.SetIKRotationWeight(AvatarIKGoal.LeftHand, 1);
}

3.0IK位置/旋转调节小技巧

设置两个参照物,作为IK的位置和旋转的参考,这样只需要调这两个参照物

运行时调整这个参考位置,调到一个完美的位置和角度,按如下方法保存。

  • 在Inspector的Transform的右上角,点击齿轮小图标,选择Copy Component Values
  • 退出Play模式
  • 在Inspector的Transform的右上角,点击齿轮小图标,选择Paste Component Values

14.0NAV寻路导航

(47条消息) unity 导航_LinQY_lucky的博客-CSDN博客_unity导航

选中要导航的区域,调整为Navigation Static,然后window -> AI -> Navigation开始烘培,在要寻路的物体添加

Nav Mash Agent 组件,开始导航;

using UnityEngine.Al;//AI

public class PlayerControl : MonoBehaviour
private NavMeshAgent agent;

void Start()
{
//获取代理组件
agent = GetComponent<NavMeshAgent>0);
}
void Update()
{
//如果按下鼠标
if (lnput.GetMouseButtonDown(O))
  {
  //获取点击位置
  Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
  RaycastHit hit;
  if (Physics.Raycast(ray, out hit))
    {
      //点击位置
      Vector3 point = hit.point;
      //设置该位置为导航目标点
      agent.SetDestination(point);
    }
  }
}

Nav Mesh Obstacle组件

导航网格上的障碍物,动态的障碍物

给物体直接添加该组件即可;

Off Mesh Link组件

在任意两点间,设置跨越移动,

或者选中两物体 ,勾选Generate OffMeshLinks(生成脱机链接),设置好Jump Distance可在两点跳跃,

选中一个物体,设置好Drop Distance可从高往下跳跃.

可以代码调节能导航的层

Nav Mash Agent 组件中;

//可以代码调节能导航的层
nav.areaMask = -1;//全选
nav.areaMask = 1;//第0层
nav.areaMask = 2;//第1层
nav.areaMask = 4;//第2层
nav.areaMask = 6;//第2+1层
nav.areaMask = 7;//第2+1+0层
nav.areaMask = 100;//第4层,100 = 64+32+4;只有4满足

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IClHw1Zd-1673715707031)(…/MDPicture/nav.jpg)]千锋Unity学习笔记_第4张图片

15.0UI

UI文档:UGUI六大组件概述

1.0常用组件

在画布下添加面板Panel 将调整 Panel 的锚点,将其他ui放在该Panel下,当屏幕变化时,ui会相对移动。

Mask组件:遮罩,父物体添加后,子物体只能在父物体的范围下显示。

Content Size Fitted组件,根据字体多少,自动适配框的大小。

Vertical Layout Group组件,

Horizontal Layout Group组件,

Grid Layout Group组件,在父物体添加,用来调整子物体的布局。

Layout Element组件 ,可以取消布局,在子物体中自由拖动

2.0虚拟摇杆

(35条消息) unity虚拟摇杆控制的实现_静风闲云的博客-CSDN博客_unity 虚拟摇杆

一、前言

手机游戏,经常会用到摇杆来控制角色,本文记录了如何在unity中用比较简单的方法制作摇杆,并且实现摇杆控制角色左右移动。

二、需要继承的类

ScrollRect(滚动类,一般用于实现UI的拖拽滚动,包含在UnityEngine.UI中)
IPointerDownHandler(指针按下类,实现接口检测指针是否按下,包含在UnityEngine.EventSystems中)
IPointerUpHandler(指针抬起类,实现接口检测指针是否抬起,需要和IPointerDownHandler的接口一起实现才会发挥作用,包含在UnityEngine.EventSystems中)
三、虚拟摇杆的制作

需要图片:

虚拟摇杆的背景图
摇杆图
canvas中新建一个image对象,把虚拟摇杆的背景图放上去,在该对象中新建一个子image作为摇杆,把摇杆图放上去,调整好大小和位置即可。

四、摇杆控制角色移动

新建一个脚本Stick,输入以下代码,挂载到摇杆背景上,并把摇杆对象拖到脚本的content处。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;


public class Stick : ScrollRect, IPointerUpHandler, IPointerDownHandler
{
    protected float mRadius = 0f;//摇杆范围半径
    static public Vector3 cont;//摇杆的偏移量
    protected override void Start()
    {
        base.Start();//原start方法

        //计算摇杆范围半径
        mRadius = (transform as RectTransform).sizeDelta.x * 0.45f;
    }

    public override void OnDrag(PointerEventData eventData)
    {
        base.OnDrag(eventData);//原onDrag方法

        //摇杆位置
        var contentPosition = content.anchoredPosition;

        //将摇杆的偏移量装换为Vector3,且为静态的,
        cont = new Vector3(contentPosition.x, 0,contentPosition.y);


        //如果摇杆位置超出范围,则限制在范围内
        if (contentPosition.magnitude > mRadius)
        {
            contentPosition = contentPosition.normalized * mRadius;
            SetContentAnchoredPosition(contentPosition);
        }
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        //这个接口需要实现用来检测指针是否点击,什么都不写也行,有就ok
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        //在此写控制角色停止移动逻辑
        cont = Vector3.zero;
    }
}

3.0虚拟摇杆2

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class JoyStick : MonoBehaviour,IBeginDragHandler,IDragHandler, IEndDragHandler
{
    [Header("摇杆移动半径")]
    public float MaxDrag;
    private  float distance;

    private Vector3 direction;
    //private Vector3 moveDirection;
    private Vector3 Origin;
    private void Start()
    {
        Origin = transform.position;
    }
    public void OnBeginDrag(PointerEventData eventData)
    {
       // throw new System.NotImplementedException();
    }
    
    public void OnDrag(PointerEventData eventData)
    {
        distance = Vector2.Distance(Origin,Input.mousePosition);
        direction = (Input.mousePosition - Origin).normalized;
       
        //throw new System.NotImplementedException();
        if (distance < MaxDrag)
        {
            transform.position = Input.mousePosition;
        }
    
        else
        {
          Vector3 newdirection = direction * MaxDrag;
            transform.position = Origin + newdirection; 
        }
    }
    
    public void OnEndDrag(PointerEventData eventData)
    {
        //  throw new System.NotImplementedException();
        transform.position = Origin;
        direction = Vector3.zero; 
    }
    private void Update()
    {
        Vector3 MoveDirection = new Vector3(direction.x, 0, direction.y);
        Debug.Log(direction);
    }
}

16实用属性(Attribute)

因为unity主要用c#语言,而c#语言具有强大的属性(Attribute)功能。

(47条消息) Unity中常用的Attribute_时间不会说谎shane的博客-CSDN博客

1.0 RequireComponent:约束组件
实用方法:[RequireComponent(typeof(Rigidbody))]
在某个自定类(派生于MonoBehavior)前写上这个属性,
那么当附加该组件的时候,会强制自动添加组件typeof(Rigidbody)
RequireComponent约束的组件。是不能删除的。除非先删除当前自定义脚本。
PS:可以多个 typeof()

2.0 SerializeField:序列化区域
实用方法:[SerializeField]
写在(派生于MonoBehavior)类中的变量上,实际效果如同变量前加个 public。
好处就是,你可以给变量定义成私有或者保护,并且显示在Inspector中。

3.0 Range(float min, float max):区域约束
实用方法:[Range(1, 5)]
写在(派生于MonoBehavior)类中的变量上。
这时,该变量在Inspector区域内显示成一个拖动条。
PS:也可以写在数组变量上。

4.0 Tooltip(string tooltip):提示
实用方法:[Tooltip(“这就是测试”)]
写在(派生于MonoBehavior)类中的变量上。
这时,当鼠标移动到Inspector区域的该变量上,会出现一个提示

5.0 Space(float height):间隔
实用写法:[Space(60)]
写在(派生于MonoBehavior)类中的变量上。
这时,该变量在Inspector区域内将于上一个变量之间空开60像素。

6.0 Header(string header):显示文字
实用写法:[Header(“显示字符串”)]
写在(派生于MonoBehavior)类中的变量上。
这时,该变量在Inspector区域的显示上一行中显示显示字符串。

7.0 Multiline(int lines):多行文本框
实用写法:[Multiline(5)]
写在(派生于MonoBehavior)类中的string变量上。
这时,该变量在Inspector区域的显示为一个多行编辑框。

8.0 TextArea(int minlines, int maxlines):多行文本框(滑动条)
实用写法:[TextArea(1,7)]
写在(派生于MonoBehavior)类中的string变量上。
这时,该变量在Inspector区域的显示为一个多行编辑框,超出了最大行,就会显示滚动条。

9.0 ContextMenu(string item):组件菜单
实用写法:[ContextMenu(“ShowName”)]
写在(派生于MonoBehavior)类中的方法上。
这时,挂有该脚本的对象的Inspector的脚本的右上角三个点的按钮中多出一个菜单按钮。

10.0 DisallowMultipleComponent:不能在一个对象上重复添加该脚本
实用写法:[DisallowMultipleComponent]
写在(派生于MonoBehavior)类上。
这时,挂有该脚本的对象不能再挂这个类。

11.0 AddComponentMenu(string menuItem):在Component菜单中添加一项
实用写法:[AddComponentMenu(“新功能/生成cs文件”)]
写在(派生于MonoBehavior)类上。
这时,在菜单Component中出现了你的自定义的菜单按钮。

17数据存储

(47条消息) Unity(数据的储存&解析)_一年时间升本,随缘更新的博客-CSDN博客_unity存储数据

XML & json:

(47条消息) XML和JSON_一旭日东升一的博客-CSDN博客_xml和json

一、PlayerPrefs

unity3d提供了一个用于本地持久化保存与读取的类-------PlayerPrefs.工作原理很简单,以键值对的形式将数据保存在文件中,然后程序可以根据这个名称取出上次保存的数值(注:PlayerPrefs运用起来很方便,随时都可以存取与读取)。

Void Start()
{
//Playerprefs类支持3中数据类型的保存和读取,分别是浮点型、整型和字符串型:
PlayerPrefs.SetInt();//保存整型数据
PlayerPrefs.SetFloat();//保存浮点型数据
PlayerPrefs.SetString();//保存字符串型数据
PlayerPrefs.GetInt();//读取整型数据
PlayerPrefs.GetFloat();//读取浮点型数据
PlayerPrefs.GetString();//读取字符串型数据
}

保存路径:win+R -> cmd -> regedit ,打开注册表:Windows:HKCU\Software[company name][product name]

二、TextAsset

读取普通文本资源:TextAsset

在Project窗口的根目录创建Resources文件夹,然后把名字为unity3d.txt的文件夹的文件放在Resources文件夹下就可以读取到。

三、Json

校验解析网站: JSON在线解析及格式化验证 - JSON.cn

下载:NuGet Gallery | System.Json 4.7.1

1.JSON 语法规则

1)对象表示为键值对

2)数据由逗号分隔 {“firstName”: “Jack”,“middleName”:“Nigulas”}

3)花括号保存对象

4)方括号保存数组

json创建
//⼤括号 — > ⼀对⼀对
JsonObject jsonTransform = new JsonObject ();//创建⼀个JSON对象,相当于⼀个⼤括号
JsonValue jsonPosition = "10,20,30";//创建⼀个JSON值对象,存储⼀个Value
jsonTransform.Add(“position”,jsonPosition);//JSON对象,也就是⼤括号,添加⼀个key:value
//打印结果
Debug.Log(jsonTransform.ToString());
{
    "position":"10,20,30"
}
///中括号 — > ⼀个⼀个
JsonValue[] rotationXYZ = new JsonValue[] {20,30,40} ;//定义⼀个值数组,⽤来存储,中括号中的⼀个个的值
JsonArray jsonRotation = new JsonArray(rotationXYZ);//将这个数组中的⼀个个的值放到JsonArray数组对象中
jsonTransform.Add(“rotation”,jsonRotation);//⼀个JsonArray对象,也可以是⼀个Value,
//所以可以⽤jsonTransform来Add
//打印结果
Debug.Log(jsonTransform);
//结果显示:
{
    "position":"10,20,30",
    "rotation":[
        20,
        30,
        40
    ]
}
///jsonArray中添加对象(⼤括号中包含的所有内容)
JsonObject x = new JsonObject ();
x.Add(“x”,10);
JsonObject y = new JsonObject ();
y.Add(“y”,20);
JsonObject z = new JsonObject ();
z.Add(“z”,30);
JsonValue[] scaleXYZ = new JsonValue[] {x,y,z};//实例⼀个jsonValues数组(所有类型都可以转换成jsonValue)
JsonArray jsonScale = new JsonArray (scaleXYZ);//将实例好了的数组,添加到jsonArray对象中,形成⼀个jsonArray对象
 //作⽤在于给这个整体,添加⼀个中括号[]
jsonTransform.Add(“scale”,jsonScale);//将这个整体,放⼊到jsonTransform中
//打印结果
Debug.Log(jsonTransform);
//结果显示:
{
    "position":"10,20,30",
    "rotation":[
        20,
        30,
        40
    ],
    "scale":[
        {
            "x":10
        },
        {
            "y":20
        },
        {
            "z":30
        }
    ]
}

AddRange的用法

        KeyValuePair<string, JsonValue>[] keyValues = new KeyValuePair<string, JsonValue>[3];//字典
        keyValues[0] = new KeyValuePair<string, JsonValue>("大学", "大连大学");
        keyValues[1] = new KeyValuePair<string, JsonValue>("专业", "计算机");
        keyValues[2] = new KeyValuePair<string, JsonValue>("方向", "人工智能");
        Person_obj.AddRange(keyValues);
    JsonObject Person_obj = new JsonObject();
    JsonArray core_obj = new JsonArray();
    JsonValue[] ArrarValue ;
    // Start is called befo the first frame update
    void Start()
    {
        Person_obj.Add("Name", "小明");
        Person_obj.Add("Age", 18);
        Person_obj.Add("Heigh", 180);
        JsonObject NewObj = new JsonObject();
        

        core_obj.AddRange("语文", "英语", "数学","历史");
        JsonValue coer_value = core_obj;
        JsonValue Trans_value = transform.position.ToString();
        Person_obj.Add("科目", coer_value);
        Person_obj.Add("坐标", Trans_value);
        Debug.Log(Person_obj);
    }
{
    "Name":"小明",
    "Age":18,
    "Heigh":180,
    "科目":[
        "语文",
        "英语",
        "数学",
        "历史"
           ],
    "坐标":"(-0.67, 9.49, 10.38)"
}
json解析

基本解析方法JsonMapper.ToObject (json);

using UnityEngine;
using LitJson;
public class ListJson : MonoBehaviour
{
    string json = "{\n\"name\":\"小明\",\n\"技能\":[ \n{\"1\":\"位移\",\"冷却\":[1,2,3,4,5]},\n{\"2\":\"蓄力\",\"冷却\":[5,6,7,8,9]},\n{\"3\":\"大战\",\"冷却\":[2,4,6,8,0]},\n{\"4\":\"范围\",\"冷却\":[3,5,7,8]}\n]\n}";
    void Start()
    {
        JsonData Date = JsonMapper.ToObject(json);
        //Debug.Log(Date["name"]);
        for (int i = 0; i < 3; i++)
        {
           Debug.Log(Date["技能"][i]["冷却"]);
        }  
    }
}

高阶方法:如下json

{
    "Name":"小明",
    "Age":18,
    "Heigh":180,
    "Colloge":"大连大学",
    "Profession":"计算机",
    "Direction":"人工智能",
    "Course":[
        "语文",
        "英语",
        "数学",
        "历史"
             ],
    "Transform":"(-0.67, 9.49, 10.38)"
}

解析:先创建一个类C#如下:

public class PersonInformation
{
    public string Name;
    public int Age;
    public int Height;
    public string Colloge;
    public string Profession;
    public string Direction;
    public string Transform;
    public string[] Course;
}

重点代码,泛型:

PersonInformation person = JsonMapper.ToObject(Person_json);

{
        string Person_json = "{\n    \"Name\":\"小明\",\n    \"Age\":18,\n    \"Heigh\":180,\n    \"Colloge\":\"大连大学\",\n    \"Profession\":\"计算机\",\n    \"Direction\":\"人工智能\",\n    \"Course\":[\n        \"语文\",\n        \"英语\",\n        \"数学\",\n        \"历史\"\n    ],\n    \"Transform\":\"(-0.67, 9.49, 10.38)\"\n}";
//暂时用这样
        PersonInformation person = JsonMapper.ToObject(Person_json);
        Debug.Log(person.Age);
        Debug.Log(person.Name);
        Debug.Log(person.Course[1]);
    }

四、XML存储

技术文档 | Microsoft Learn

(47条消息) unity 对XML文件的创建、写入、读取、更新等的操作_爱尚游Bin的博客-CSDN博客

(47条消息) unity中XML文件操作_alwaysPractice的博客-CSDN博客

1)XML 被设计用来传输和存储数据。

2)XML 标签没有被预定义。您需要自行定义标签。

3)XML 数据以纯文本格式进行存储,因此提供了一种独立于软件和硬件的数据存储方法。

项目开发中,会使用xml作为软件的配置文件,在这里记录一下关于XML的基本操作。

本案例将XML文件创建在StreamingAssets文件夹中,若工程中不存在该文件夹请自己创建
(保存到该文件夹,便于在项目发布时,能够将配置文件一并打包到程序中,并且不被压缩便于日后修改)
引用命名空间:
using System.IO;
using System.Xml;

1.XML的创建
void CreateXML() {
        localPath = UnityEngine.Application.streamingAssetsPath + "/"+"MyXML.xml";
        if (!File.Exists(localPath) ) {
            XmlDocument xml = new XmlDocument();//实例化
            XmlDeclaration xmldecl = xml.CreateXmlDeclaration("1.0", "UTF-8", "");//设置xml文件编码格式为UTF-8
            XmlElement root = xml.CreateElement("Data");//创建根节点
            XmlElement info = xml.CreateElement("Info");//创建子节点
            info.SetAttribute("Name","小王");//创建子节点属性名和属性值
            info.SetAttribute("Age","28");
            info.SetAttribute("Phone","12345678");
            root.AppendChild(info);//将子节点按照创建顺序,添加到xml
            xml.AppendChild(root);
            xml.Save(localPath);//保存xml到路径位置
            Debug.Log("创建XML成功!");
        }
    }

调用该方法,运行结果如下图:

创建的XML文件

<Data>
  <Info Name="小王" Age="28" Phone="12345678" />
Data>
2.XML的写入
void AddXML() {
        localPath = UnityEngine.Application.streamingAssetsPath + "/" + "MyXML.xml";
        if ( File.Exists(localPath) )
        {
            XmlDocument xml = new XmlDocument();
            xml.Load(localPath);//加载xml文件
            XmlNode root = xml.SelectSingleNode("Data");//获取根节点
            XmlElement info = xml.CreateElement("Info_2");//创建新的子节点
            info.SetAttribute("Name", "小李");//创建新子节点属性名和属性值
            info.SetAttribute("Age", "25");
            info.SetAttribute("Phone", "87654321");
            root.AppendChild(info);//将子节点按照创建顺序,添加到xml
            xml.AppendChild(root);
            xml.Save(localPath);//保存xml到路径位置
            Debug.Log("添加XML成功!");
        }
    }

在创建MyXML文件后,调用 AddXML() 方法。

XML的写入

void AddXML() {
        localPath = UnityEngine.Application.streamingAssetsPath + "/" + "MyXML.xml";
        if ( File.Exists(localPath) )
        {
            XmlDocument xml = new XmlDocument();
            xml.Load(localPath);//加载xml文件
            XmlNode root = xml.SelectSingleNode("Data");//获取根节点
            XmlElement info = xml.CreateElement("Info_2");//创建新的子节点
            info.SetAttribute("Name", "小李");//创建新子节点属性名和属性值
            info.SetAttribute("Age", "25");
            info.SetAttribute("Phone", "87654321");
            root.AppendChild(info);//将子节点按照创建顺序,添加到xml
            xml.AppendChild(root);
            xml.Save(localPath);//保存xml到路径位置
            Debug.Log("添加XML成功!");
        }
    }

在创建MyXML文件后,调用 AddXML() 方法。运行结果如图下图:

写入后的XML文件

<Data>
  <Info Name="小王" Age="28" Phone="12345678" />
  <Info_2 Name="小李" Age="25" Phone="87654321" />
Data>
Character Controller组件写入xml(作业)
  void CharatorControllerXML()
    {
        string CCXMLpath = Application.streamingAssetsPath + "/CharatorController.xml";
        XmlDocument CCDoc = new XmlDocument();
        XmlDeclaration CCDec = CCDoc.CreateXmlDeclaration("1.0", "UTF-8", "");

        XmlElement Root = CCDoc.CreateElement("Charactor_Controller");//创建根节点
        Root.SetAttribute("name", "角色控制器组件");// 创建子节点属性名和属性值

        XmlElement InfoSlopeLimit = CCDoc.CreateElement("SlopeLimit");//创建子元素
        XmlAttribute slopLimitAttribut = CCDoc.CreateAttribute("name");//创建属性节点
        slopLimitAttribut.Value = "边缘最小值";//给属性赋值
        InfoSlopeLimit.SetAttributeNode(slopLimitAttribut);//将属性赋给元素
        InfoSlopeLimit.InnerText = characterController.slopeLimit.ToString();//给元素传值

        XmlElement InfoStepOffset = CCDoc.CreateElement("StepOffset");
        InfoStepOffset.InnerText = characterController.stepOffset.ToString();
        XmlElement InfoSkinWidth = CCDoc.CreateElement("SkinWidth");
        InfoSkinWidth.InnerText = characterController.skinWidth.ToString();
        XmlElement InfoMinMoveDictance = CCDoc.CreateElement("MinMoveDictance");
        InfoMinMoveDictance.InnerText = characterController.minMoveDistance.ToString();
        XmlElement InfoCenter = CCDoc.CreateElement("Center");
        InfoCenter.InnerText = characterController.center.ToString();
        XmlElement InfoRadious = CCDoc.CreateElement("Radious");
        InfoRadious.InnerText = characterController.radius.ToString();
        XmlElement InfoHeight = CCDoc.CreateElement("Height");
        InfoHeight.InnerText = characterController.height.ToString();

        Root.AppendChild(InfoSlopeLimit);//子元素赋给根元素
        Root.AppendChild(InfoStepOffset);
        Root.AppendChild(InfoSkinWidth);
        Root.AppendChild(InfoMinMoveDictance);
        Root.AppendChild(InfoCenter);
        Root.AppendChild(InfoRadious);
        Root.AppendChild(InfoHeight);

        CCDoc.AppendChild(Root);//根元素赋给文档
        CCDoc.Save(CCXMLpath);//保存
    }    
<Charactor_Controller name="角色控制器组件">
  <SlopeLimit name="边缘最小值">45SlopeLimit>
  <StepOffset>0.3StepOffset>
  <SkinWidth>0.08SkinWidth>
  <MinMoveDictance>0.001MinMoveDictance>
  <Center>(0.00, 0.00, 0.00)Center>
  <Radious>0.5Radious>
  <Height>2Height>
Charactor_Controller>
3.XML的读取
 void ReadXML() {
        localPath = UnityEngine.Application.streamingAssetsPath + "/" + "MyXML.xml";
        if ( File.Exists(localPath) )
        {
            XmlDocument xml = new XmlDocument();
            xml.Load(localPath);//加载xml文件
            XmlNodeList nodeList = xml.SelectSingleNode("Data").ChildNodes;
            foreach (XmlElement xe in nodeList) {//遍历所以子节点
                if (xe.Name== "Info_2" ) {
                    Debug.Log(xe.GetAttribute("Name"));//获取Name属性值
                    Debug.Log(xe.GetAttribute("Age"));
                    Debug.Log(xe.GetAttribute("Phone"));
                }
            }                     
            Debug.Log("读取XML成功!"+xml.OuterXml);
        }
    }

在写入XML信息后,在Start()中调用ReadXML()方法。运行结果下图:千锋Unity学习笔记_第5张图片

XML的读取

void ReadXML() {
        localPath = UnityEngine.Application.streamingAssetsPath + "/" + "MyXML.xml";
        if ( File.Exists(localPath) )
        {
            XmlDocument xml = new XmlDocument();
            xml.Load(localPath);//加载xml文件
            XmlNodeList nodeList = xml.SelectSingleNode("Data").ChildNodes;
            foreach (XmlElement xe in nodeList) {//遍历所以子节点
                if (xe.Name== "Info_2" ) {
                    Debug.Log(xe.GetAttribute("Name"));//获取Name属性值
                    Debug.Log(xe.GetAttribute("Age"));
                    Debug.Log(xe.GetAttribute("Phone"));
                }
            }                     
            Debug.Log("读取XML成功!"+xml.OuterXml);
        }
    }

在写入XML信息后,在Start()中调用ReadXML()方法。运行结果下图:

4.XML的更新
public void UpdateXml()
    {
        localPath = UnityEngine.Application.streamingAssetsPath + "/" + "MyXML.xml";
        if ( File.Exists(localPath) )
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(localPath);
            XmlNodeList nodeList = xmlDoc.SelectSingleNode("Data").ChildNodes;
            foreach ( XmlElement xe in nodeList )
            {
                //拿到节点中属性Name =小王的节点
                if ( xe.GetAttribute("Name") == "小王" )
                {
                    //更新节点属性
                    xe.SetAttribute("Age", "21");        
                    break;
                }
            }
            xmlDoc.Save(localPath);
            Debug.Log("更新XML成功!");
        }
    }

更新后的XML信息

<Data>
  <Info Name="小王" Age="21" Phone="12345678" />
  <Info_2 Name="小李" Age="25" Phone="87654321" />
Data>
5.XML的删除
 public void DeleteXml()
    {
        localPath = UnityEngine.Application.streamingAssetsPath + "/" + "MyXML.xml";
        if ( File.Exists(localPath) )
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(localPath);
            XmlNodeList nodeList = xmlDoc.SelectSingleNode("Data").ChildNodes;
            foreach ( XmlElement xe in nodeList )
            {
                if ( xe.GetAttribute("Name") == "小李" )
                {
                    xe.RemoveAttribute("Phone");
                }
                if ( xe.GetAttribute("Name") == "小王" )
                {
                    xe.RemoveAll();
                }
            }
            xmlDoc.Save(localPath);
            Debug.Log("删除XML成功!");
        }
    }

XML的删除

 public void DeleteXml()
    {
        localPath = UnityEngine.Application.streamingAssetsPath + "/" + "MyXML.xml";
        if ( File.Exists(localPath) )
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(localPath);
            XmlNodeList nodeList = xmlDoc.SelectSingleNode("Data").ChildNodes;
            foreach ( XmlElement xe in nodeList )
            {
                if ( xe.GetAttribute("Name") == "小李" )
                {
                    xe.RemoveAttribute("Phone");
                }
                if ( xe.GetAttribute("Name") == "小王" )
                {
                    xe.RemoveAll();
                }
            }
            xmlDoc.Save(localPath);
            Debug.Log("删除XML成功!");
        }
    }

删除后XML信息

<Data>
  <Info />
  <Info_2 Name="小李" Age="25" />
Data>

18SQLite数据库

SQL 教程 | 菜鸟教程 (runoob.com)

软件:SqliteManager

SQL语法:

插⼊全数据 语法:Insert Into 表名称 Values(值1,值2,。。。)

注意:Values(所有的值都要写进来)

举例:

Insert Into StudentInfo  Values('20160103','刘盼',18,'乌鲁⽊⻬') 

插⼊部分数据 语法:Insert Into 表名称 (字段名称1,字段名称2) Values (值1,值2)

举例:

Insert Into StudentInfo (Num,Name,Age)  Values ('20170101','武涛',18) 

语法:Update 表名称 Set 字段名称1 = 新值 Where 字段名称2 = 某值

举例:

Update StudentInfo Set Address = '哈萨克斯坦' Where Name = '刘盼' 

语法:Select 字段名称 From 表名称 Where 列名 = 某值 and 与 or 或

查询部分字段

举例:

Select Age From StudentInfo Where Name = '李狗蛋'

查询所有字段

举例:

Select * From StudentInfo Where Name = '刘盼' 

模糊查询:

Select * From StudentBaseMsg Where StuName Like ''%L%'' 

查询并排序:Select * From StudentBaseMsg Order By StuAge ASC/DESC ASC 从⼩到⼤排序 DESC从⼤到⼩排序

语法:Delete From 表名称 Where (条件)

举例:

Delete From StudentInfo Where Num = '20170102'

编程实现增删改查

步骤(共9步):

1、将DLL导⼊⼯程Plugins⽂件夹

导包:D:\Study\Unity\unity\2021.3.1f1c1\Editor\Data\MonoBleedingEdge\lib\mono\unityjit-win32里的Mono.Data.Sqlite和System.Data

三个:Mono.Data.Sqlite ,【2017】System.Data ,Sqlite3:SQLite Download Page

2、using Mono.Data.Sqlite;

**3、创建路径(流路径)**关于路径:查看5.0Application

固定写法“Data Source = ” + 路径

public string GetDataPath(string databasePath) 
{ 
    #if UNITY_EDITOR  
        return String.Concat("data source=", Application.streamingAssetsPath, "/", databasePath);
    #endif
    #if UNITY_ANDROID 
        return String.Concat("URI=file:", Application.persistentDataPath, "/", databasePath);//安卓写法 
    #endif
    #if UNITY_IOS return String.Concat("data source=", Application.persistentDataPath, "/", databasePath);
    #endif 
}

4、创建数据库连接对象(SqliteConnection), 并在构造函数中传⼊数据库所在路径

5、通过数据库连接对象创建指令对象(SqliteCommand)

6、打开数据库连接(Open⽅法)

7、将SQL语句传⼊指令对象(属性CommandText)

8、执⾏SQL语句(SqliteCommand)

  1. ExecuteNonQuery() 作⽤:执⾏SQL语句,并返回受影响的⾏数 使⽤范围:增删改
  2. ExecuteScalar() 作⽤:执⾏SQL语句,返回查询到的 第⼀个结果(第⼀⾏的第⼀列) 使⽤范围:查询单个数据 (查询的结果是⼀⾏⼀列)
  3. ExecuteReader() 作⽤:执⾏SQL语句,返回所有查 询到的结果(SqliteDataReader) 使⽤范围:查询多个数据 (多⾏多列) 取数据 Read(); 读取下⼀⾏ FieldCount 列数 ;GetName(列号)获取该列的字段名; GetValue(列号) 获取该列的值; 注意 :当数据读取完毕后记得 执⾏关闭读取器的⽅法 reader.Close();

9、释放资源

reader close

command dispose

con clos

整体代码:
    private string DataBasePath;//数据库的路径
    private SqliteConnection sqlcon;//创建数据库连接对象(SqliteConnection)
    private SqliteCommand sqlcomm;//创建指令对象(SqliteCommand)
    void Start()
    {
#if UNITY_EDITOR//运行在编译器下
        DataBasePath = "Data Source = " + Application.streamingAssetsPath + "/dump.sqlite";//创建路径(流路径)
#endif//一定要加.sqlite;

        //运行在windows下
#if UNITY_STANDALONE_WIN
        DataBasePath = "Data Source = " + Application.streamingAssetsPath + "/dump.sqlite";//创建路径(流路径)
#endif

        sqlcon = new SqliteConnection(DataBasePath);//传⼊数据库所在路径
        sqlcon.Open();//打开数据库连接
        sqlcomm = sqlcon.CreateCommand();//创建数据库指令对象
        sqlcomm.CommandText = "Select Name from StudentBaseBable";//将SQL语句传⼊指令对象(属性CommandText)
        object obj = sqlcomm.ExecuteScalar();//执⾏SQL语句(SqliteCommand)
        //执⾏SQL语句,返回查询到的 第⼀个结果(第⼀⾏的第⼀列) 使⽤范围:查询单个数据 (查询的结果是⼀⾏⼀列) 
        Debug.Log(obj);
        
        sqlcomm.CommandText = "insert into StudentBaseBable values('20421011','唐龙','33','湖南')";
        int rows = sqlcomm.ExecuteNonQuery();//执⾏SQL语句,并返回受影响的⾏数  使⽤范围:**增删改**
        Debug.Log("受影响的行数:" + rows.ToString());
        
        sqlcomm.CommandText = "select * from StudentBaseBable";
        sqlDataReader = sqlcomm.ExecuteReader(); //执⾏SQL语句,返回所有查 询到的结果(SqliteDataReader) 使⽤范围:查询多个数据 (多⾏多列) 
        string currentcom = "";
        for (int i = 0; i < sqlDataReader.FieldCount; i++) 读取下⼀⾏ FieldCount 列数
        {
            currentcom += sqlDataReader.GetName(i).ToString();//GetName(列号) 获取该列的字段名
            currentcom += "\t";
        }
        Debug.Log(currentcom);
        while (sqlDataReader.Read())//取数据 Read() 
        {
            string currentcom02 = "";
            for (int i = 0; i < sqlDataReader.FieldCount; i++)// 读取下⼀⾏ FieldCount 列数
            {
                currentcom02 += sqlDataReader.GetValue(i).ToString();//GetValue(列号) 获取该列的值 
                currentcom02 += "\t";
            }
            Debug.Log(currentcom02);
        }
    }
    private void OnApplicationQuit()//应用程序关闭时调用
    {
        if (sqlDataReader != null)//注意 当数据读取完毕后记得 执⾏关闭读取器的⽅法 reader.Close();
        {
            sqlDataReader.Close();
            sqlDataReader = null;
        }
        if (sqlcomm != null)
        {
            sqlcomm.Dispose();
            sqlcomm = null;
        }
        if (sqlcon != null)//释放资源
        {
            sqlcon.Close();//释放资源
            sqlcon = null;
        }
    }

19优化

Unity全面优化 - 简书 (jianshu.com)

Draw Call: CPU向GPU发布渲染命令,Draw Call越大:CPU的占有率就会越高
优化Draw Call的方法:
1、批处理:

1静态批处理:要求宽松,批处理量比较大,将静态场景设置为Batching Static

2动态批处理:要求苛刻,批处理量比较少
2、调节摄像机的渲染路径

1正向渲染,

2延时光照,

3顶点光照

20协同程序与WWW

千锋Unity学习笔记_第6张图片

(54条消息) Unity-协程详解_卖烤麸烤饼儿的博客-CSDN博客_unity 协程

//协程不是多线程,它与主线程同时运行,它在主线程运行的同时开启另一段逻辑处理。
private Coroutine cou;
void Start()
{
     cou =  StartCoroutine(install(3,0.5));
     StartCoroutine("parent");
}
void Update()
{
     if(input.getkeydown(keycode.space))
     {
         stopCoroutine(cou);
     }
}

IEnumerator insatall(float firstTime,float secondTime)
  {
     for(int i ; i < 5; i++)
     {
     yield return new WaitForSeconds(firstTime);
     //install firs等待firstTime秒后开始执行
          for(int j ; j < 3; j++)
          { 
             yield return new WaitForSecond(secondTime);
             //等待SecondTime秒后开始执行
          }
     }
}
IEnumerator parent()
  {
     Debug.log("Parent");
}
Ienumerator BreakCon()
{
    for(int i = 1; i < 10; i++)
        if(i % 5 == 0)
            yield break;//退出协程
        else
            yield return new WaitForSeconds(1);
            Deubd.log(i);
}

(54条消息) Unity的WWW类的用法整理_寒冰骑士的博客-CSDN博客_unity wwwform 传入数组

21Shader

主要参考Unity_Shader md文档

Unity_Shader md文档

基础

(54条消息) UnityShader(二)Unity Shader结构_夜槿笙歌的博客-CSDN博客

shader:

[(55条消息) unity-shader(入门)_莉萝爱萝莉的博客-CSDN博客_unityshader](https://blog.csdn.net/qq_50682713/article/details/117993486?ops_request_misc=&request_id=&biz_id=102&utm_term=unity shader&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-1-117993486.142v70control,201v4add_ask&spm=1018.2226.3001.4187)

(55条消息) Unity—Shader_renwen1579的博客-CSDN博客

代码:

// 当前Shader的名称,斜杠可以控制当前Shader显示在材质面板下拉列表的位置 ,对于属性块(Properties)中声明的变量,可以在材质面板进行调整(需要先将Shader指定给一个材质),材质面板中显示的变量名是引号中的名称,如果要再Shader中访问这些变量,可以通过变量名访问。
Shader "Unlit/MyShader" 
{  
    // 属性块  
    Properties  
{  
    _Int("Int",int) = 2  
    _Float("Float",float) = 1.5  
    _Range("Range",Range(0.0,2.0)) = 1.0  
	
    _Color("Color",Color) = (1,1,1,1)  
    _Vector("Vector",Vector) = (1,2,3,4)  
	
    _MainTex ("Texture", 2D) = "white" {}  //二阶贴图
    _Cube("Cube",Cube) = "white"{}  
    _3D("3D",3D) = "black"{}  
    // 相当于变量,会显示在Inspector面板中  
    // 结构: 变量名(显示名称,类型) = 默认值  
}

  //每一个Unity Shader都必须包含至少一个SubShader语义块。当游戏运行在不同平台上时,Unity会扫描所有的SubShader,并选择第一个能够运行的SubShader。如果都无法运行,则会调用Fallback语义指定的Unity Shader。
    SubShader  
    {  
        //标签(key-value),可选 ,SunShader的标签(Tags)是一个键值对,且键和值都是字符串类型。它用来告诉Unity该怎样及如何渲染这个对象。SubShader支持的标签类型如下: 
        Tags  {  
	"Queue"="Transparent" //Queue 渲染顺序  
	"RenderType"="Opaque" //RenderType 渲染类型(着色器替换功能) 
	"DisableBatching"="True" //禁用批处理  
	"ForceNoShadowCasting"="True" //是否投射阴影  
	"IgnoreProjector"="True" //忽略Projector影响(通常用于透明物体)  
	"CanUseSpriteAltas"="False" //是否用于图片的Shader(通常用于UI)  
	"PreviewType"="Plane" //用作Shader面板预览的类型  
             }  
        // 渲染设置,可选,RenderSetup,用于设置显卡的各种状态,例如是否开启混合/深度测试等。常见的渲染状态设置选项如下:
        Cull off 
		//Cull off  设置剔除哪个面 [off(正反两面都渲染)/back/front]  
         //ZTest Always  设置深度测试使用的函数 [Always/Less/Greater/LEqual/GEqual/Equal/NotEqual]
         //Zwrite off  设置是否开启深度写入 [on/off]
         //Blend [SrcFactor(源)] [DstFactor(目标)] 开启并设置混合模式  
         //LOD 100  细节层次,unity引擎会根据不同的LOD值在使用不同的SubShader
            
        Pass  //每个Pass定义了一次完整的渲染流程,但如果Pass的数目过多,往往会造成性能下降。
        {  
            Name "MyPass" //Name语句可以设置当前Pass的名称,可以在其他Unity Shader中使用UsePass命令来使用这个Pass,需要注意的是,使用UsePass命令时必须使用大写形式的名字。
        //Pass同样可以设置标签,但不同于SunShader的标签,这些标签也用于告诉引擎怎样渲染这个物体。
            Tags{  
	"LightMode"="ForwardBase"// 定义该Pass通道在Unity渲染流水中的角色  
	"RequireOptions"="SoftVegetation"// 满足某些条件时才渲染该Pass通道 
                 }
	
            // 渲染设置 也可以在Pass通道中定义  
			// .....
			
            // CG语言代码,主要是顶点/片元着色器  
            CGPROGRAM  
			// .... 
            ENDCG  
        }  
    }  
	
    Fallback off // "name"/off 当上面的SubShader都无法执行时,执行此语句 ,当前Unity Shader中的SunShader都无法运行时,调用Fallback语句,一般用于指定一个最基础的Shader。
}

进阶

c#高阶

  • 命名空间
  • 异常处理 try catch
  • 反射
  • 特性 HideInInspector Header

设计模式:GoF26

UI 框架:UI模块的模态处理,多层UI模块的栈处理、本地化、UI对象的统一管理

状态机框架:通用状态

A*寻路算法: 底层原理, A Star Path Finding

资源管理:拖拽、Resources,Assets Bundle

网络:网络底层Socket【收发消息】【同步(状态同步、帧同步)】,网络游戏框架【Photon】

热更新:Lua【ToLua框架】Slua Xlua

你可能感兴趣的:(unity,游戏引擎,学习)