2
\$\begingroup\$

I'm creating a simple workaround on the unsupported prefab-on-prefab.

I've thus created this simple class:

[ExecuteInEditMode]
public class PrefabLinker : MonoBehaviour
{
    public GameObject prefab;

    private GameObject spawn;

    void Awake ()
    {
        #if UNITY_EDITOR
        if (!EditorApplication.isPlaying)
            return;
        #endif

        spawn=(GameObject)Instantiate(prefab);
        spawn.transform.parent=transform.parent;
        spawn.transform.localPosition=transform.localPosition;
    }

    #if UNITY_EDITOR
    void Update ()
    {
        if (EditorApplication.isPlaying)
            return;

        // Manually draw the Sprite

    }
    #endif
}

However I've no clue on how to manually draw the Sprite, without adding it to the scene. Obviously I can't add it to the scene like I do when I play it, because otherwise the spawn would be saved in the prefab, polluting it and creating a mess.

I'm hesitant to add the spawn to the scene "somewhere else" and updating its position, because I'd like to prevent the level designers from mistakenly move this spawn instead of the PrefabLinker object.

This only needs to work with 2D stuff. I've found this link which I guess does something similar to my needs, but I've no idea how to fix it to work with sprites (and doesn't work out of the box).

\$\endgroup\$
4
  • 1
    \$\begingroup\$ I haven't done this myself, but I think you might be able to spawn the prefab in the editor and set hideFlags.DontSave to keep it from being serialized into the scene (or containing prefab?). Note that your script will need to manually delete objects marked this way to keep them from leaking. docs.unity3d.com/Documentation/ScriptReference/… \$\endgroup\$ – DMGregory May 14 '14 at 16:57
  • \$\begingroup\$ @DMGregory meanwhile I've built a couple of classes working around that, and DontSave might be a useful addition, thanks. \$\endgroup\$ – o0'. May 14 '14 at 17:43
  • 2
    \$\begingroup\$ Did a bit more research. Unfortunately HideFlags.DontSave will not prevent the child objects from being included in the prefab: answers.unity3d.com/questions/225304/… \$\endgroup\$ – DMGregory May 14 '14 at 18:34
  • \$\begingroup\$ what does "manually draw the sprite" mean? I don't understand the question \$\endgroup\$ – jhocking Sep 5 '14 at 17:06
1
\$\begingroup\$

Still no clue on how to draw the Sprite, so I've just managed to Instance the prefabs in a auto-cleaning way.

PrefabLinker.cs:

#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class PrefabLinker : MonoBehaviour
{
    public GameObject prefab;

    private GameObject spawn;
    private static Trash trash;

    void Awake ()
    {
        if (trash==null)
        {
            trash=(Trash)GameObject.FindObjectOfType(typeof(Trash));
        }
    }
    void Start ()
    {
        // NOTA: facendolo nella OnEnable non funziona (Unity buggato)
        spawn.transform.position=transform.position;
    }
    void OnEnable ()
    {
        spawn=(GameObject)Instantiate(prefab);
        spawn.transform.parent=trash.transform;
        LinkBack lb=(LinkBack)spawn.AddComponent("LinkBack");
        lb.originalObject=this;
    }
    void OnDisable ()
    {
        DestroyImmediate(spawn);
    }

    #if UNITY_EDITOR
    void Update ()
    {
        if (EditorApplication.isPlaying)
            return;

        spawn.transform.position=transform.position;
    }
    #endif
}

LinkBack.cs:

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class LinkBack : MonoBehaviour
{
    public PrefabLinker originalObject;
}

Trash.cs:

using UnityEngine;
using System.Collections;

// todo. volendo pulire automaticamente (non strettamente necessario se gli elementi stessi provvedono)

[ExecuteInEditMode]
public class Trash : MonoBehaviour
{
}
\$\endgroup\$
1
  • \$\begingroup\$ While I solved it this way, I won't accept this answer since the exact question asked how to draw a Sprite, and this is only a workaround to my specific situation, which doesn't apply to other people in need of drawing a Sprite for other reasons. \$\endgroup\$ – o0'. May 14 '14 at 17:50
0
\$\begingroup\$

Ok, some crazy code coming through

public struct Record
{
    public Mesh mesh;
    public Matrix4x4 matrix;
    public List<Material> materials;
    public MaterialPropertyBlock propertyBlock;
}

foreach (SpriteRenderer spriteRenderer in source.GetComponentsInChildren(typeof(SpriteRenderer), true))
{
    Sprite sprite = spriteRenderer.sprite;
    if (sprite == null)
    {
        continue;
    }

    Mesh mesh = new Mesh();

    var bounds = sprite.bounds;
    mesh.vertices = new Vector3[]{
        new Vector3(bounds.min.x,bounds.min.y),
        new Vector3(bounds.min.x,bounds.max.y),
        new Vector3(bounds.max.x,bounds.max.y),
        new Vector3(bounds.max.x,bounds.min.y),
    };

    mesh.triangles = new int[]{
        0,1,2,
        2,3,0
    };

    Vector2 textureCoordsFix = new Vector2(
        1.0f / (float)(sprite.texture.width),
        1.0f / (float)(sprite.texture.height)
        );

    Vector2 _00 = new Vector2(sprite.rect.x, sprite.rect.yMax);
    Vector2 _01 = new Vector2(sprite.rect.x, sprite.rect.y);
    Vector2 _11 = new Vector2(sprite.rect.xMax, sprite.rect.y);
    Vector2 _10 = new Vector2(sprite.rect.xMax, sprite.rect.yMax);

    _00.Scale(textureCoordsFix);
    _01.Scale(textureCoordsFix);
    _11.Scale(textureCoordsFix);
    _10.Scale(textureCoordsFix);

    mesh.uv = new Vector2[]{
        _00,
        _01,
        _11,
        _10
    };

    mesh.colors = new Color[]{
        Color.white,
        Color.white,
        Color.white,
        Color.white
    };

    //Important part, MaterialPropertyBlock is a part of unity sprite pipeline
    MaterialPropertyBlock block = new MaterialPropertyBlock();
    spriteRenderer.GetPropertyBlock(block);

    records.Add(new Record()
    {
        mesh = mesh,
        matrix = baseMat * spriteRenderer.transform.localToWorldMatrix,
        materials = new List<Material>(spriteRenderer.sharedMaterials),
        propertyBlock = block
    });
}

Then somewhere in drawcall

Matrix4x4 mat = transform.localToWorldMatrix;
foreach (Record record in records)
{
    for (int i = 0; i < record.materials.Count; i++)
    {
        Graphics.DrawMesh(record.mesh, mat * record.matrix, record.materials[i], gameObject.layer, null, i, record.propertyBlock);
    }
}

Works pretty fine for me, but still feels kludgy

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.