Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instance SplineMeshTiling to prevent copies overwriting each other #46

Open
lukemadera opened this issue Jun 11, 2021 · 2 comments
Open

Comments

@lukemadera
Copy link

lukemadera commented Jun 11, 2021

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor.Experimental.SceneManagement;
#endif

namespace SplineMesh {
///


/// Deform a mesh and place it along a spline, given various parameters.
///
/// This class intend to cover the most common situations of mesh bending. It can be used as-is in your project,
/// or can serve as a source of inspiration to write your own procedural generator.
///

[ExecuteInEditMode]
[SelectionBase]
[DisallowMultipleComponent]
public class SplineMeshTiling : MonoBehaviour {
string _instanceId = "";

    private GameObject generated;
    private Spline spline = null;
    private bool toUpdate = false;

    public bool initOnEnable = false;
    [Tooltip("Mesh to bend along the spline.")]
    public Mesh mesh;
    [Tooltip("Material to apply on the bent mesh.")]
    public Material material;
    [Tooltip("Physic material to apply on the bent mesh.")]
    public PhysicMaterial physicMaterial;
    [Tooltip("Translation to apply on the mesh before bending it.")]
    public Vector3 translation;
    [Tooltip("Rotation to apply on the mesh before bending it.")]
    public Vector3 rotation;
    [Tooltip("Scale to apply on the mesh before bending it.")]
    public Vector3 scale = Vector3.one;

    [Tooltip("If true, a mesh collider will be generated.")]
    public bool generateCollider = true;

    [Tooltip("If true, the mesh will be bent on play mode. If false, the bent mesh will be kept from the editor mode, allowing lighting baking.")]
    public bool updateInPlayMode;

    [Tooltip("If true, a mesh will be placed on each curve of the spline. If false, a single mesh will be placed for the whole spline.")]
    public bool curveSpace = false;

    [Tooltip("The mode to use to fill the choosen interval with the bent mesh.")]
    public MeshBender.FillingMode mode = MeshBender.FillingMode.StretchToInterval;

    private void OnEnable() {
        if (initOnEnable) {
            Init();
        }
    }

    public void Init() {
        if (_instanceId.Length < 1) {
            if (transform.childCount > 0 && transform.GetChild(0).name.Contains(GetType().Name)) {
                string name = transform.GetChild(0).name;
                _instanceId = name.Substring(0, name.IndexOf("_"));
            } else {
                _instanceId = UnityEngine.Random.Range(0, 999999999).ToString();
            }
        }
        // tip : if you name all generated content in the same way, you can easily find all of it
        // at once in the scene view, with a single search.
        string generatedName = _instanceId + "_genBy_" + GetType().Name;
        var generatedTranform = transform.Find(generatedName);
        generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject);

        spline = GetComponentInParent<Spline>();
        spline.NodeListChanged += (s, e) => toUpdate = true;

        toUpdate = true;
    }

    private void OnValidate() {
        if (spline == null) return;
        toUpdate = true;
    }

    private void Update() {
        // we can prevent the generated content to be updated during playmode to preserve baked data saved in the scene
        if (!updateInPlayMode && Application.isPlaying) return;

        if (toUpdate) {
            toUpdate = false;
            CreateMeshes();
        }
    }

    public void CreateMeshes() {

#if UNITY_EDITOR
// we don't update if we are in prefab mode
if (PrefabStageUtility.GetCurrentPrefabStage() != null) return;
#endif
var used = new List();

        if (curveSpace) {
            int i = 0;
            foreach (var curve in spline.curves) {
                var go = FindOrCreate(_instanceId + "segment " + i++ + " mesh");
                go.GetComponent<MeshBender>().SetInterval(curve);
                go.GetComponent<MeshCollider>().enabled = generateCollider;
                used.Add(go);
            }
        } else {
            var go = FindOrCreate(_instanceId + "segment 1 mesh");
            go.GetComponent<MeshBender>().SetInterval(spline, 0);
            go.GetComponent<MeshCollider>().enabled = generateCollider;
            used.Add(go);
        }

        // we destroy the unused objects. This is classic pooling to recycle game objects.
        foreach (var go in generated.transform
            .Cast<Transform>()
            .Select(child => child.gameObject).Except(used)) {
            UOUtility.Destroy(go);
        }
    }

    private GameObject FindOrCreate(string name) {
        var childTransform = generated.transform.Find(name);
        GameObject res;
        if (childTransform == null) {
            res = UOUtility.Create(name,
                generated,
                typeof(MeshFilter),
                typeof(MeshRenderer),
                typeof(MeshBender),
                typeof(MeshCollider));
            res.isStatic = !updateInPlayMode;
        } else {
            res = childTransform.gameObject;
        }
        res.GetComponent<MeshRenderer>().material = material;
        res.GetComponent<MeshCollider>().material = physicMaterial;
        MeshBender mb = res.GetComponent<MeshBender>();
        mb.Source = SourceMesh.Build(mesh)
            .Translate(translation)
            .Rotate(Quaternion.Euler(rotation))
            .Scale(scale);
        mb.Mode = mode;
        return res;
    }
}

}

@programming2012
Copy link

This way can fix the bug, but will create more than one "generated by SplineMeshTiling" GameObject.

@lukemadera
Copy link
Author

Yep, I realized that and made more updates to block the duplicates. I just updated my post with the update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants