在unity中使用布料的时候,我们知道,设置与布料发生碰撞的物体有两种方式,一种是直接在属性中设置与不料发生碰撞的单个球形碰撞体,或者添加两个球形碰撞体再连接成一个胶囊体,如下图
然后在今天做项目的时候,由于提前不知道要求那个碰撞体可以与布料发生碰撞,所以需要动态的添加与布料发生碰撞的物体。
项目场景如下:
点击发射按钮,炮弹发射,点击上下移动按钮炮筒上下移动,因此需要动态监测炮弹是否与布料发生碰撞,如果发生碰撞,则需要有一系列的事件发生
代码如下
屏幕自适应、炮弹的发射、碰撞物体的添加与移除
using UnityEngine;
using System.Collections;
public class SampleListener : MonoBehaviour {
public GameObject ballPre;
public Transform targetPos;
public Cloth cloth;
private int icount;
public GameObject FireFlare;
void Start () {
InitUI(); //屏幕自适应
}
public void Fire() {
Rigidbody ballRi = ((GameObject)(Instantiate(ballPre, targetPos.position, targetPos.rotation))).GetComponent<Rigidbody>(); //实例化炮弹
ballRi.AddForce((targetPos.position - transform.position) * 500); //向炮弹施加一个力
addCollider(ref cloth, ballRi.gameObject.GetComponent<SphereCollider>()); //将自身添加到布料碰撞列表
BallListener.destoryGameobject.Add((GameObject)Instantiate(FireFlare, targetPos.position, targetPos.rotation));
}
public void Update() {
if (BallListener.destoryGameobject.Count != 0) { //检测待销毁对象列表是否为空
icount++; //计数器自加
if (icount > 60) {
GameObject.Destroy((GameObject)BallListener.destoryGameobject[0]); //销毁列表头对象
BallListener.destoryGameobject.RemoveAt(0); //移除列表中的对象
icount = 0; //重置计数器
}
}
}
public void Rota(int i) { //炮管旋转回调方法
transform.Rotate(Vector3.forward, i * 5);
}
private void addCollider(ref Cloth c, SphereCollider sc) {
ClothSphereColliderPair[] cscp = new ClothSphereColliderPair[c.sphereColliders.Length + 1]; //重新声明碰撞器数组
for (int i = 0; i < c.sphereColliders.Length; i++) {
cscp[i] = c.sphereColliders[i]; //初始化碰撞器数组
}
cscp[cscp.Length - 1] = new ClothSphereColliderPair(sc); //添加碰撞器
BallListener.clothColliders.Add(cscp[cscp.Length - 1]); //储存碰撞器至列表
c.sphereColliders = cscp; //设置碰撞列表
}
private void InitUI() { //UI按钮屏幕自适应方法
Vector2 editScreen = new Vector2(1381, 638);
Transform canvas = GameObject.Find("Canvas").transform; //在Canvas下的对象将进行位置和大小的调整
Vector2 scaleExchange = new Vector2(Screen.width / editScreen.x, Screen.height / editScreen.y);
for (int i = 0; i < canvas.childCount; i++) {
RectTransform canvasChildRT = canvas.GetChild(i).GetComponent<RectTransform>();
canvasChildRT.position = new Vector3(scaleExchange.x * canvasChildRT.position.x, //调整其位置
scaleExchange.y * canvasChildRT.position.y, 0);
canvasChildRT.sizeDelta = new Vector3(scaleExchange.x * canvasChildRT.sizeDelta.x, //调整其大小
scaleExchange.y * canvasChildRT.sizeDelta.y, 0);
}
}
}
碰撞之后的自我销毁、在碰撞列表中对象的移除
using UnityEngine;
using System.Collections;
public class BallListener : MonoBehaviour {
public static ArrayList clothColliders = new ArrayList(); //列表中储存了能与布料发生碰撞的对象
public static ArrayList destoryGameobject = new ArrayList();
public GameObject Emi;
Cloth cloth; //指定的布料对象
void Start () {
cloth = GameObject.Find("Cloth").GetComponent<Cloth>(); //初始化布料对象
}
void OnTriggerEnter(Collider target) { //碰撞检测
removeCollider(); //移除碰撞列表中的对象
Quaternion q = new Quaternion();
q.eulerAngles = new Vector3(270, 0, 0);
GameObject fire = (GameObject)Instantiate(Emi, new Vector3(transform.position.x, transform.position.y+5, transform.position.z-3), q);
if (!target.gameObject.name.Equals("Cloth")) { //与布料对象发生碰撞
destoryGameobject.Add(fire);
}
Destroy(gameObject); //进行自我销毁
}
void removeCollider() {
clothColliders.Remove(new ClothSphereColliderPair(GetComponent<SphereCollider>())); //在碰撞列表中移除自身
ClothSphereColliderPair[] cscp = new ClothSphereColliderPair[clothColliders.Count]; //重新声明碰撞列表
for (int i = 0; i < cscp.Length; i++) {
cscp[i] = (ClothSphereColliderPair)clothColliders[i]; //初始化碰撞列表
}
cloth.sphereColliders = cscp; //设置碰撞列表
}
}