目录
第二题→在Game窗口长按鼠标左键用LineRenderer画出鼠标移动的轨迹
关于rigidbody的Is Trigger 和Is Kinematic 的理解->
这周刷了几道双指针题,在洛谷上写了点暴搜题,准备蓝桥杯
LineRenderer代码控制相关
private Material m;
//动态添加一个线段 GameObject line = new GameObject();
line.name = "Line";
LineRenderer lineRenderer = line.AddComponent();
//首尾相连 lineRenderer.loop = true;
//开始结束宽 lineRenderer.startWidth = 0.02f; lineRenderer.endWidth = 0.02f;
//开始结束颜色 lineRenderer.startColor = Color.white; lineRenderer.endColor = Color.red;
//设置材质 m = Resources.Load("M"); lineRenderer.material = m;
//设置点
//一定注意 设置点 要 先设置点的个数
lineRenderer.positionCount = 4;
//接着就设置 对应每个点的位置
lineRenderer.SetPositions(new Vector3[] { new Vector3(0,0,0), new Vector3(0,0,5), new Vector3(5,0,5)});
lineRenderer.SetPosition(3, new Vector3(5, 0, 0));
//是否使用世界坐标系 //决定了 是否随对象移动而移动
lineRenderer.useWorldSpace = false;
//让线段受光影响 会接受光数据 进行着色器计算
lineRenderer.generateLightingData = true;
LineRenderer练习题
第一题:写一个函数,传入一个圆的中心点和半径,用LineRenderer画出一个圆
运用知识点→3D数学,
点加向量,等于让这个点朝向量的方向平移向量的模长
四元数乘以向量→相当于旋转这个向量
void Start()
{
DrawCircle(new Vector3(0, 0, 0), 5);
}
public void DrawCircle(Vector3 Center,float r)
{
GameObject obj = new GameObject();
obj.name = "Circle";
LineRenderer lineRenderer = obj.AddComponent<LineRenderer>();
lineRenderer.positionCount = 360;
lineRenderer.loop = true;
for(int i = 0; i < 360; i++)
{
lineRenderer.SetPosition(i,Center+ (Quaternion.AngleAxis(i, Vector3.up))*transform.forward*r);
}
}
第二题→在Game窗口长按鼠标左键用LineRenderer画出鼠标移动的轨迹
挂载到摄像机上->
LineRenderer lr;
void Start()
{
lr = this.gameObject.AddComponent<LineRenderer>();
lr.startWidth = 0.1f;
lr.endWidth = 0.1f;
lr.loop = false;
lr.positionCount = 0;
}
private void Update()
{
if(Input.GetMouseButton(0))
{
lr.positionCount += 1;
Vector3 curPos = Input.mousePosition; //鼠标坐标是二维的
curPos.z = 10;
lr.SetPosition(lr.positionCount - 1, Camera.main.ScreenToWorldPoint(curPos));
}
}
}
物理系统范围检测
必备条件:想要被范围检测到的对象 必须具备碰撞器
注意点:
1.范围检测相关API 只有当执行该句代码时 进行一次范围检测 它是瞬时的
2.范围检测相关API 并不会真正产生一个碰撞器 只是碰撞判断计算而已
1.盒状范围检测
参数一:立方体中心点
参数二:立方体三边大小
参数三:立方体角度
参数四:检测指定层级(不填检测所有层)
参数五:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal
返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)
Collider[] colliders = Physics.OverlapBox( Vector3.zero, Vector3.one, Quaternion.AngleAxis(45, Vector3.up),
1 << LayerMask.NameToLayer("UI") |
1 << LayerMask.NameToLayer("Default"), QueryTriggerInteraction.UseGlobal);
指定检测的层级是以二进制的每一位代表一层,所以层级最多可以有32层,NameToLayer能够获取对应名字的层级数字,然后让1左移就可以得到对应层级的独一无二的二进制数,在unity内部它会根据我们参数的结果,用结果 & 上每一个层级对应的二进制数,如果返回1则说明要检测该层,否则不检测
拿上面传入的举例,如果UI在第4层(对应十进制16),Default在第0层(对应十进制1),则他们 或 的结果就是0001 0001
然后编辑器内部就会根据0001 0001 来 & 上每个二进制数 , 比如他&上第0层,得到0000 0001,返回1,说明要检测该层, 再&上第四层得到 0001 0000 返回非0,检测该层 ,因为& 上其它层级全部为0,所以其它层级不进行范围检测
根据返回值,我们就可以得到所有检测到的碰撞体的信息,通过遍历的方式
for (int i = 0; i < colliders.Length; i++)
{
print(colliders[i].gameObject.name);
}
盒状范围检测还有一个API返回碰撞到的数量
另一个API
返回值:碰撞到的碰撞器数量
参数:传入一个数组进行存储
Physics.OverlapBoxNonAlloc()
if (Physics.OverlapBoxNonAlloc(Vector3.zero, Vector3.one, colliders) != 0)
{
}
2.球形范围检测
参数一:中心点
参数二:球半径
参数三:检测指定层级(不填检测所有层)
参数四:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal
返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)
colliders = Physics.OverlapSphere(Vector3.zero, 5, 1 << LayerMask.NameToLayer("Default"));
另一个API
返回值:碰撞到的碰撞器数量
参数:传入一个数组进行存储
Physics.OverlapSphereNonAlloc
if (Physics.OverlapSphereNonAlloc(Vector3.zero, 5, colliders) != 0)
{
}
3.胶囊范围检测
参数一:半圆一中心点 参数二:半圆二中心点 参数三:半圆半径 参数四:检测指定层级(不填检测所有层) 参数五:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal 返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息) colliders = Physics.OverlapCapsule(Vector3.zero, Vector3.up, 1, 1 << LayerMask.NameToLayer("UI"), QueryTriggerInteraction.UseGlobal);
另一个API
返回值:碰撞到的碰撞器数量
参数:传入一个数组进行存储
Physics.OverlapCapsuleNonAlloc
if (Physics.OverlapCapsuleNonAlloc(Vector3.zero, Vector3.up, 1, colliders) != 0)
{
}
物理系统射线检测
首先需要声明一条射线→
Ray r3 = new Ray(Vector3.zero, Vector3.forward);
参数1是射线的起点,参数二是方向
r3.origin 获取起点
r3.direction 获取方向
2.摄像机发射出的射线
得到一条从屏幕位置作为起点
摄像机视口方向为 方向的射线
Ray r2 = Camera.main.ScreenPointToRay(Input.mousePosition);
射线检测
进行射线检测 如果碰撞到对象 返回true
参数一:射线 参数二: 检测的最大距离 超出这个距离不检测 参数三:检测指定层级(不填检测所有层) 参数四:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal 返回值:bool 当碰撞到对象时 返回 true 没有 返回false
Ray r3 = new Ray(Vector3.zero, Vector3.forward);
if (Physics.Raycast(r3, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
print("碰撞到了对象");
}
**还有一种重载** 不用传入 射线 直接传入起点 和 方向 也可以用于判断
就是把 第一个参数射线 变成了 射线的 两个点 一个起点 一个方向
if (Physics.Raycast(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
print("碰撞到了对象2");
}
得到检测到的信息的API→
2.获取相交的单个物体信息
物体信息类 RaycastHit
RaycastHit hitInfo;
参数一:射线
参数二:RaycastHit是结构体 是值类型 Unity会通过out 关键字 在函数内部处理后 得到碰撞数据后返回到该参数中
参数三:距离
参数四:检测指定层级(不填检测所有层)
参数五:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal
if (Physics.Raycast(r3, out hitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
print("碰撞到了物体 得到了信息");
碰撞器信息
print("碰撞到物体的名字" + hitInfo.collider.gameObject.name);
碰撞到的点
print(hitInfo.point);
法线信息
print(hitInfo.normal);
得到碰撞到对象的位置
print(hitInfo.transform.position);
得到碰撞到对象 离自己的距离
print(hitInfo.distance);
RaycastHit 该类 对于我们的意义
它不仅可以得到我们碰撞到的对象信息
还可以得到一些 碰撞的点 距离 法线等等的信息
}
还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
if (Physics.Raycast(Vector3.zero, Vector3.forward, out hitInfo, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal))
{
}
3.获取相交的多个物体
可以得到碰撞到的多个对象
如果没有 就是容量为0的数组
参数一:射线
参数二:能检测的最大距离
参数三:检测指定层级(不填检测所有层)
参数四:是否忽略触发器 UseGlobal-使用全局设置 Collide - 检测触发器 Ignore - 忽略触发器 不填使用UseGlobal
RaycastHit[] **hits** = Physics.RaycastAll(r3, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal);
for (int i = 0; i < hits.Length; i++)
{
print("碰到的所有物体 名字分别是" + hits[i].collider.gameObject.name);
}
还有一种重载 不用传入 射线 直接传入起点 和 方向 也可以用于判断
之前的参数一射线 通过两个点传入
hits = Physics.RaycastAll(Vector3.zero, Vector3.forward, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal);
还有一种函数 返回的碰撞的数量 通过out得到数据
if (Physics.RaycastNonAlloc(r3, **hits**, 1000, 1 << LayerMask.NameToLayer("Monster"), QueryTriggerInteraction.UseGlobal) > 0) //参数二是RaycastHit类型的数组
{
}
练习→在一面墙上点击哪,就生成子弹特效(异步加载资源实现)
void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 100))
{
ResourceRequest rq = Resources.LoadAsync<GameObject>("EffBullet/HitEff");
ResourceRequest rq1 = Resources.LoadAsync<GameObject>("EffBullet/DDD");
rq.completed += (t) =>
{
GameObject obj = (t as ResourceRequest).asset as GameObject;
GameObject dex = Instantiate(obj, hit.point, Quaternion.identity);
Destroy(dex, 2);
};
rq1.completed += (t) =>
{
GameObject obj = (t as ResourceRequest).asset as GameObject;
GameObject dex = Instantiate(obj, hit.point + hit.normal * 0.5f, Quaternion.identity);
Destroy(dex, 2);
};
print("触发检测");
}
}
}