ExampleSower.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using UnityEngine;
  6. namespace SplineMesh {
  7. /// <summary>
  8. /// Example of component to places assets along a spline. This component can be used as-is but will most likely be a base for your own component.
  9. ///
  10. /// In this example, the user gives the prefab to place, a spacing value between two placements, the prefab scale and an horizontal offset to the spline.
  11. /// These three last values have an additional range, allowing to add some randomness. for each placement, the computed value will be between value and value+range.
  12. ///
  13. /// Prefabs are placed from the start of the spline at computed spacing, unitl there is no lentgh remaining. Prefabs are stored, destroyed
  14. /// and built again each time the spline or one of its curves change.
  15. ///
  16. /// A random seed is used to obtain the same random numbers at each update. The user can specify the seed to test some other random number set.
  17. ///
  18. /// Place prefab along a spline and deform it easily have a lot of usages if you have some imagination :
  19. /// - place trees along a road
  20. /// - create a rocky bridge
  21. /// - create a footstep track with decals
  22. /// - create a path of firefly in the dark
  23. /// - create a natural wall with overlapping rocks
  24. /// - etc.
  25. /// </summary>
  26. [ExecuteInEditMode]
  27. [SelectionBase]
  28. [DisallowMultipleComponent]
  29. public class ExampleSower : MonoBehaviour {
  30. private GameObject generated;
  31. private Spline spline = null;
  32. private bool toUpdate = true;
  33. public GameObject prefab = null;
  34. public float scale = 1, scaleRange = 0;
  35. public float spacing = 1, spacingRange = 0;
  36. public float offset = 0, offsetRange = 0;
  37. public bool isRandomYaw = false;
  38. public int randomSeed = 0;
  39. private void OnEnable() {
  40. string generatedName = "generated by "+GetType().Name;
  41. var generatedTranform = transform.Find(generatedName);
  42. generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject);
  43. spline = GetComponentInParent<Spline>();
  44. spline.NodeListChanged += (s, e) => {
  45. toUpdate = true;
  46. foreach (CubicBezierCurve curve in spline.GetCurves()) {
  47. curve.Changed.AddListener(() => toUpdate = true);
  48. }
  49. };
  50. foreach (CubicBezierCurve curve in spline.GetCurves()) {
  51. curve.Changed.AddListener(() => toUpdate = true);
  52. }
  53. }
  54. private void OnValidate() {
  55. toUpdate = true;
  56. }
  57. private void Update() {
  58. if (toUpdate) {
  59. Sow();
  60. toUpdate = false;
  61. }
  62. }
  63. public void Sow() {
  64. UOUtility.DestroyChildren(generated);
  65. UnityEngine.Random.InitState(randomSeed);
  66. if (spacing + spacingRange <= 0 ||
  67. prefab == null)
  68. return;
  69. float distance = 0;
  70. while (distance <= spline.Length) {
  71. CurveSample sample = spline.GetSampleAtDistance(distance);
  72. GameObject go;
  73. go = Instantiate(prefab, generated.transform);
  74. go.transform.localRotation = Quaternion.identity;
  75. go.transform.localPosition = Vector3.zero;
  76. go.transform.localScale = Vector3.one;
  77. // move along spline, according to spacing + random
  78. go.transform.localPosition = sample.location;
  79. // apply scale + random
  80. float rangedScale = scale + UnityEngine.Random.Range(0, scaleRange);
  81. go.transform.localScale = new Vector3(rangedScale, rangedScale, rangedScale);
  82. // rotate with random yaw
  83. if (isRandomYaw) {
  84. go.transform.Rotate(0, 0, UnityEngine.Random.Range(-180, 180));
  85. } else {
  86. go.transform.rotation = sample.Rotation;
  87. }
  88. // move orthogonaly to the spline, according to offset + random
  89. var binormal = (Quaternion.LookRotation(sample.tangent, sample.up) * Vector3.right).normalized;
  90. var localOffset = offset + UnityEngine.Random.Range(0, offsetRange * Math.Sign(offset));
  91. localOffset *= sample.scale.x;
  92. binormal *= localOffset;
  93. go.transform.position += binormal;
  94. distance += spacing + UnityEngine.Random.Range(0, spacingRange);
  95. }
  96. }
  97. }
  98. }