父Prefab与子prefab问题

时间:2023-03-08 18:33:37
父Prefab与子prefab问题

PrefabRevolution

原文:http://framebunker.com/blog/poor-mans-nested-prefabs/   (溜还是老外溜啊父Prefab与子prefab问题

有些时候需要在Prefab里预制一个子prefab,但unity只会默认父prefab,一旦预制了prefab就会与其内部的prefab失去关联;

using UnityEngine;

#if UNITY_EDITOR

using UnityEditor;

using UnityEditor.Callbacks;

#endif

using System.Collections.Generic;

 

[ExecuteInEditMode]

public class PrefabInstance : MonoBehaviour

{

public GameObject prefab;

 

#if UNITY_EDITOR

// Struct of all components. Used for edit-time visualization and gizmo drawing

public struct Thingy {

public Mesh mesh;

public Matrix4x4 matrix;

public List<Material> materials;

}

 

[System.NonSerializedAttribute] public List<Thingy> things = new List<Thingy> ();

 

void OnValidate () {

things.Clear();

if (enabled)

Rebuild (prefab, Matrix4x4.identity);

}

 

void OnEnable () {

things.Clear();

if (enabled)

Rebuild (prefab, Matrix4x4.identity);

}

 

void Rebuild (GameObject source, Matrix4x4 inMatrix) {

if (!source)

return;

 

Matrix4x4 baseMat = inMatrix * Matrix4x4.TRS (-source.transform.position, Quaternion.identity, Vector3.one);



foreach (MeshRenderer mr in source.GetComponentsInChildren(typeof (Renderer), true))

{

things.Add(new Thingy () {

mesh = mr.GetComponent<MeshFilter>().sharedMesh,

matrix = baseMat * mr.transform.localToWorldMatrix,

materials = new List<Material> (mr.sharedMaterials)

});

}

 

foreach (PrefabInstance pi in source.GetComponentsInChildren(typeof (PrefabInstance), true))

{

if (pi.enabled && pi.gameObject.activeSelf)

Rebuild (pi.prefab, baseMat * pi.transform.localToWorldMatrix);

}

}

 

// Editor-time-only update: Draw the meshes so we can see the objects in the scene view

void Update () {

if (EditorApplication.isPlaying)

return;

Matrix4x4 mat = transform.localToWorldMatrix;

foreach (Thingy t in things)

for (int i = 0; i < t.materials.Count; i++)

Graphics.DrawMesh (t.mesh, mat * t.matrix, t.materials[i], gameObject.layer, null, i);

}

 

// Picking logic: Since we don't have gizmos.drawmesh, draw a bounding cube around each thingy

void OnDrawGizmos () { DrawGizmos (new Color (0,0,0,0)); }

void OnDrawGizmosSelected () { DrawGizmos (new Color (0,0,1,.2f)); }

void DrawGizmos (Color col) {

if (EditorApplication.isPlaying)

return;

Gizmos.color = col;

Matrix4x4 mat = transform.localToWorldMatrix;

foreach (Thingy t in things)

{

Gizmos.matrix = mat * t.matrix;

Gizmos.DrawCube(t.mesh.bounds.center, t.mesh.bounds.size);

}

}

 

// Baking stuff: Copy in all the referenced objects into the scene on play or build

[PostProcessScene(-2)]

public static void OnPostprocessScene() { 

foreach (PrefabInstance pi in UnityEngine.Object.FindObjectsOfType (typeof (PrefabInstance)))

    BakeInstance (pi);

}

 

public static void BakeInstance (PrefabInstance pi) {

if(!pi.prefab || !pi.enabled)

return;

pi.enabled = false;

GameObject go = PrefabUtility.InstantiatePrefab(pi.prefab) as GameObject;

Quaternion rot = go.transform.localRotation;

Vector3 scale = go.transform.localScale;

go.transform.parent = pi.transform;

go.transform.localPosition = Vector3.zero;

go.transform.localScale = scale;

go.transform.localRotation = rot;

pi.prefab = null;

foreach (PrefabInstance childPi in go.GetComponentsInChildren<PrefabInstance>())

BakeInstance (childPi);

}

 

#endif

}

PrefabInstance
类能解决这个问题,用法:比如有两个prefab,PrefabFarent和PrefabSon,只需要把PrefabInstance
类挂到PrefabFarent上,把PrefabSon拖到prefab里就行。

这样无论怎么改变PrefabSon,当实例化PrefabFarent时都能得到最新改变了的PrefabSon