Unity的一些基础性东西

32 篇文章 1 订阅
3 篇文章 0 订阅

1.Unity是单线程的游戏引擎,unity的非主线程中无法访问Unity的API,这种限制的原因:游戏中逻辑更新和画面更新的时间点要求有确定性,必须按照帧序严格保持同步,否则就会出现游戏中的对象不同步现象。

2.生命周期:我们在自己脚本里写OnApplicationQuit,OnDisable,OnDestroy三个函数时的执行顺序于书写顺序一样,是因为在OnApplicationQuit里调用了后面两个函数。

3.center就是你那个模型,或者多个模型联合起来的外接盒的几何中心。pivot是模型制作者决定的,Unity内置模型的pivot就是它的几何中心,所以两者一样。而模型如果是用3ds Max或其它三维工具制作的,就可以把pivot设置到模型的任何位置(在Max中叫做模型的轴),比如可以把它设置到盒子的一个顶点上,或底盘中心。当两者不在一起的时候,如果设置为center,旋转的时候位置会跟着改变,如果设置成pivort,旋转时position则不会改变。

4.gloabl和local,前者显示的世界坐标轴,后者显示的自己坐标轴。

5.persp和ISO,前者是透视模式(3d),后者是正交模式(无论离摄像头近还是远都显示一样的,2d)。

6.关于物体移动:1.lerp:变速,由起点向终点无限接近。值由大到小2.movetowards:匀速3.Lerp:第三个参数为AnimationCurve 对象的curve.Evaluate(x)值,x为自定义float变量。

public AnimationCurve curve;
//(2)定义x轴变量
private float x;
//(3)定义持续时间

 [Tooltip("持续时间")]
public float duration = 1;

 x +=Time.deltaTime / duration;//备注:x到1相当于物体到达终点         
 //transform.position = Vector3.Lerp(Vector3.zero, target, curve.Evaluate(x));//将数值上的变化 转换为 坐标的变化
 transform.position = Vector3.LerpUnclamped(Vector3.zero, target, curve.Evaluate(x));//将数值上的变转换为 坐标的变化   无上限限制!

7.坐标点转换:local Space ---》 world space 

8.向量相减,方向指向被减数( P-Q = (x1-x2,y1-y2)),向量相加(P+Q = (x1+x2,y1+y2)),为两个向量的对角线,运算后得到的向量在世界坐标原点。1弧度 = 180 / π 角度,1角度 = π / 180 弧度。 弧度 = 角度数 * π / 180 (角度数* Mathf.Deg2Rad),角度 = 弧度数 * 180 / π(弧度数* Mathf.Rad2Deg)   unity里Mathf.Sin(弧度数)等参数用的是弧度数。向量的点乘(点积/内积):各分量乘积和,a·b=|a|·|b|cos<a,b>,几何意义:是一条边向另一条边的投影乘以另一条边的长度.相应元素的乘积的和:v1( x1, y1,z1) * v2(x2, y2,z2) = x1*x2 + y1*y2+z1*z2;注意 : 结果不是一个向量,而是一个标量, a*b = b*a  满足乘法交换律,Unity应用:1.对于标准化过得向量,点乘结果等于两个向量的夹角的余弦值,对于标准化过得向量,方向相同结果为1,垂直为0,完全相反为-1。2.根据点乘的正负值,得到夹角大小范围,>0,则夹角(0,90)<0,则夹角(90,180),可以利用这点判断一个多边形是面向摄像机还是背向摄像机。API:Vector3.Dot(a,b), 单位向量的到的点乘结果换算成的角度在0-180之间(Vector3.Angle(a,b)返回的也是0-180)。向量的叉乘(叉积/外积):定义:c = a x b,其中a b c均为向量,几何意义是:得到一个与这两个向量都垂直的向量,这个向量的模是以两个向量为边的平行四边形的面积,v1( x1, y1,z1) x v2(x2, y2,z2) = [y1 * z2 - z1 *y2, z1 *x2 - x1 * z2, x1 *y2 - y1 * x2]。性质1:c⊥a,c⊥b,即向量c与向量a,b所在平面垂直,性质2:模长|c| = |a||b| sin<a,b>。性质3:满足右手法则, a x b = -b x a,所以我们可以使用叉乘的正负值来判断a,b的相对位置,即b是处于a的顺时针还是逆时针方向,  (i、j、k分别为空间中相互垂直的三条坐标轴的单位向量).所以结果为 axb=(y1 * z2 - z1 *y2, z1 *x2 - x1 * z2, x1 *y2 - y1 * x2),注意:如果与任意的轴向量(x 或 y 或z)做叉乘,得到的叉乘结果向量在另外两个轴向组成的二维空间内。

二维向量叉乘公式a(x1,y1),b(x2,y2),则a×b=(x1y2-x2y1)。

local epsilon = 0.000001; local dot = _v1.x * _v2.x + _v1.z * _v2. local angle = 0; if math.abs(dot - 1) <= epsilon then angle = 0;

elseif math.abs(dot + 1) <= epsilon then angle = math.pi; else angle = math.acos(dot); local cross = _v1.x * _v2.z - _v2.x * _v1.z;  if cross < 0 then angle = 2 * math.pi - angle; end 

向量求模:

https://blog.csdn.net/codeswarrior/article/details/79834257右手法则:右手的四指方向指向第一个矢量,屈向叉乘矢量的夹角方向(两个矢量夹角方向取小于180°的方向),那么此时大拇指方向就是叉乘所得的叉乘矢量的方向.(大拇指应与食指成九十度)(注意:Unity当中使用左手,因为Unity使用的是左手坐标系)。unity应用:简单的说: 点乘判断角度,叉乘判断方向。 形象的说: 当一个敌人在你身后的时候,叉乘可以判断你是往左转还是往右转更好的转向敌人,点乘得到你当前的面朝向的方向和你到敌人的方向的所成的角度大小。UnityAPI:Vector3.Cross(v1, v2).通过单位向量获得叉乘的向量转换的角度在0-90度之间,因为模长是绝对值 一定是正的。

判断是否在矩形内:思路是矩形的四个顶点,按照顶点顺序,每两个顶点在组成一个向量,如果该点在矩形内,那么改点在四个向量的同侧。

-- 计算 叉乘|
public int checkCross(p1, p2, p){
    return (p2.x - p1.x) * (p.z - p1.z) -(p.x - p1.x) * (p2.z - p1.z)
}

-- 已知p1 p2 p3 p4为 矩形的顺序四个顶点,p为检测点
public bool checkRect(p1, p2, p3, p4, p){
    return checkCross(p1, p2, p) * checkCross(p3, p4, p) >= 0 and checkCross(p2, p3, p) *  checkCross(p4 ,p1, p) >= 0
}

如果不知道四个顶点,需要求的时候:先要求出当前朝向的垂直向量B,方法为向量Y轴与当前朝向做叉乘,得到的向量的标量即为垂直向量

    Vector3 pos = attacker.getCurRotation() *(长度) + attacker.getCurPosition();

     Vector3 pos1 = B *(宽度 + 模型半径).sum(attacker.getCurPosition());
     Vector3 pos2 = B *(-宽度  - 模型半径).sum(attacker.getCurPosition());
     Vector3 pos3 = B *(宽度 + 模型半径).sum(pos ;
      Vector3 pos4 = B *(-宽度  -  模型半径).sum(pos);

pos1 pos2 pos3 pos4 即为四个顶点

判断两个线段是否相交
-- p1, p2为一条线段两端点 p3, p4为另一条线段的两端点   
public bool checkIntersect(p1, p2, p3, p4){
    if(Math.max(p1.x, p2.x))  < Math.min(p3.x, p4.x) )
        return false
    if (Math.max(p3.x, p4.x) < Math.min(p1.x, p2.x)) 
       return false;  
    if(Math.max(p1.z, p2.z) < Math.min(p3.z, p4.z))   
       return false
    if (Math.max(p3.z, p4.z) < Math.min(p1.z, p2.z)) 
       return false;  

    if (checkCross(p3, p2, p1)* checkCross(p4, p2, p1) <= 0  &&

        checkCross(p1, p4, p3)  * checkCross(p2, p4, p3) <= 0) 
         return true

}
    return false;  
}

下面为判断敌人在玩家周围方位代码:

        Vector3 dir = t2.position - t1.position;
        dot = Vector3.Dot(dir.normalized, transform.forward);
        float angle = Mathf.Acos(dot) * Mathf.Rad2Deg;
        cross = Vector3.Cross(transform.forward, dir);

        Debug.DrawLine(t1.position, t2.position, Color.red);
        Debug.DrawLine(t1.position, t1.position + t1.forward, Color.yellow);
        Debug.DrawLine(Vector3.zero, cross, Color.blue);

        if (angle > 90 && cross.y > 0)
        {
            print("右后方");
        }
        else if (angle > 90 && cross.y < 0)
        {
            print("左后方");
        }
        else if (angle < 90 && cross.y > 0)
        {
            print("右前方");
        }
        else if (angle < 90 && cross.y < 0)
        {
            print("左前方");
        }

判断扇形技能是否击中目标的的方法:已知:自身坐标,自身朝向(标量)。目标坐标。技能半径,扇形角度。

1.如果两者距离大于技能半径,则未击中。

2.自身的朝向的标量乘以技能半径获得向量A。

3.目标坐标于自身坐标做向量减法运算,得到的向量指向被减数,即由自身指向目标的向量D。由于游戏里技能一般都是x,z坐标系判断即可,不用y轴坐标系,所以这里把自身坐标和目标坐标的y轴手动设置为0后来运算,得到是x,z组成的二维坐标系向量。

4.由上面向量运算可知,任意向量与轴向量叉乘得到的向量在两个轴向组成的坐标系中,且垂直于叉乘的两个向量,所以向量A与Y轴的两个方向做叉乘得到向量B和C,得到两个向量后做标量处理,处理后的结果分别乘以(技能半径 * Math.tan(扇形角度 / 2 )),结果为通过两个扇形角度确定后的向量B和C,

5.向量A分别加上向量B和C就获得了扇形的两条边向量E和F。判断向量E和F是不是在向量D 的两侧就可以了。

D.cross(E).y * D.cross(F).y  <= 0 为在扇形内。

判断是不是在椭圆内的方法:椭圆性质:

1)焦点在X轴时,标准方程为:2)焦点在Y轴时,标准方程为:

                      

又及:如果中心在原点,但焦点的位置不明确在X轴或Y轴时,方程可设为mx²+ny²=1(m>0,n>0,m≠n)。即标准方程的统一形式。椭圆的面积是πab。

所以判断点是否在椭圆内的方法可以是:点到椭圆的两个焦点的距离之和大于长轴(2a),则在椭圆外,等于则在椭圆上,小于则在椭圆内。

已知:长半轴,短半轴,自己坐标,自己朝向,目标坐标。

1.通过c^2 = a ^2 - b ^2 求出焦距c。

2.通过与y轴于自己朝向做叉乘获取垂直于当前朝向的标量A。

3.通过标量 A * c 获取 标量方向上长度为c的向量 B。再用自己的坐标分别加上 B和 -B 来获取两个焦点坐标。

4.目标坐标于两个焦点坐标的距离和于2a做比较。 

9.欧拉角于四元数:欧拉角:eulerAngles使用三个角度来保存方位。有点:任意三个数字都是合法的,不存在不合法的欧拉角,缺点:对于一个方位,存在多个欧拉角描述,因此无法判断多个欧拉角代表的位移是否相同,万向节死锁:物体沿x轴旋转±90度,自身坐标系z轴于世界坐标系y轴重合,此时再沿Y轴或Z轴旋转,将失去一个自由度,自身坐标的Y轴和世界坐标的z轴。旋转为0,全部转移另一个Z轴或者Y轴。四元数:Quaternion在3D图形学中代表旋转,由一个三维向量(x/y/z)和一个标量w组成,取值范围为-1到1.四元数左乘向量,表示将该向量按照四元数表示的角度旋转,两个四元数相乘可以组合旋转效果。优点:避免万向节死锁,缺点:存在不合法的四元数,不建议单独修改某个值。trasform.RotateAround()围绕某个点和轴转动(世界坐标点和世界坐标轴)

10.碰撞条件:运动的物体有刚体并且两个物体都有碰撞组件,触发条件:两者具有碰撞组件,其中之一带有刚体组件,其中之一勾选 IsTrigger。

11.transform.forward /up / right 是表示的是自身Z轴/Y轴/X轴前1米(模长为1的向量)在世界坐标的位置,但原点在世界原点。不加在物体上没有任何意义。

12.Awake start update等方法注意事项:首先,在生命周期里的Awake等方法的实现机制是:生命周期方法的实现机制实际上是一种类反射机制。Uniy引擎整体是架设在mono IDE基础上的。mono IDE是支持通过string来查找方法的,且和真正的反射一样是能够查找调用私有方法的,当找到这些方法后会存下指针,待使用。在引擎内部存在一张表,这张表的形成是通过在场景中查找全部的MonoBehaviour

类型脚本然后便利里面的方法,将需要的调用的方法是全部记录下来,然后进行调用。防止那些不需要调用的MonoBehaviour中的方法占用空间,节省资源开耗。Mono的API可能效率更高,但对于单次调用,性能仍然逊于虚方法调用。反射实际上是开销非常大的调用方式,比之虚方法来说要高得多,因此Unity选择使用反射并非是出于性能方面的考虑。实际上,每帧调用的这些事件方法从数量级上来说是很卑微的,反射造成的性能影响亦可忽略不计。

 Unity使用这种事件机制的根本原因是出于对灵活性的考虑。Unity采用组件式设计,触发一个事件,需要通知到相应gameobject的所有组件。如果使用多态来实现,则必须假设所有组件都派生自包含此事件的基类,或者筛选出派生自此基类的组件逐一通知。这样一来是麻烦,二来则容易带来复杂的继承关系,与组件式这种倡导用聚合代替继承的设计从理念上就是相悖的。
另一方面的原因则是为了跟JS保持一致性。这种事件机制对于JS这种动态类型语言来说是浑然天成的。

这种设计最大的缺陷在于事件名通过字符串耦合,如此一来,完全绕开了编译期静态检查,无法为事件调用的正确性提供保障;在复杂的系统里,也可能因为事件重名而导致bug。

在Unity脚本中使用继承和普通的C#没有多大区别,只要在父类只继承MonoBehaviour就可以了,如果你将子类脚本贴到GameObject上,子类中如果有Awake,Start,Update等方法,将会覆盖父类中的这些方法,如果要掉用父类中的这些方法,可以使用base.Satrt(),base.Update().但是当子类没有覆盖写自己的对应方法时,就会调用父类的方法,原因:就是你脚本挂在gameobject上的时候,unity自已经new 了一个对象,并且根据上面已经说得反射机制,调用了父类的生命周期方法,如果父类也没有,就不会调用。

13.聊天的存储结构一般是循环队列。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值