射线的机制相当于碰撞;
创建射线:
1 Ray ray=new Ray();
origin : 射线发射的原点;
direction: 射线发射的方向;
distance: 射线的长度;
hitInfo: 如果返回true,hitInfo将包含碰撞器碰撞的更多信息;
Layer: gameObject的层;
LayerMask: 只选定LayerMask层内的碰撞器,其他层内碰撞器忽略;返回bool类型,当射线与任何碰撞器碰撞时为真,反之为假;
射线碰撞的应用:
使用Physics类方法Raycast方法实现射线碰撞检测功能;
射线的添加方法:
1 bool Raycast(Ray ray,out RaycastHit hitInfo); // Ray ray是要发射的射线, hitInfo是碰撞信息; 2 // 从主摄像头到鼠标点击位置创建一条射线; 3 Ray ray=Camera.main.ScreenPiontToRay(Input.mousePosition);
实际运用如代码所示:
1 using Sysytem.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 public class RayScript:MonoBehaviour{ 5 public float speed; // 外联速度值 6 7 Ray ray; // 射线 8 RaycastHit hit; // 射线的碰撞信息 9 LayerMask mask; // 用来接收LayerMask的value值; 10 void Start(){ 11 // 1<<10打开第10层,当前射线只能检测到第十层上的碰撞体; 12 // ~(1<<10)打开除10层以外的所有层; 13 //~(1<<0)打开所以层, 或者不写LayerMask; 14 // (1<<8)|(1<<10) 同时打开第8层和第10层; 15 mask = ~(1 << LayerMask.NameToLayer ("Cube")); 16 } 17 void Update(){ 18 CubeMove(); // 调用CubeMove的方法 19 20 // 从自身位置发射射线; 21 // 发射一条射线,返回检测到的第一个物体;返回值为bool; 22 ray=new Ray(transform.position,transform.forward); 23 if(Physics.Raycast(ray,out hit,10)){ 24 // 给射线添加颜色,只能在scene场景中显示,game场景中不会显示; 25 // 因为没有没有添加刚体,所以这里用collider来获取碰撞位置; 26 Debug.DrawLine(transform.position,hit.collider.transform.position,Color.red); //碰撞物体中心的位置; 27 // Debug.DrawLine(transform.position,hit.point,Color.red); // point是射线碰撞点的位置; 28 29 // 可以用Debug来调试看看 本方法是否运行; 30 Debug.Log("调试"); 31 } 32 // 33 #region 34 // 35 // 得到射线范围内的所有游戏物体; 36 //返回的是一个游戏物体的数组;所以定义一个数组来接收得到的游戏物体; 37 RaycastHit[] hits=Physics.RaycastAll(ray,10); // 这里代入的参数为射线和射线的距离; 38 if(hits.Length>0){ 39 // 打印,检查是否运行了次方法; 40 41 Debug.Log(hits.Length); 42 } 43 #endregion 44 45 // 46 #region 47 // 48 // 一般我们采用摄像头来发射线; 49 if (Input.GetMouseButtonDown(0)) { 50 //屏幕坐标转换成射线位置; 51 Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition); 52 if (Physics.Raycast (ray, out hit)) { 53 // 缓动 Lerp 54 transform.position = Vector3.Lerp (transform.position, hit.point, Time.deltaTime); 55 } 56 } 57 Ray ray2 = new Ray (transform.position, transform.forward); 58 // 通过LayerMask.NameToLayer方法 来找寻 层名为 "Cube"的层数,打开第N值,射线只能检查到这一层; 59 LayerMask mask = 1 << (LayerMask.NameToLayer ("Cube")); 60 if (Physics.Raycast (ray2, out hit, 100,mask.value)) { 61 Debug.Log (hit.collider.gameObject.name); 62 } 63 #endregion 64 } 65 void CubeMove(){ 66 float hor = Input.GetAxis ("Horizontal"); 67 float ver = Input.GetAxis ("Vertical"); 68 // transform.position += transform.forward * Time.deltaTime * ver * speed; 69 // transform.position += transform.right * Time.deltaTime * hor * speed; 70 // 恒等于 71 transform.position += (transform.forward * ver + transform.right * hor) * speed * Time.deltaTime; 72 }
在Unity中每个GameObject都有Layer属性, Layer一共有32层,0-7层,默认不可以编译,并且不能增加层数;
GameObject的Layers(层):
Layers通常用来被摄像机用来渲染部分场景,和灯光照射部分场景使用, 可以用来做射线检测时忽略一些collider或者CCollision时使用;
编辑Layers:
如果Layers处于开启状态那么就能通过Layers找寻到GameObject;
开启方法:
1 LayerMask mask=1<< 你需要开启的Layers层;
如果Layers处于关闭状态那么就可以在进行射线检测的时候忽略掉;
关闭方法:
1 LayerMask mask=0<<你需要关闭的Layers层; 2 或者 3 LayerMask mask=~(1<<你需要开启的Layers层); // ~表示取反
例如:
1 LayerMask mask = 1 << 2; 表示开启Layer2; 2 LayerMask mask = 0 << 5;表示关闭Layer5; // 恒等于 LayerMask mask=~(1<<5); 3 LayerMask mask = 1<<2|1<<8;表示开启Layer2和Layer8; 4 LayerMask mask = 0<<3|0<<7;表示关闭Layer3和Layer7; // 恒等于 LayerMask mask=~(1<<7);
实战:
场景中创建N(两个以上)个物体,鼠标可以选中任何物体,当鼠标选中为非地面时,选中的物体变为红色,之前选中的物体恢复为之前的颜色,鼠标点击到地面时,让之前选中的那个物体移动的当前点击的位置;
分析: 在场景中创建一块地板,几个游戏物体,这样采用摄像头发射射线
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 public class GameScript : MonoBehaviour { 6 7 private GameObject selectedGameObject; // 用来记录点中的物体 8 private bool flag; // 标记当前是否选中了地面 9 private Color seletedColor; // 记录当前选中物体的颜色; 10 private RaycastHit hit; // 碰撞信息; 11 12 void Update () { 13 14 15 if (Input.GetMouseButtonDown (0)) { 16 // 从摄像头发射一条经过鼠标点击屏幕的点的射线,如果射线碰撞到碰撞体该方法返回true,否则false; 17 if (Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hit)) { 18 // 判断鼠标是否点击到地面 19 if (hit.collider.name == "Plane") { 20 flag = true; 21 22 } else { 23 24 flag = false; 25 26 // 判断是否选中物体 27 if (selectedGameObject) { 28 29 // 将前一个旋转的物体颜色恢复为原来的颜色; 30 selectedGameObject.GetComponent<MeshRenderer> ().material.color = seletedColor; 31 } 32 // 更新选中的物体; 33 selectedGameObject = hit.collider.gameObject; 34 seletedColor = selectedGameObject.GetComponent<MeshRenderer> ().material.color; 35 36 selectedGameObject.GetComponent<MeshRenderer> ().material.color = Color.red; 37 } 38 } 39 40 } 41 if (flag && selectedGameObject) { // 当这一次鼠标选择地面,并且被选中物体存在; 42 43 Move (hit.point); 44 } 45 } 46 47 48 void Move(Vector3 distination){ 49 // 判断两者之间的距离 50 if (Vector3.Distance(selectedGameObject.transform.position,distination) <= 0.01f) { 51 52 selectedGameObject.transform.position = distination; 53 } else { 54 55 // 不希望在Y轴上下移动 56 57 Vector3 pos = selectedGameObject.transform.position; // 自身的位置; 58 59 pos = Vector3.Lerp (selectedGameObject.transform.position, distination, Time.deltaTime); 60 61 // 限制Y轴移动 62 selectedGameObject.transform.position = new Vector3 (pos.x, selectedGameObject.transform.position.y, 63 pos.z); 64 65 } 66 } 67 }