以下均为来自中国大学mooc 游戏引擎原理及应用时的学习笔记,不含商用,仅供学习交流使用,如果侵权请联系作者删除。


文章目录

  • 7.1 物理引擎基础
  • 7.2 典型效果模拟
  • 7.3 链接结构
  • 7.4 碰撞检测
  • 7.5 浮力效果


7.1 物理引擎基础

unity 引擎 结构 图 unity引擎教程_游戏


unity 引擎 结构 图 unity引擎教程_游戏_02


unity 引擎 结构 图 unity引擎教程_游戏开发_03


unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_04


unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_05


unity 引擎 结构 图 unity引擎教程_游戏_06


unity 引擎 结构 图 unity引擎教程_游戏开发_07


unity 引擎 结构 图 unity引擎教程_游戏开发_08


unity 引擎 结构 图 unity引擎教程_游戏_09


为小球添加刚体组件即可使得小球具有刚体属性

这时候把小球放到空中会掉下来

但是并不会反弹 是因为地面不具有物理材质

为了让地面具有物理材质,我们可以这样:

unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_10


创建一个物理材质并使得其具有弹性

然后将其拖拽给plane中mesh collider

unity 引擎 结构 图 unity引擎教程_unity_11


unity 引擎 结构 图 unity引擎教程_游戏_12


这个方法可以给小球添加一个恒力

relative代表的是相对小球的局部空间

7.2 典型效果模拟

unity 引擎 结构 图 unity引擎教程_游戏开发_13


unity 引擎 结构 图 unity引擎教程_unity_14


unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_15


unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_16


unity 引擎 结构 图 unity引擎教程_游戏_17


unity 引擎 结构 图 unity引擎教程_unity_18


unity 引擎 结构 图 unity引擎教程_游戏开发_19


unity 引擎 结构 图 unity引擎教程_unity_20


模拟子弹:

var关键字
var 是3.5新出的一个定义变量的类型 其实也就是弱化类型的定义 VAR可代替任何类型 编译器会根据上下文来判断你到底是想用什么类型的 至于什么情况下用到VAR 我想就是你无法确定自己将用的是什么类型 就可以使用VAR 类似 OBJECT 但是效率比OBJECT高点。

首先我们将小球变成预制件,为其添加刚体和恒力的组件
然后编写以下代码

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

public class bulltetshoot : MonoBehaviour
{
    public GameObject bullet;
    static float presstime = 0f;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetButton("Fire1"))
        {
            presstime += Time.deltaTime;
        }
        if (Input.GetButtonUp("Fire1"))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            GameObject b = Instantiate(bullet, ray.origin, Quaternion.LookRotation(ray.direction)) as GameObject;//这个函数可以把预制件实例化,参数分别是预制件,位置,方向
            var cf = b.GetComponent<ConstantForce>().relativeForce = new Vector3(0, 0, presstime * 10);//var为任意类型的变量
            presstime = 0;
        }
    }
}qi

之后将这个组件拖拽给摄像机 (其实不拖拽给摄像机也没有关系 因为脚本中自带着去获取了以主相机视角发出来的射线的)然后在把预制件托给这个物体

unity 引擎 结构 图 unity引擎教程_unity_21


之后便可以模拟出发射子弹的效果

unity 引擎 结构 图 unity引擎教程_unity_22

7.3 链接结构

unity 引擎 结构 图 unity引擎教程_unity3d_23


unity 引擎 结构 图 unity引擎教程_unity3d_24

球窝类型

unity 引擎 结构 图 unity引擎教程_unity_25


门扇类型

unity 引擎 结构 图 unity引擎教程_游戏_26


固定类型

unity 引擎 结构 图 unity引擎教程_游戏开发_27


unity 引擎 结构 图 unity引擎教程_游戏_28


unity 引擎 结构 图 unity引擎教程_unity_29


unity中实现:

我们创建一个空物体,然后为其添加hinge joint组件,此时会自动添加rigid body组件

unity 引擎 结构 图 unity引擎教程_unity3d_30


unity 引擎 结构 图 unity引擎教程_unity3d_31

可以通过调整这个anchor来调整锚定点的位置,这个箭头表示旋转轴的方向和正方向

我们创建一个新物体,并且把那个锚点定位方块的旋转轴

unity 引擎 结构 图 unity引擎教程_游戏_32

为了让物体不发生移动,我们把空物体的is kinematic给点上

unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_33


接下来我们给这个物体添加上刚体的属性

然后把它拖拽给空物体的hinge组件上面,意思就是让它们链接起来了

此时运行游戏可以看到这个物体动起来了

unity 引擎 结构 图 unity引擎教程_游戏开发_34


unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_35

我们在创建一个空物体,然后给他挂接一个Spring joint组件,是弹簧连接

unity 引擎 结构 图 unity引擎教程_unity3d_36


然后会发现这个物体像弹簧一样在动

unity 引擎 结构 图 unity引擎教程_游戏_37


这个连接是可以被破坏的这个limits代表的是当力或者力矩达到这个值的时候就会被破坏

unity 引擎 结构 图 unity引擎教程_unity3d_38


此时我们调整这个 然后发射子弹 当蓄力到一定程度,便可把这个力矩给打烂

有时候当我们破坏了物体 我们需要知道这个信息,因此我们写一个函数,将这个函数拖拽给两个空物体

private void OnJointBreak(float breakForce)
    {
        Debug.Log("you destroied " + name + " with a force of" + breakForce + "N");
        
    }

当我们破坏地时候 就会在右下角出现信息

7.4 碰撞检测

unity 引擎 结构 图 unity引擎教程_unity_39

unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_40


对于这种静态碰撞体可以利用预计算来计算它们跟其他物体的碰撞结果

常常运用于房屋 树木这种不可移动的物体

unity 引擎 结构 图 unity引擎教程_游戏_41

触发器碰撞比如说计算浮力

unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_42


刚体和刚体 刚体和静态物体 刚体和运动学物体是可以进行碰撞的检测的

unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_43


这些是可以当作触发器的在unity中 物体都有碰撞体积

unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_44


unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_45


在右边的这里可以调整碰撞体积当我们给它点上这个的时候

unity 引擎 结构 图 unity引擎教程_游戏开发_46


它的行为就会变成一个触发器类型碰撞函数:

unity 引擎 结构 图 unity引擎教程_游戏开发_47


上面那个函数处理普通的碰撞类型事件

下面那个函数处理触发器的碰撞类型事件

发生碰撞的 至少需要有一个是刚体

我们建立这样的一个场景

unity 引擎 结构 图 unity引擎教程_游戏开发_48


其中 粉色墙壁是触发器 而其他墙壁是普通刚体

我们给粉色墙壁和其他墙壁都附上下面这段脚本

private void OnCollisionEnter(UnityEngine.Collision collision)
    {
        if (collision.gameObject.tag == "Bullet")
        {
            Destroy(collision.gameObject);//销毁碰撞的物体
        }

    }
    private void OnTriggerEnter(Collider other)//触发器碰撞
    {
        var rb = other.GetComponent<Rigidbody>();
        if (rb != null)
        {
            rb.useGravity = false;//消除重力
        }
    }

当我们射出子弹的时候 如果碰到粉色墙壁则会失去重力 碰到其他墙壁则这个物体会消失

unity 引擎 结构 图 unity引擎教程_游戏_49


添加tag的方法在这里

7.5 浮力效果

unity 引擎 结构 图 unity引擎教程_unity 引擎 结构 图_50

首先创建一个如图所示的地形 水用cube+材质来替代(standard assest中有水的材质

unity 引擎 结构 图 unity引擎教程_游戏_51

我们写出以下代码:首先是挂接在水上的脚本:
对水来说思路很简单,只需要写出当物体与水发生触发器类型的碰撞以及离开的时候 给含有float脚本的组件设置其状态:处于水的状态和离开水的状态

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

public class water : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.GetComponent<floater>())
        {
            other.gameObject.GetComponent<floater>().SetIsInWater(true);
    
        }
    }
    private void OnTriggerExit(Collider other)
    {
        if (other.gameObject.GetComponent<floater>())
        {
            other.gameObject.GetComponent<floater>().SetIsInWater(false);

        }
    }
}

挂接在漂浮的物体上的脚本:

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

public class floater : MonoBehaviour
{
    private bool isInwater;
    private GameObject water;
    private float waterY;
    private const float floatageForce= 0;
    private const float density = 1;//密度
    private const float g = 9.8f;
    private const float waterDrag = 5;//这类似阻尼,我们给物体在运动时添加一个阻力

    // Start is called before the first frame update
    void Start()
    {
        isInwater = false;
        water = GameObject.FindWithTag("Water");//我们搜寻场景中含有Water这个tag的物体
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    private void FixedUpdate()//由于是一个物理现象,最好使用fixupdate来实现物理现象的函数
    {
        if (isInwater)
        {
            calFloatage();
            GetComponent<Rigidbody>().drag = waterDrag;//
        }
    }
    void calFloatage()
    {
        waterY = water.transform.position.y+water.transform.localScale.y/2;//获得水面最高处的坐标
        //if (waterY > (transform.position.y - transform.localScale.y))//transform.position.y - transform.localScale.y这个是
        if(isInwater)
        {
            float h = waterY - (transform.position.y - transform.localScale.y / 2) > transform.localScale.y ?
                transform.localScale.y : waterY - (transform.position.y - transform.localScale.y / 2);//如果物体全部沉到水中和只沉了一部分的情况
            float floatageForce = density * g * transform.localScale.x * transform.localScale.z * h;//计算浮力
            GetComponent<Rigidbody>().AddForce(0, floatageForce, 0);//给这个物体添加浮力
        }
    }
    public void SetIsInWater(bool inWater)
    {
        isInwater = inWater;
    }
    /*public bool GetIsInWater()
    {
        return isInwater;
    }*/
}

然后给物块添加刚体属性 给水添加触发器属性

最终成果如图

unity 引擎 结构 图 unity引擎教程_游戏_52