2.6 物理碰撞
现在的游戏虽然有主角、敌人,也可以发射子弹,但主角和敌人却没有任何交互。接下来,我们将分别给主角、子弹和敌人添加碰撞体,并添加触发碰撞的代码,使其在碰撞的时候产生交互。
2.6.1 添加碰撞体
步骤 01 我们先给敌人添加碰撞体。在场景中选择任意一个敌人,在菜单栏中选择【Component】→【Physics】→【Box Collider】,为敌人添加一个立方体碰撞体组件,然后在Inspector窗口中找到【Box Collider】组件,选中【Is Trigger】复选框,使其具有触发作用,如图2-24所示。
图2-24 立方体碰撞体选项
步骤 02 在菜单栏中选择【Component】→【Physics】→【Rigidbody】,为敌人添加一个刚体组件,所有需要参与物理计算的游戏体都需要有一个刚体组件才能正常工作。在Inspector窗口中找到【Rigidbody】组件,取消选择【Use Gravity】复选框去掉重力影响,选中【Is Kinematic】复选框,使游戏体的运动不受物理模拟影响,如图2-25所示。
图2-25 刚体选项
步骤 03 现在,我们已经为场景中的一个敌人添加并设置了相关的物理组件,确定其处于选择状态,在Inspector窗口的右下角单击【Apply】按钮,如图2-26所示,原始敌人的Prefab及场景中的其他敌人会自动更新到当前敌人的设置。
图2-26 Prefab选项
提示
如果是在Project窗口修改原始敌人Prefab的设置,场景中的敌人游戏体会自动更新与Prefab一致。
步骤 04 参考前面的步骤为主角和子弹添加物理组件,如图2-27所示。
图2-27 立方体碰撞框
2.6.2 触发碰撞
我们已经为主角、子弹和敌人添加了碰撞体,但还是看不到任何互动效果,我们将为它们分别指定一个Tag标识,然后添加触发碰撞事件的代码。
步骤 01 在菜单栏中选择【Edit】→【Project Settings】→【Tags and Layers】,单击“+”号创建新的Tag,命名为PlayerRocket和Enemy,如图2-28所示。
图2-28 添加Tag
步骤 02 在Project窗口中选择敌人的Prefab,在Inspector窗口中设置Tag为Enemy,如图2-29所示。
图2-29 设置敌人的Tag
步骤 03 选择子弹的Prefab,设置它的Tag为PlayerRocket。
步骤 04 选择主角,设置它的Tag为Player,这个Tag是Unity预设在工程内的。
步骤 05 打开Enemy.cs脚本,添加一个生命属性:
public float m_life = 10;
步骤 06 在Enemy脚本中添加一个OnTriggerEnter函数,这是一个重载自MonoBehaviour的回调函数,在碰撞体互相接触时会被触发,如下所示:
void OnTriggerEnter(Collider other) { if(other.tag.CompareTo("PlayerRocket")==0) // 如果撞到主角子弹 { Rocket rocket=other.GetComponent<Rocket>(); // 获得子弹上的Rocket脚本组件 if (rocket ! = null) { m_life-=rocket.m_power; // 减少生命 if (m_life <= 0) { Destroy(this.gameObject); // 自我销毁 } } } else if(other.tag.CompareTo("Player")==0) // 如果撞到主角 { m_life = 0; Destroy(this.gameObject); // 自我销毁 } }
① other.tag.CompareTo( "PlayerRocket" ) == 0语句用来比较字符串,判断遇到的碰撞体是否是主角的子弹。
② Rocket rocket = other.GetComponent<Rocket>()语句获得了对方碰撞体的Rocket脚本组件。
③ m_life -= rocket.m_power语句减去一些自身生命,当生命值为0时,使用Destroy函数销毁自身。
④ other.tag.CompareTo("Player") == 0语句用来判断是否与主角相撞,如果是,则直接销毁自身。
运行游戏,敌人已经可以被主角发射的子弹消灭,如果它与主角相撞,则直接销毁。
步骤 07 打开Rocket.cs脚本,也添加一个OnTriggerEnter函数,它的作用很简单,如果子弹撞击到敌人,销毁自身。
void OnTriggerEnter(Collider other) { if (other.tag.CompareTo("Enemy")! =0) return; Destroy(this.gameObject); }
步骤 08 打开Player.cs脚本,添加一个生命属性,同时也添加一个OnTriggerEnter函数,主角飞船与任何己方子弹以外的碰撞体相撞都会损失一点生命,当生命值为0时销毁自身,如下所示:
public float m_life = 3; void OnTriggerEnter(Collider other) { if(other.tag.CompareTo("PlayerRocket")! =0) // 如果与主角子弹以外的碰撞体相撞 { m_life-=1; // 减少生命 if (m_life <= 0) { Destroy(this.gameObject); // 自我销毁 } } }
运行游戏,我们可以发射子弹消灭敌人,主角也可以被敌人撞击损坏,游戏已经有点模样了,但如果敌人不能被消灭则会一直存活下去。接下来,我们将根据事件回调函数OnBecameVisible判断敌人是否进入屏幕,当敌人移动到屏幕外,则销毁敌人。
步骤 09 打开脚本Enemy.cs,添加两个属性m_renderer和m_isActiv,代码如下所示:
internal Renderer m_renderer; // 模型渲染组件 internal bool m_isActiv=false; // 是否激活 // Use this for initialization void Start () { m_transform = this.transform; m_renderer=this.GetComponent<Renderer>(); // 获得模型渲染组件 } void OnBecameVisible() // 当模型进入屏幕 { m_isActiv = true; } void Update () { UpdateMove(); if(m_isActiv&&! this.m_renderer.isVisible) // 如果移动到屏幕外 { Destroy(this.gameObject); // 自我销毁 } }
现在,敌人在飞出屏幕外后会自行销毁。