Unity3D学习笔记(十):Physics类和射线
物理系统:碰撞器、触发器等
力:有大小有方向的矢量,有受力点位置(和向量的区别)
----F = ma(m质量,a加速度,质量越大,加速度越小,停下来越慢)
----m1v1 = m2v2(冲量守恒定理,质量越小,速度越快)
----力的分解
Ft = mv(动量定理)
----Rigid.AddForce(Vector3.forward, ForceMode mode);写在Start里
----Force(默认):持续力,完全满足动量守恒定理;Ft = mv
----Impulse:瞬间冲击力、爆炸力,不完全满足动量守恒定理;忽略t,让t = 1,F = mv
----VelocityChange:直接改变速度;忽略t和m,让t = m = 1,F =v
----Acceleration:给一个加速度;忽略m,让m = 1,Ft =v
力矩:作用力使物体绕着转动轴或支点转动的趋向。
----Rigid.AddTorque(Vector3.up);
练习:Dota2的选人面板,人物可以拖拽旋转,速度越来越快,反向拖动,转速大幅降低
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ForceTest : MonoBehaviour { public float forceFactor = 10; private Rigidbody rigid; private float mouse_x; // Use this for initialization void Start () { //力需要一个目标,只有非运动学刚体才会收到力的影响 rigid = GetComponent<Rigidbody>(); //力的单位1牛顿,质量0.1KG //ForceMode是枚举, //rigid.AddForce(Vector3.forward,ForceMode.Impulse); //rigid.AddForceAtPosition(Vector3.forward,new Vector3(1,1,1)); //rigid.AddTorque(Vector3.up); //最大旋转速度,限制物体旋转速度,可以修改 rigid.maxAngularVelocity = 999999; } // Update is called once per frame void Update () { //练习:Dota2的选人面板,人物可以拖拽旋转,速度越来越快,反向拖动,转速大幅降低 //按下鼠标左键拖动才会接收值 if (Input.GetMouseButton(0)) { mouse_x = Input.GetAxis("Mouse X"); } else { mouse_x = 0; } rigid.AddTorque(Vector3.up * -mouse_x * forceFactor, ForceMode.Force); //鼠标当前帧的位置可以获取,和上一帧相减,可以得到一个旋转的偏移量 //Input.mousePosition } }
力给在物体重心上
rigid.AddForce(Vector3.forward,ForceMode.Impulse);
选一个受力点,添加一个力,可以让物体旋转起来
rigid.AddForceAtPosition(Vector3.forward,new Vector3(1,1,1));
Physics - Gravity,方向向下的重力
![](https://img2018.cnblogs.com/blog/1517599/201902/1517599-20190211190944950-2100353081.png)
ForceMode是枚举
直线:向两端无限延长的直的线,没有端点
线段:两个点之间的直线,两个端点
射线:由一个点向一个方向发射一条无限延长的直线,一个端点
Unity如何判断前方扇形面积有敌人
Ray Unity中的射线(结构体),有两个参数,origin原点,direction方向
射线检测的唯一条件:游戏物体必须有碰撞器组件,有没有刚体无所谓
layerMask层级遮罩,设置只检查哪一个层级的游戏物体,默认全部检测
RaycastHit hitInfo是碰撞信息
bool : Physics.Raycast(Ray ray, float maxDistance, int layerMask, QueryTriggerInteraction queryTriggerInteraction);
RaycastHit[] hitinfos = Physics.RaycastAll();
using System.Collections; using System.Collections.Generic; using UnityEngine; public class RaycastTest : MonoBehaviour { private Ray ray; private RaycastHit hitInfo; // Use this for initialization void Start () { //层级位移运算 int layerMask = (1 << 8); Debug.Log(layerMask); layerMask = (1 << 9); Debug.Log(layerMask); layerMask = (1 << 8) | (1 << 9); Debug.Log(layerMask); layerMask = LayerMask.GetMask(new string[] { "Lxm", "Cjy" }); Debug.Log(layerMask); //结果第8位,第9位 //Ray(Vector3 origin, Vector3 direction); //Ray射线是结构体,有两个参数,origin原点,direction方向 ray = new Ray(transform.position,Vector3.forward); //发射射线,物理系统的光线投射,有16种重载 //Physics.Raycast(ray); //射线是没有网格的,是看不到,是物理系统的一部分,是数学计算得来的 if (Physics.Raycast(ray)) { Debug.Log("射线已射中物体"); } //maxDistance射线的最大距离就是float的最大值,可以手动设置 //Raycast(Ray ray, float maxDistance); //hitinfo:这条射线所碰撞物体的相关信息,储存碰撞物体的信息; //Raycast(Ray ray, out RaycastHit hitInfo); if (Physics.Raycast(ray, out hitInfo, 100, layerMask, QueryTriggerInteraction.Ignore)) { Debug.Log(hitInfo.transform.name); Debug.DrawLine(transform.position, hitInfo.point,Color.red,100); } //层级遮罩,设置只检查哪一个层级的游戏物体,默认全部检测 //层级实质相当于枚举项,值是2的幂次方,序号只是层级的索引 //Raycast(Ray ray, float maxDistance, int layerMask); //如果检测第八层,需要填写256 if (Physics.Raycast(ray, collider.gameObject.tag, 256)) { Debug.Log(hitInfo.transform.name); Debug.DrawLine(transform.position, hitInfo.point, Color.red, 100); } //Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask); //Ray ray是射线;RaycastHit hitInfo是碰撞信息;float distance是碰撞距离;int layerMask是碰撞的层 //RaycastAll穿过多个物体 RaycastHit[] hitinfos = Physics.RaycastAll(ray,100); foreach (var item in hitinfos) { Debug.Log(item.transform.name); } //不仅发射摄像,还可以发射形状物体 //Physics.BoxCast(); //Physics.CapsuleCast(); //如何检测一个人在地面上而不是在空中(二段跳判定) //1、在人物半身添加一个向下的射线,射线刚好接触地面 //2、在人物头顶添加一个投射盒 //特点: //射线是一帧判定 //射线没有运行时间 //位运算符(二进制的加减乘除) //&与运算:有零即为零,全一才是一 //1001010 //1000111 & //----------- //1000010 //|或运算:有一就是一,全零才是零 //1001010 //1110001 | //----------- //1111011 //~非运算符:一变零,零变一 //1101010 ~ //----------- //1111011 //^异或运算:相同即为零,不同即为一 //1010001 //1100010 ^ //----------- //0110011 //<<向左移:所有二进制位向高位进位,空出来的位补零 //1010<<1 //----------- //10100 //>>向右移:所有二进制位向低位进位,移出位被丢弃,左边移出的空位或者一律补0 //1011>>1 //----------- //0101 } // Update is called once per frame void Update () { } }
相交球:
Collider[] OverlapSphere(Vector3 position, float radius);
using System.Collections; using System.Collections.Generic; using UnityEngine; public class BoomScript : MonoBehaviour { public float forceFactor = 10; private void OnCollisionEnter(Collision collision) { //生成橡胶球,检测碰撞 Collider[] colliders = Physics.OverlapSphere(transform.position, 10); //剔除自己和没有加刚体的 foreach (var item in colliders) { //剔除自己 if (item.transform == transform) { continue; } //判断刚体不等于空,防止与地面碰撞 //attachedRigidbody,碰撞器附加的刚体,如果碰撞器没有附加刚体返回null。 if (item.attachedRigidbody != null) { float distance = Vector3.Distance(transform.position, item.transform.position); float forceValue = 1 / distance * forceFactor; Vector3 dir = (item.transform.position - transform.position).normalized; Vector3 force = dir * forceValue; item.attachedRigidbody.AddForce(force, ForceMode.Impulse); } } } }
Line Renderer
线体渲染,添加颜色,Line Renderer 配合 ray射线 可以制作镭射激光
用材质球渲染射线,粒子特效
Width曲线,调节粗细,添加关键帧,调节线体不同部位的粗细
画复杂线段,多点添加
设置颜色的渐变
![](https://img2018.cnblogs.com/blog/1517599/201902/1517599-20190211191055996-295584444.png)
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerFire : MonoBehaviour { LineRenderer lineR; public Transform fireTrans; //方便对layer作调节 public LayerMask layer; Ray ray; RaycastHit hit; void Start () { lineR = GetComponent<LineRenderer>(); } void Update () { ray = new Ray(fireTrans.position, fireTrans.up); if(Physics.Raycast(ray, out hit, 1000, layer)) { //hit.point lineR.positionCount = 2; lineR.SetPosition(0, fireTrans.position); lineR.SetPosition(1, hit.point); } else { lineR.positionCount = 0; } } }
C#的委托和事件在Unity中的用法
委托 - Action:没有返回值,没有参数的,在using System命名空间下
带一个参数,没有返回值的委托怎么定义,public Action<float> OnValueChanged
委托变事件,直接加event
通过滑动条Value的变化,来调用委托
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public class DeleTest : MonoBehaviour { public float width = 100; public float height = 50; public event Action buttonClickCallback; public event Action<float> OnValueChanged; // 事件 用来封装委托的 private float floatValue; public float FloatValue { get { return floatValue; } set { if (value != floatValue) { // 触发事件 if (OnValueChanged != null) OnValueChanged(value); } floatValue = value; } } public float size = 1; public GUIStyle sliderStyle; public GUIStyle thumbStyle; void Start() { FloatValue = 100; } void Update() { } private void OnGUI() { if (GUI.Button(new Rect((Screen.width - width) / 2, (Screen.height - height) / 2, width, height), "开始游戏")) { if (buttonClickCallback != null) buttonClickCallback(); } // public static float Slider(Rect position, float value, float size, float start, float end, GUIStyle slider, GUIStyle thumb, bool horiz, int id); //value = GUI.Slider(new Rect(10, 10, width, height), value, size, 0, 10, sliderStyle, thumbStyle, true, 0); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Test : MonoBehaviour { void Awake () { DeleTest del = GetComponent<DeleTest>(); del.buttonClickCallback += SceneChange; del.OnValueChanged += MusicValueChange; //del.OnValueChanged(); } void Update () { } void SceneChange() { Debug.Log("切换场景啦!!!!"); } void MusicValueChange(float value) { Debug.Log("音量调节为了:" +value); } }