From ff62827ed652a8b4722f810504f618e93595431c Mon Sep 17 00:00:00 2001 From: Alexander IP <20anip06@gmail.com> Date: Sun, 14 May 2023 12:51:19 -0400 Subject: [PATCH] working on tree growth! --- Assets/DataStructure/Scripts/DataStructure.cs | 11 +- .../Scripts/DataStructureDebug.cs | 55 +-- Assets/DataStructure/Scripts/Grid.cs | 40 +- Assets/Scenes/Testing.unity | 84 ++++- .../Intefaces/ITickableSystem.cs | 7 +- .../Managers/SystemsManager.cs | 10 +- .../{Scripts/Trees => }/Art/Bark.mat | 0 .../{Scripts/Trees => }/Art/Bark.mat.meta | 0 .../{Scripts/Trees => }/Art/Leaves.mat | 0 .../{Scripts/Trees => }/Art/Leaves.mat.meta | 0 .../{Scripts/Trees => }/Art/bark1col.jpg | Bin .../{Scripts/Trees => }/Art/bark1col.jpg.meta | 0 .../{Scripts/Trees => }/Art/bark1norm.jpg | Bin .../Trees => }/Art/bark1norm.jpg.meta | 0 .../{Scripts/Trees => }/Art/leaves.png | Bin .../{Scripts/Trees => }/Art/leaves.png.meta | 0 .../{Scripts/Trees => }/Prefabs.meta | 0 .../Test Tree.prefab} | 2 +- .../Test Tree.prefab.meta} | 0 .../Scenes/ExampleTreeTesting.unity | 111 +++--- .../Scenes/ExampleTreeTesting.unity.meta | 0 .../{Trees/Scripts.meta => Generation.meta} | 0 .../Scripts/Generation/ColorGenerator.cs | 36 ++ .../ColorGenerator.cs.meta | 0 Assets/TreeGrowth/Scripts/Generation/Node.cs | 251 +++++++++++++ .../Scripts => Generation}/Node.cs.meta | 0 .../Scripts/Generation/TreeGenerator.cs | 344 ++++++++++++++++++ .../TreeGenerator.cs.meta | 0 .../Scripts/Generation/TreeTester.cs | 49 +++ .../TreeTester.cs.meta} | 2 +- Assets/TreeGrowth/Scripts/TreeCellData.cs | 1 + Assets/TreeGrowth/Scripts/TreeManager.cs | 59 ++- Assets/TreeGrowth/Scripts/TreeParameters.cs | 10 +- Assets/TreeGrowth/Scripts/Trees.meta | 8 - Assets/TreeGrowth/Scripts/Trees/Art.meta | 8 - Assets/TreeGrowth/Scripts/Trees/Scenes.meta | 8 - .../Scripts/Trees/Scripts/ColorGenerator.cs | 31 -- .../TreeGrowth/Scripts/Trees/Scripts/Node.cs | 155 -------- .../Scripts/Trees/Scripts/TreeGenerator.cs | 306 ---------------- .../Scripts/Trees/Scripts/TreePlacer.cs | 26 -- Assets/Visuals/Visuals.asmdef | 3 - Assets/Visuals/Visuals.asmdef.meta | 7 - .../WaterSimulation/Scripts/WaterSimDebug.cs | 1 + .../Scripts/WaterSimulation.cs | 1 + .../BurstAotSettings_StandaloneWindows.json | 17 + .../BurstAotSettings_WSAPlayer.json | 16 + ProjectSettings/CommonBurstAotSettings.json | 6 + ProjectSettings/EditorSettings.asset | 26 +- ProjectSettings/QualitySettings.asset | 21 +- 49 files changed, 1000 insertions(+), 712 deletions(-) rename Assets/TreeGrowth/{Scripts/Trees => }/Art/Bark.mat (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Art/Bark.mat.meta (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Art/Leaves.mat (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Art/Leaves.mat.meta (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Art/bark1col.jpg (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Art/bark1col.jpg.meta (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Art/bark1norm.jpg (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Art/bark1norm.jpg.meta (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Art/leaves.png (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Art/leaves.png.meta (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Prefabs.meta (100%) rename Assets/TreeGrowth/{Scripts/Trees/Prefabs/TEST TREE.prefab => Prefabs/Test Tree.prefab} (99%) rename Assets/TreeGrowth/{Scripts/Trees/Prefabs/TEST TREE.prefab.meta => Prefabs/Test Tree.prefab.meta} (100%) rename Assets/TreeGrowth/{Scripts/Trees => }/Scenes/ExampleTreeTesting.unity (91%) rename Assets/TreeGrowth/{Scripts/Trees => }/Scenes/ExampleTreeTesting.unity.meta (100%) rename Assets/TreeGrowth/Scripts/{Trees/Scripts.meta => Generation.meta} (100%) create mode 100644 Assets/TreeGrowth/Scripts/Generation/ColorGenerator.cs rename Assets/TreeGrowth/Scripts/{Trees/Scripts => Generation}/ColorGenerator.cs.meta (100%) create mode 100644 Assets/TreeGrowth/Scripts/Generation/Node.cs rename Assets/TreeGrowth/Scripts/{Trees/Scripts => Generation}/Node.cs.meta (100%) create mode 100644 Assets/TreeGrowth/Scripts/Generation/TreeGenerator.cs rename Assets/TreeGrowth/Scripts/{Trees/Scripts => Generation}/TreeGenerator.cs.meta (100%) create mode 100644 Assets/TreeGrowth/Scripts/Generation/TreeTester.cs rename Assets/TreeGrowth/Scripts/{Trees/Scripts/TreePlacer.cs.meta => Generation/TreeTester.cs.meta} (83%) delete mode 100644 Assets/TreeGrowth/Scripts/Trees.meta delete mode 100644 Assets/TreeGrowth/Scripts/Trees/Art.meta delete mode 100644 Assets/TreeGrowth/Scripts/Trees/Scenes.meta delete mode 100644 Assets/TreeGrowth/Scripts/Trees/Scripts/ColorGenerator.cs delete mode 100644 Assets/TreeGrowth/Scripts/Trees/Scripts/Node.cs delete mode 100644 Assets/TreeGrowth/Scripts/Trees/Scripts/TreeGenerator.cs delete mode 100644 Assets/TreeGrowth/Scripts/Trees/Scripts/TreePlacer.cs delete mode 100644 Assets/Visuals/Visuals.asmdef delete mode 100644 Assets/Visuals/Visuals.asmdef.meta create mode 100644 ProjectSettings/BurstAotSettings_StandaloneWindows.json create mode 100644 ProjectSettings/BurstAotSettings_WSAPlayer.json create mode 100644 ProjectSettings/CommonBurstAotSettings.json diff --git a/Assets/DataStructure/Scripts/DataStructure.cs b/Assets/DataStructure/Scripts/DataStructure.cs index 49ce0bc..95b3d52 100644 --- a/Assets/DataStructure/Scripts/DataStructure.cs +++ b/Assets/DataStructure/Scripts/DataStructure.cs @@ -16,11 +16,13 @@ public class DataStructure : MonoBehaviour, ITickableSystem #region Public [Header("Grids")] public Vector2 OverallSize; + [Tooltip("Highest level grid is the largest grid and has the highest index")] public List Levels; - public List Grids { get; private set; } + [SerializeField] private List grids = new List(); + public List Grids { get {return grids;} } [Header("Data")] public List InitializingObjects = new List(); @@ -43,6 +45,7 @@ public class DataStructure : MonoBehaviour, ITickableSystem public int TickInterval { get { return 0; } } public int ticksSinceLastTick { get; set; } public bool willTickNow { get; set; } + public bool shouldTick { get { return true; } } #endregion #region Debug @@ -175,8 +178,8 @@ private void populateGrids(List levels) } // Assign the parent cell to the container cell - cell.parentCell = containerCell; - containerCell.childCells.Add(cell); + cell.ParentCell = containerCell; + containerCell.ChildCells.Add(cell); } } @@ -502,7 +505,7 @@ private int receiveCellDataFromWriter(IWriteCellData writer) int level = dataPointer.Item2; addCellData(level, name, dataToAdd[dataPointer]); - + writes++; } diff --git a/Assets/DataStructure/Scripts/DataStructureDebug.cs b/Assets/DataStructure/Scripts/DataStructureDebug.cs index 7e5ee71..22129dd 100644 --- a/Assets/DataStructure/Scripts/DataStructureDebug.cs +++ b/Assets/DataStructure/Scripts/DataStructureDebug.cs @@ -53,42 +53,20 @@ public class DataStructureDebug : MonoBehaviour public void Start() { - Debug.Log("Performing tests on data structure..."); - Stopwatch st = new Stopwatch(); - st.Start(); - foreach (Grid grid in ds.Grids) { gridColors.Add(grid, UnityEngine.Random.ColorHSV()); } + } + public void FixedUpdate() + { if (DoQueryTest) { + DoQueryTest = false; performQueryTest(QueryTestCount); } - // if (DoAddDataTest) - // { - // performAddDataTest(AddDataTestCount); - // } - - // if (DoRemoveDataTest) - // { - // performRemoveDataTest(RemoveDataTestCount); - // } - - // if (DoModifyDataTest) - // { - // performModifyDataTest(ModifyDataTestCount); - // } - - st.Stop(); - - Debug.Log("All tests completed in " + st.ElapsedMilliseconds + " ms"); - } - - public void FixedUpdate() - { if (QuerySingleCellTest && QuerySingleCellPosition != lastTestPos) { lastTestPos = QuerySingleCellPosition; @@ -100,15 +78,18 @@ public void FixedUpdate() public void performQueryTest(int count) { Debug.Log("Performing " + count + " random queries on " + (TestLevel == -1 ? "random level" : ("level " + TestLevel)) + "..."); - int startTime = DateTime.Now.Millisecond; + + Stopwatch st = new Stopwatch(); + st.Start(); for (int i = 0; i < count; i++) { Vector2 testPos = new Vector2(UnityEngine.Random.Range(0, ds.OverallSize.x), UnityEngine.Random.Range(0, ds.OverallSize.y)); performDebugQuery(testPos, TestLevel == -1 ? UnityEngine.Random.Range(0, ds.Grids.Count - 1) : TestLevel, false); } + st.Stop(); - Debug.Log(count + " random queries successfully completed in " + (DateTime.Now.Millisecond - startTime) + " ms"); + Debug.Log(count + " random queries successfully completed in " + st.Elapsed.TotalMilliseconds + " ms"); } private void performDebugQuery(Vector2 queryPos, int level = -1, bool fetchData = true) @@ -278,12 +259,12 @@ private void OnDrawGizmos() { Gizmos.color = Color.green; - Vector3 center = new Vector3(cell.center.x, (cell.level.Level - 1) * LevelZShift, cell.center.y); + Vector3 center = new Vector3(cell.center.x, (cell.Level.Level - 1) * LevelZShift, cell.center.y); - Gizmos.DrawLine(center + new Vector3(-cell.level.CellSize.x / 2, 0, -cell.level.CellSize.y / 2), center + new Vector3(cell.level.CellSize.x / 2, 0, -cell.level.CellSize.y / 2)); - Gizmos.DrawLine(center + new Vector3(cell.level.CellSize.x / 2, 0, -cell.level.CellSize.y / 2), center + new Vector3(cell.level.CellSize.x / 2, 0, cell.level.CellSize.y / 2)); - Gizmos.DrawLine(center + new Vector3(cell.level.CellSize.x / 2, 0, cell.level.CellSize.y / 2), center + new Vector3(-cell.level.CellSize.x / 2, 0, cell.level.CellSize.y / 2)); - Gizmos.DrawLine(center + new Vector3(-cell.level.CellSize.x / 2, 0, cell.level.CellSize.y / 2), center + new Vector3(-cell.level.CellSize.x / 2, 0, -cell.level.CellSize.y / 2)); + Gizmos.DrawLine(center + new Vector3(-cell.Level.CellSize.x / 2, 0, -cell.Level.CellSize.y / 2), center + new Vector3(cell.Level.CellSize.x / 2, 0, -cell.Level.CellSize.y / 2)); + Gizmos.DrawLine(center + new Vector3(cell.Level.CellSize.x / 2, 0, -cell.Level.CellSize.y / 2), center + new Vector3(cell.Level.CellSize.x / 2, 0, cell.Level.CellSize.y / 2)); + Gizmos.DrawLine(center + new Vector3(cell.Level.CellSize.x / 2, 0, cell.Level.CellSize.y / 2), center + new Vector3(-cell.Level.CellSize.x / 2, 0, cell.Level.CellSize.y / 2)); + Gizmos.DrawLine(center + new Vector3(-cell.Level.CellSize.x / 2, 0, cell.Level.CellSize.y / 2), center + new Vector3(-cell.Level.CellSize.x / 2, 0, -cell.Level.CellSize.y / 2)); } } } @@ -305,9 +286,9 @@ public void debugDrawGrid(Grid toDraw, float levelZShift) { // For each neighbor, draw a small line to the edge of this cell Gizmos.color = Color.white; - for (int i = 0; i < cell.neighbors.Length; i++) + for (int i = 0; i < cell.Neighbors.Length; i++) { - if (cell.neighbors[i] != null) + if (cell.Neighbors[i] != null) { if (i == 0) { // above @@ -332,10 +313,10 @@ public void debugDrawGrid(Grid toDraw, float levelZShift) if (DrawParentLines) { // Draw a line to the parent cell - if (cell.parentCell != null) + if (cell.ParentCell != null) { Gizmos.color = Color.red; - Gizmos.DrawLine(center, new Vector3(cell.parentCell.center.x, (cell.parentCell.level.Level - 1) * levelZShift, cell.parentCell.center.y)); + Gizmos.DrawLine(center, new Vector3(cell.ParentCell.center.x, (cell.ParentCell.Level.Level - 1) * levelZShift, cell.ParentCell.center.y)); } } } diff --git a/Assets/DataStructure/Scripts/Grid.cs b/Assets/DataStructure/Scripts/Grid.cs index 4729c54..d3169fb 100644 --- a/Assets/DataStructure/Scripts/Grid.cs +++ b/Assets/DataStructure/Scripts/Grid.cs @@ -18,7 +18,7 @@ public class Grid public Grid childGrid; private List cells; - private List childCells; + // private List childCells; public int xCellCount, yCellCount; @@ -32,7 +32,7 @@ public Grid(Vector2 size, GridLevel gridLevel) this.gridLevel = gridLevel; this.cells = new List(); - this.childCells = new List(); + // this.childCells = new List(); this.xCellCount = (int)(size.x / gridLevel.CellSize.x); this.yCellCount = (int)(size.y / gridLevel.CellSize.y); @@ -55,21 +55,21 @@ private void populate() // Assign this cell's neighbors to the cell above and to the left if (y > 0) { - cell.neighbors[0] = cells[cells.Count - xCellCount - 1]; + cell.Neighbors[0] = cells[cells.Count - xCellCount - 1]; } if (x > 0) { - cell.neighbors[1] = cells[cells.Count - 2]; + cell.Neighbors[1] = cells[cells.Count - 2]; } // Assign the cell above and to the left's neighbors to this cell if (y > 0) { - cells[cells.Count - xCellCount - 1].neighbors[2] = cell; + cells[cells.Count - xCellCount - 1].Neighbors[2] = cell; } if (x > 0) { - cells[cells.Count - 2].neighbors[3] = cell; + cells[cells.Count - 2].Neighbors[3] = cell; } } } @@ -257,7 +257,7 @@ public void SetGridData(string dataName, object data) { gridData[dataName].SetData(data); } - else + else // TODO: Maybe add a thing here to create a new entry if it doesn't exist? Debug.Log("Grid data \"" + dataName + "\" does not exist."); } @@ -372,22 +372,34 @@ public void RemoveCellData(string dataName) #endregion } - [Serializable] + // [Serializable] public class GridCell { #region Public public Vector2 center; public Bounds bounds; - public GridLevel level; + private GridLevel level; + [HideInInspector] + public GridLevel Level { get { return level; } } // References - public GridCell parentCell; - public List childCells = new List(); - public GridCell[] neighbors = new GridCell[4]; // 0 = above, 1 = left, 2 = below, 3 = right + private GridCell parentCell; + [HideInInspector] + public GridCell ParentCell { get { return parentCell; } set { parentCell = value; } } + + [HideInInspector] + private List childCells = new List(); + [HideInInspector] + public List ChildCells { get { return childCells; } } + + private GridCell[] neighbors = new GridCell[4]; // 0 = above, 1 = left, 2 = below, 3 = right + [HideInInspector] + public GridCell[] Neighbors { get { return neighbors; } } // 0 = above, 1 = left, 2 = below, 3 = right #endregion #region Private // Data + [SerializeField] private GenericDictionary> data = new GenericDictionary>(); #endregion @@ -406,8 +418,8 @@ public bool Contains(Vector2 queryPos) return false; } - return (queryPos.x >= center.x - level.CellSize.x / 2 && queryPos.x <= center.x + level.CellSize.x / 2 && - queryPos.y >= center.y - level.CellSize.y / 2 && queryPos.y <= center.y + level.CellSize.y / 2); + return (queryPos.x >= center.x - Level.CellSize.x / 2 && queryPos.x <= center.x + Level.CellSize.x / 2 && + queryPos.y >= center.y - Level.CellSize.y / 2 && queryPos.y <= center.y + Level.CellSize.y / 2); } public GridCell GetChild(Vector2 queryPos) diff --git a/Assets/Scenes/Testing.unity b/Assets/Scenes/Testing.unity index 7c8837c..af94534 100644 --- a/Assets/Scenes/Testing.unity +++ b/Assets/Scenes/Testing.unity @@ -139,7 +139,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!4 &25418883 Transform: m_ObjectHideFlags: 0 @@ -178,6 +178,7 @@ MonoBehaviour: QuerySingleCellTest: 1 QuerySingleCellLevel: 0 QuerySingleCellPosition: {x: 0, y: 0} + TestedCells: [] TestedCellData: list: [] keyCollision: 0 @@ -231,6 +232,7 @@ MonoBehaviour: - {fileID: 11400000, guid: 36751346e59f29e409b3874b0603be45, type: 2} - {fileID: 11400000, guid: a8156ca0bf27694458adbefdae0a24e1, type: 2} - {fileID: 11400000, guid: 5d57596dba7f4ac4582655b943c0fedc, type: 2} + grids: [] InitializingObjects: - {fileID: 6456605024775582197} ReadingObjects: @@ -239,7 +241,7 @@ MonoBehaviour: WritingObjects: - {fileID: 6456605024775582197} - {fileID: 542635039} - CalculateDebugInfo: 1 + CalculateDebugInfo: 0 gridReadsPerTick: 0 gridWritesPerTick: 0 gridActivityPerTick: 0 @@ -250,6 +252,11 @@ MonoBehaviour: gridWriteTimePerTick: 0 cellReadTimePerTick: 0 cellWriteTimePerTick: 0 +--- !u!4 &484432729 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + m_PrefabInstance: {fileID: 1853387044} + m_PrefabAsset: {fileID: 0} --- !u!1 &525463473 GameObject: m_ObjectHideFlags: 0 @@ -267,7 +274,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!4 &525463474 Transform: m_ObjectHideFlags: 0 @@ -374,7 +381,8 @@ Transform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: [] + m_Children: + - {fileID: 484432729} m_Father: {fileID: 638825940} m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -393,11 +401,13 @@ MonoBehaviour: trees: [] newTrees: [] nulledTrees: [] - first: 1 - TestTreePrefab: {fileID: 2512629738840422531, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} - initialTreeGenerationBounds: + GenerateInitialTrees: 0 + CollectInitialChildTrees: 1 + InitialTreeCount: 100 + InitialTreeGenerationBounds: m_Center: {x: -50, y: 0, z: -50} m_Extent: {x: 25, y: 0, z: 25} + TestTreePrefab: {fileID: 2512629738840422531, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} references: version: 2 RefIds: [] @@ -449,6 +459,7 @@ MonoBehaviour: - {fileID: 282096875} - {fileID: 6456605024775582197} - {fileID: 542635039} + - {fileID: 525463473} CalculateDebugInfo: 0 BeginTickTime: 0 TickTime: 0 @@ -584,6 +595,63 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1001 &1853387044 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 542635040} + m_Modifications: + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422528, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2512629738840422531, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} + propertyPath: m_Name + value: Test Tree + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 0baa68192c27f434cb5441f33316dd05, type: 3} --- !u!1 &6456605024775582197 GameObject: m_ObjectHideFlags: 0 @@ -600,7 +668,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!114 &6456605024775582198 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/SystemsManagement/Intefaces/ITickableSystem.cs b/Assets/SystemsManagement/Intefaces/ITickableSystem.cs index dd88e6b..ff69c8a 100644 --- a/Assets/SystemsManagement/Intefaces/ITickableSystem.cs +++ b/Assets/SystemsManagement/Intefaces/ITickableSystem.cs @@ -1,11 +1,14 @@ using UnityEngine; -namespace Managers.Interfaces { - public interface ITickableSystem { +namespace Managers.Interfaces +{ + public interface ITickableSystem + { float TickPriority { get; } int TickInterval { get; } // in frames int ticksSinceLastTick { get; set; } bool willTickNow { get; set; } + bool shouldTick { get; } /** diff --git a/Assets/SystemsManagement/Managers/SystemsManager.cs b/Assets/SystemsManagement/Managers/SystemsManager.cs index 9ede8ef..b941a1e 100644 --- a/Assets/SystemsManagement/Managers/SystemsManager.cs +++ b/Assets/SystemsManagement/Managers/SystemsManager.cs @@ -42,6 +42,8 @@ public void Awake() public void Start() { + Debug.LogWarning("Remember to add all tickable systems to the TickableObjects list in SystemsManager!"); + for (int i = 0; i < TickableObjects.Count; i++) { ITickableSystem[] systems = TickableObjects[i].GetComponents(); @@ -70,7 +72,6 @@ public void FixedUpdate() } // Figure out which systems need to be ticked this frame - int currentTick = Time.frameCount; for (int i = 0; i < tickableSystems.Count; i++) { ITickableSystem system = tickableSystems[i]; @@ -78,8 +79,11 @@ public void FixedUpdate() if (system.ticksSinceLastTick >= system.TickInterval) { system.ticksSinceLastTick = 0; - system.willTickNow = true; - toTick.Add(system); + if (system.shouldTick) + { + system.willTickNow = true; + toTick.Add(system); + } } else { diff --git a/Assets/TreeGrowth/Scripts/Trees/Art/Bark.mat b/Assets/TreeGrowth/Art/Bark.mat similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Art/Bark.mat rename to Assets/TreeGrowth/Art/Bark.mat diff --git a/Assets/TreeGrowth/Scripts/Trees/Art/Bark.mat.meta b/Assets/TreeGrowth/Art/Bark.mat.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Art/Bark.mat.meta rename to Assets/TreeGrowth/Art/Bark.mat.meta diff --git a/Assets/TreeGrowth/Scripts/Trees/Art/Leaves.mat b/Assets/TreeGrowth/Art/Leaves.mat similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Art/Leaves.mat rename to Assets/TreeGrowth/Art/Leaves.mat diff --git a/Assets/TreeGrowth/Scripts/Trees/Art/Leaves.mat.meta b/Assets/TreeGrowth/Art/Leaves.mat.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Art/Leaves.mat.meta rename to Assets/TreeGrowth/Art/Leaves.mat.meta diff --git a/Assets/TreeGrowth/Scripts/Trees/Art/bark1col.jpg b/Assets/TreeGrowth/Art/bark1col.jpg similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Art/bark1col.jpg rename to Assets/TreeGrowth/Art/bark1col.jpg diff --git a/Assets/TreeGrowth/Scripts/Trees/Art/bark1col.jpg.meta b/Assets/TreeGrowth/Art/bark1col.jpg.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Art/bark1col.jpg.meta rename to Assets/TreeGrowth/Art/bark1col.jpg.meta diff --git a/Assets/TreeGrowth/Scripts/Trees/Art/bark1norm.jpg b/Assets/TreeGrowth/Art/bark1norm.jpg similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Art/bark1norm.jpg rename to Assets/TreeGrowth/Art/bark1norm.jpg diff --git a/Assets/TreeGrowth/Scripts/Trees/Art/bark1norm.jpg.meta b/Assets/TreeGrowth/Art/bark1norm.jpg.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Art/bark1norm.jpg.meta rename to Assets/TreeGrowth/Art/bark1norm.jpg.meta diff --git a/Assets/TreeGrowth/Scripts/Trees/Art/leaves.png b/Assets/TreeGrowth/Art/leaves.png similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Art/leaves.png rename to Assets/TreeGrowth/Art/leaves.png diff --git a/Assets/TreeGrowth/Scripts/Trees/Art/leaves.png.meta b/Assets/TreeGrowth/Art/leaves.png.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Art/leaves.png.meta rename to Assets/TreeGrowth/Art/leaves.png.meta diff --git a/Assets/TreeGrowth/Scripts/Trees/Prefabs.meta b/Assets/TreeGrowth/Prefabs.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Prefabs.meta rename to Assets/TreeGrowth/Prefabs.meta diff --git a/Assets/TreeGrowth/Scripts/Trees/Prefabs/TEST TREE.prefab b/Assets/TreeGrowth/Prefabs/Test Tree.prefab similarity index 99% rename from Assets/TreeGrowth/Scripts/Trees/Prefabs/TEST TREE.prefab rename to Assets/TreeGrowth/Prefabs/Test Tree.prefab index 10286cf..1cc1648 100644 --- a/Assets/TreeGrowth/Scripts/Trees/Prefabs/TEST TREE.prefab +++ b/Assets/TreeGrowth/Prefabs/Test Tree.prefab @@ -13,7 +13,7 @@ GameObject: - component: {fileID: 2512629738840422534} - component: {fileID: 2512629738840422529} m_Layer: 0 - m_Name: TEST TREE + m_Name: Test Tree m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 diff --git a/Assets/TreeGrowth/Scripts/Trees/Prefabs/TEST TREE.prefab.meta b/Assets/TreeGrowth/Prefabs/Test Tree.prefab.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Prefabs/TEST TREE.prefab.meta rename to Assets/TreeGrowth/Prefabs/Test Tree.prefab.meta diff --git a/Assets/TreeGrowth/Scripts/Trees/Scenes/ExampleTreeTesting.unity b/Assets/TreeGrowth/Scenes/ExampleTreeTesting.unity similarity index 91% rename from Assets/TreeGrowth/Scripts/Trees/Scenes/ExampleTreeTesting.unity rename to Assets/TreeGrowth/Scenes/ExampleTreeTesting.unity index 7db6e5e..aa23252 100644 --- a/Assets/TreeGrowth/Scripts/Trees/Scenes/ExampleTreeTesting.unity +++ b/Assets/TreeGrowth/Scenes/ExampleTreeTesting.unity @@ -346,52 +346,6 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!1 &1517396862 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1517396863} - - component: {fileID: 1517396864} - m_Layer: 0 - m_Name: TreePlacer - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1517396863 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1517396862} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1517396864 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1517396862} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 68f61647aad0b9c47af6679d2fdd9005, type: 3} - m_Name: - m_EditorClassIdentifier: - TreeGenerator: {fileID: 6247895241133104446} - Generate: 0 --- !u!1 &1871596001 GameObject: m_ObjectHideFlags: 0 @@ -488,21 +442,23 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a04f9774aff229d4b80e003dea33c843, type: 3} m_Name: m_EditorClassIdentifier: - StemSize: 0.3 - BranchSize: 0.1 - SizeFalloff: 0.9 - Distort: 0.5 - BranchLength: 2 - LeafColliderSize: 0.2 - BranchAngle: 30 - BranchLengthFalloff: 0.9 - Iterations: 100 - GenerateLeaves: 1 - LeafQuadRadius: 0.3 - RayCastCount: 0 - MaxChildrenPerNode: 3 - MeshSubdivisions: 5 - BatchSize: 5 + parameters: + QUADS_PER_LEAF: 16 + StemSize: 0.3 + BranchSize: 0.1 + SizeFalloff: 0.9 + Distort: 0.5 + BranchLength: 2 + LeafColliderSize: 0.2 + BranchAngle: 30 + BranchLengthFalloff: 0.9 + Iterations: 100 + GenerateLeaves: 1 + LeafQuadRadius: 0.3 + RayCastCount: 0 + MaxChildrenPerNode: 3 + MeshSubdivisions: 5 + BatchSize: 5 LeafColliders: {fileID: 0} ColorSchemes: [] --- !u!1 &6278295379626485818 @@ -514,6 +470,7 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 6281588471591219840} + - component: {fileID: 6300902751677474739} - component: {fileID: 6247895241133104446} - component: {fileID: 6292878802196684226} - component: {fileID: 6300902751677474738} @@ -538,7 +495,7 @@ Transform: m_Children: - {fileID: 519503807} m_Father: {fileID: 0} - m_RootOrder: 4 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!33 &6292878802196684226 MeshFilter: @@ -591,3 +548,33 @@ MeshRenderer: m_SortingLayer: 0 m_SortingOrder: 0 m_AdditionalVertexStreams: {fileID: 0} +--- !u!114 &6300902751677474739 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6278295379626485818} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9bbd394eafb6db14b90ea1a78711a61e, type: 3} + m_Name: + m_EditorClassIdentifier: + Generate: 0 + Parameters: + QUADS_PER_LEAF: 16 + StemSize: 0.3 + BranchSize: 0.1 + SizeFalloff: 0.9 + Distort: 0.5 + BranchLength: 2 + LeafColliderSize: 0.2 + BranchAngle: 30 + BranchLengthFalloff: 0.9 + Iterations: 100 + GenerateLeaves: 1 + LeafQuadRadius: 0.3 + RayCastCount: 0 + MaxChildrenPerNode: 3 + MeshSubdivisions: 5 + BatchSize: 5 diff --git a/Assets/TreeGrowth/Scripts/Trees/Scenes/ExampleTreeTesting.unity.meta b/Assets/TreeGrowth/Scenes/ExampleTreeTesting.unity.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Scenes/ExampleTreeTesting.unity.meta rename to Assets/TreeGrowth/Scenes/ExampleTreeTesting.unity.meta diff --git a/Assets/TreeGrowth/Scripts/Trees/Scripts.meta b/Assets/TreeGrowth/Scripts/Generation.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Scripts.meta rename to Assets/TreeGrowth/Scripts/Generation.meta diff --git a/Assets/TreeGrowth/Scripts/Generation/ColorGenerator.cs b/Assets/TreeGrowth/Scripts/Generation/ColorGenerator.cs new file mode 100644 index 0000000..ac355d0 --- /dev/null +++ b/Assets/TreeGrowth/Scripts/Generation/ColorGenerator.cs @@ -0,0 +1,36 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace TreeGrowth.Generation +{ + [System.Serializable] + public class ColorGenerator + { + public float Probability = 1; + + [Range(0f, 1f)] + public float HueMin; + [Range(0f, 1f)] + public float HueMax; + + [Range(0f, 1f)] + public float SaturationMin; + [Range(0f, 1f)] + public float SaturationMax; + + [Range(0f, 1f)] + public float ValueMin; + [Range(0f, 1f)] + public float ValueMax; + + public Color GetColor() + { + return Color.HSVToRGB( + Random.Range(this.HueMin, this.HueMax), + Random.Range(this.SaturationMin, this.SaturationMax), + Random.Range(this.ValueMin, this.ValueMax) + ); + } + } +} \ No newline at end of file diff --git a/Assets/TreeGrowth/Scripts/Trees/Scripts/ColorGenerator.cs.meta b/Assets/TreeGrowth/Scripts/Generation/ColorGenerator.cs.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Scripts/ColorGenerator.cs.meta rename to Assets/TreeGrowth/Scripts/Generation/ColorGenerator.cs.meta diff --git a/Assets/TreeGrowth/Scripts/Generation/Node.cs b/Assets/TreeGrowth/Scripts/Generation/Node.cs new file mode 100644 index 0000000..47cf778 --- /dev/null +++ b/Assets/TreeGrowth/Scripts/Generation/Node.cs @@ -0,0 +1,251 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using System.Linq; +using UnityEditor; +using System; +using Random = UnityEngine.Random; + +namespace TreeGrowth.Generation +{ + public class Node + { + public readonly Vector3 Position; + public readonly Vector3 Direction; + public readonly TreeGenerator Tree; + + public readonly int Depth; + public float Energy; + + public readonly Node Parent; + public Node[] Children; + + public SphereCollider LeafCollider; + public Vector3 MeshOrientation; + + public int SubtreeSize + { + get; + private set; + } + + public Node(Vector3 position, TreeGenerator tree) + { + this.Tree = tree; + this.Position = position; + this.Direction = Vector3.up; + this.Depth = 0; + this.Children = new Node[] { }; + } + + public Node(Vector3 position, Node parent) + { + this.Tree = parent.Tree; + this.Position = position; + this.Direction = (this.Position - parent.Position).normalized; + this.Depth = parent.Depth + 1; + this.Children = new Node[] { }; + parent.Children = parent.Children.Concat(new Node[] { this }).ToArray(); + this.CreateLeafCollider(); + this.Parent = parent; + + } + + public void CreateLeafCollider() + { + this.LeafCollider = this.Tree.LeafColliders.AddComponent(); + this.LeafCollider.center = this.Position; + this.LeafCollider.radius = this.Tree.parameters.LeafColliderSize; + } + + public void RemoveLeafCollider() + { + if (this.LeafCollider == null) + return; + + GameObject.DestroyImmediate(this.LeafCollider); + } + + public IEnumerable GetTree() + { + yield return this; + + Node currentNode = this; + Stack positions = new Stack(); + int currentPosition = 0; + + while (true) + { + if (currentPosition < currentNode.Children.Length) + { + Node child = currentNode.Children[currentPosition]; + + currentPosition++; + + yield return child; + + if (child.Children.Length > 0) + { + currentNode = child; + positions.Push(currentPosition); + currentPosition = 0; + } + } + else if (currentNode.Parent != null) + { + currentPosition = positions.Pop(); + currentNode = currentNode.Parent; + } + else + { + yield break; + } + } + } + + /** + Try to branch off of this branch. Only for if this branch already has any children. + **/ + public void Branch() + { + if (this.Children.Count() == 0) // If this branch already has any children + return; + + // The math for the falloff is as follows: (branch length falloff param ^ depth of this branch in the tree) + float nextLengthFalloffMult = Mathf.Pow(this.Tree.parameters.BranchLengthFalloff, this.Depth); + + // Get the length of a new branch if it were to grow off of this one + // The math is as follows: (branch length param * branch length falloff multiplier) + // That falloff makes it so that branches get shorter the farther out in the tree they are + float nextLength = this.Tree.parameters.BranchLength * nextLengthFalloffMult; + + // Get the direction of the first child branch (the one created by Grow()) + Vector3 childDir = this.Children[0].Direction; + + // Take the direction of the first child branch and slightly randomize it + // This is to make sure that the new branch doesn't grow in the exact same direction as the first child branch + // The math is as follows: + // (direction of first child branch * cos(branch angle param in rad) + cross product of direction of first child branch and a random direction * sign of branch angle param in deg) + Func jitterFunc = () => childDir * Mathf.Cos(this.Tree.parameters.BranchAngle * Mathf.Deg2Rad) + Vector3.Cross(childDir, Random.onUnitSphere) * Mathf.Sign(this.Tree.parameters.BranchAngle * Mathf.Rad2Deg); // TODO: Why is this converting from degrees to degrees??? + + // Get the optimal direction for a new branch to grow in + // You pass a vector function that slightly randomizes the direction a bit every attempt + // You also pass a minimum distance for that direction to be valid + Vector3 direction = this.getGrowthDirection(jitterFunc, nextLength); + + if (!Mathf.Approximately(direction.magnitude, 0)) + { + new Node(this.Position + direction * nextLength, this); + } + } + + /** + Try to grow a new branch from this one. Only for if this branch doesn't already have any children. + **/ + public void Grow() + { + if (this.Children.Count() != 0) // If this branch doesn't already have any children + return; + + // The math for the falloff is as follows: (branch length falloff param ^ depth of this branch in the tree) + float nextLengthFalloffMult = Mathf.Pow(this.Tree.parameters.BranchLengthFalloff, this.Depth); + + // Get the length of a new branch if it were to grow off of this one + // The math is as follows: (branch length param * branch length falloff multiplier) + // That falloff makes it so that branches get shorter the farther out in the tree they are + float nextLength = this.Tree.parameters.BranchLength * nextLengthFalloffMult; + + // Get the optimal direction for a new branch to grow in + // You pass a vector function that slightly randomizes the direction a bit every attempt: + // (current branch direction + branch randomness) where branch randomness: (distort param * random direction) + // You also pass a minimum distance for that direction to be valid + Vector3 nextDirection = this.getGrowthDirection(() => this.Direction + this.Tree.parameters.Distort * Random.onUnitSphere, nextLength); + + // If the returned direction is zero, then there is no possible valid direction for a new branch. So don't create one. + if (!Mathf.Approximately(nextDirection.magnitude, 0)) + new Node(this.Position + nextDirection * nextLength, this); + } + + /** + Get the optimal direction for a new branch to grow in + You pass a vector function that is used to jitter the direction a bit every attempt + **/ + private Vector3 getGrowthDirection(Func vectorGenerator, float minDistance) + { + Random.InitState(this.Tree.parameters.Seed); + + Vector3 result = Vector3.zero; + float longestDistance = minDistance; + + // Perform at most 20 attempts to find the optimal growth direction + // With every attempt it randomized the direction a bit and checks if there is an obstacle in the way + // If there is no obstacle in the way, then instantly return that test direction + // If not, then check if that obstacle is farther away than the current farthest obstacle + // If not, then discard that attempt + // If so, then keep track of that distance and the direction that caused it + for (int i = 0; i < 20; i++) + { + // Random.InitState(this.Tree.parameters.Seed); + + Vector3 growthDirection = vectorGenerator.Invoke().normalized; // Get the current direction + a bit of randomization + float range = this.raycast(this.Position, growthDirection, 0.01f); // Get the distance to the nearest object in the growth direction + + if (System.Single.IsPositiveInfinity(range)) // There is no obstacle in the way, so just return the growth direction + return growthDirection; + + // If there is an obstacle in the way, but it's farther away than the given minimum distance for this raycast to be valid, then this raycast is still valid. + if (range > longestDistance) + { + result = growthDirection; + longestDistance = range; + } + } + + // Return the best possible direction found. If no direction was found, then it will be zero + return result; + } + public void CalculateEnergy() + { + this.Energy = 1f - 0.001f * this.Depth - Mathf.Exp(-this.raycast(this.Position, Vector3.up, this.Tree.parameters.LeafColliderSize * 1.1f)); + } + + /** + Cast a ray from a given position in a given direction + + Returns the distance to the first object hit by the ray + **/ + private float raycast(Vector3 position, Vector3 direction, float skip = 0f) + { + this.Tree.RayCastCount++; // Increment the raycast count done by this branch's tree + + // Create a ray from the calculated position(tree root position + the given position + the normalized given direction * the skip distance) with the given direction + // Skip is used to offset the origin a tiny bit, so that it doesn't hit this branch + Ray ray = new Ray(this.Tree.transform.position + position + direction.normalized * skip, direction); + Debug.DrawRay(ray.origin, ray.direction, Color.red, 1f); + + RaycastHit hit; + + if (Physics.Raycast(ray, out hit)) // If we hit something, then return the distance to that object + the skip distance + return hit.distance + skip; + else // If we didn't hit anything, then return an infinite distance + return System.Single.PositiveInfinity; + } + + public void CalculateSubtreeSize() + { + if (this.Children.Length == 0) + { + this.SubtreeSize = 1; + } + else + { + foreach (var child in this.Children) + { + child.CalculateSubtreeSize(); + } + + this.SubtreeSize = this.Children.Sum(child => child.SubtreeSize) + 1; + } + } + } +} \ No newline at end of file diff --git a/Assets/TreeGrowth/Scripts/Trees/Scripts/Node.cs.meta b/Assets/TreeGrowth/Scripts/Generation/Node.cs.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Scripts/Node.cs.meta rename to Assets/TreeGrowth/Scripts/Generation/Node.cs.meta diff --git a/Assets/TreeGrowth/Scripts/Generation/TreeGenerator.cs b/Assets/TreeGrowth/Scripts/Generation/TreeGenerator.cs new file mode 100644 index 0000000..7ccd09f --- /dev/null +++ b/Assets/TreeGrowth/Scripts/Generation/TreeGenerator.cs @@ -0,0 +1,344 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace TreeGrowth.Generation +{ + [RequireComponent(typeof(MeshRenderer))] + [RequireComponent(typeof(MeshFilter))] + public class TreeGenerator : MonoBehaviour + { + public TreeParameters parameters; + + [HideInInspector] + public int RayCastCount = 0; + + private MeshFilter meshFilter; + private MeshRenderer meshRenderer; + + public Node Root; + + [HideInInspector] + public GameObject LeafColliders; + + public ColorGenerator[] ColorSchemes; + + public void Awake() + { + this.meshFilter = this.GetComponent(); + this.meshRenderer = this.GetComponent(); + } + + private static float map(float inLower, float inUpper, float outLower, float outUpper, float value) + { + return outLower + (value - inLower) * (outUpper - outLower) / (inUpper - inLower); + } + + private void calculateEnergy() + { + foreach (var node in this.Root.GetTree()) + { + if (node.Children.Length >= parameters.MaxChildrenPerNode) + { + continue; + } + + node.CalculateEnergy(); + } + } + + public void Reset() + { + this.transform.DeleteChildren(); + this.Root = new Node(Vector3.zero, this); + this.RayCastCount = 0; + this.calculateEnergy(); + + this.LeafColliders = new GameObject(); + this.LeafColliders.name = "Leaf Colliders"; + this.LeafColliders.transform.SetParent(this.transform); + this.LeafColliders.transform.localPosition = Vector3.zero; + } + + public void IterateGrowth(TreeParameters parameters) + { + this.parameters = parameters; + + this.Grow(this.parameters.BatchSize); + + this.Prune(0.2f); + + this.meshFilter.sharedMesh = this.CreateMesh(this.parameters.MeshSubdivisions); + + this.createBranchColliders(); + } + + public void Build(TreeParameters parameters) + { + this.parameters = parameters; + + this.Reset(); + for (int i = 0; i < this.parameters.Iterations / this.parameters.BatchSize; i++) + { + this.Grow(this.parameters.BatchSize); + // yield return null; + } + + this.Prune(0.2f); + this.meshFilter.sharedMesh = this.CreateMesh(this.parameters.MeshSubdivisions); + this.createBranchColliders(); + this.LeafColliders.layer = 9; + + if (this.parameters.GenerateLeaves) + { + this.generateColor(); + } + + // var iterator = this.BuildCoroutine(parameters); + // while (iterator.MoveNext()) ; + } + + public void Grow(int batchSize) + { + Node[] nodes = this.Root.GetTree().OrderByDescending(n => n.Energy).ToArray(); + + int remainingOperations = batchSize; + + foreach (Node node in nodes) // For every node in the tree + { + if (node.Children.Length == 0) // If that node has no children + { + node.Grow(); // + remainingOperations--; + } + else if (node.Children.Length < this.parameters.MaxChildrenPerNode && node.Depth > 1) + { + node.Branch(); + remainingOperations--; + } + + if (remainingOperations == 0) + { + break; + } + } + + this.calculateEnergy(); + } + + public void Prune(float amount) + { + var nodes = this.Root.GetTree().Where(n => n.Children.Length == 0).OrderByDescending(n => n.Energy).ToArray(); + + for (int i = 0; i < nodes.Length * amount; i++) + { + if (nodes[i].Parent == null) + { + continue; + } + nodes[i].RemoveLeafCollider(); + nodes[i].Parent.Children = nodes[i].Parent.Children.Where(n => n != nodes[i]).ToArray(); + } + } + + private float getBranchRadius(Node node) + { + return node.Children.Length == 0 ? 0 : map(0, 1, this.parameters.StemSize, this.parameters.BranchSize, Mathf.Pow(map(1, this.Root.SubtreeSize, 1, 0, node.SubtreeSize), this.parameters.SizeFalloff)); + } + + public Mesh CreateMesh(int subdivisions) + { + this.Root.CalculateSubtreeSize(); + + Node[] nodes = this.Root.GetTree().ToArray(); + Node[] leafNodes = nodes.Where(node => node.Children.Length == 0).ToArray(); + + int edgeCount = nodes.Sum(node => node.Children.Length); + int vertexCount = nodes.Length * subdivisions; + + if (edgeCount == 0) + { + return null; + } + + var treeTriangles = new int[(edgeCount * 6 - leafNodes.Length * 3) * (subdivisions - 1)]; + int[] leafTriangles = null; + if (this.parameters.GenerateLeaves) + { + vertexCount += leafNodes.Length * parameters.QUADS_PER_LEAF * 4; + leafTriangles = new int[leafNodes.Length * parameters.QUADS_PER_LEAF * 6]; + } + var vertices = new Vector3[vertexCount]; + var normals = new Vector3[vertexCount]; + var uvs = new Vector2[vertexCount]; + var indices = new Dictionary(); + + int vertexIndex = 0; + foreach (var node in nodes) + { + indices[node] = vertexIndex; + var direction = (node.Children.Any() && node.Parent != null) ? node.Children.Aggregate(Vector3.zero, (v, n) => v + n.Direction).normalized : node.Direction; + if (node.Parent == null) + { + node.MeshOrientation = Vector3.Cross(Vector3.forward, direction); + } + else + { + node.MeshOrientation = (node.Parent.MeshOrientation - direction * Vector3.Dot(direction, node.Parent.MeshOrientation)).normalized; + } + for (int i = 0; i < subdivisions; i++) + { + float progress = (float)i / (subdivisions - 1); + var normal = Quaternion.AngleAxis(360f * progress, direction) * node.MeshOrientation; + normal.Normalize(); + normals[vertexIndex] = normal; + float offset = 0; + if (node.Depth < 4) + { + offset = Mathf.Pow(Mathf.Abs(Mathf.Sin(progress * 2f * Mathf.PI * 5f)), 0.5f) * 0.5f * (3 - node.Depth) / 3f; + } + vertices[vertexIndex] = node.Position + normal * this.getBranchRadius(node) * (1f + offset); + uvs[vertexIndex] = new Vector2(progress * 6f, (node.Depth % 2) * 3f); + vertexIndex++; + } + } + + int triangleIndex = 0; + foreach (var node in nodes) + { + int nodeIndex = indices[node]; + + foreach (var child in node.Children) + { + int childIndex = indices[child]; + + for (int i = 0; i < subdivisions - 1; i++) + { + treeTriangles[triangleIndex++] = nodeIndex + i; + treeTriangles[triangleIndex++] = nodeIndex + i + 1; + treeTriangles[triangleIndex++] = childIndex + i; + } + + if (child.Children.Length != 0) + { + for (int i = 0; i < subdivisions - 1; i++) + { + treeTriangles[triangleIndex++] = nodeIndex + i + 1; + treeTriangles[triangleIndex++] = childIndex + i + 1; + treeTriangles[triangleIndex++] = childIndex + i; + } + } + } + } + triangleIndex = 0; + + if (this.parameters.GenerateLeaves) + { + var leafDirections = new Vector3[parameters.QUADS_PER_LEAF]; + var tangents1 = new Vector3[parameters.QUADS_PER_LEAF]; + var tangents2 = new Vector3[parameters.QUADS_PER_LEAF]; + float increment = Mathf.PI * (3f - Mathf.Sqrt(5f)); + + for (int i = 0; i < parameters.QUADS_PER_LEAF; i++) + { + float y = ((i * 2f / parameters.QUADS_PER_LEAF) - 1) + (1f / parameters.QUADS_PER_LEAF); + float r = Mathf.Sqrt(1 - Mathf.Pow(y, 2f)); + float phi = (i + 1f) * increment; + leafDirections[i] = new Vector3(Mathf.Cos(phi) * r, y, Mathf.Sin(phi) * r); + } + for (int i = 0; i < parameters.QUADS_PER_LEAF; i++) + { + tangents1[i] = Vector3.Cross(leafDirections[i], leafDirections[(i + 1) % parameters.QUADS_PER_LEAF]); + tangents2[i] = Vector3.Cross(leafDirections[i], tangents1[i]); + } + + foreach (var node in leafNodes) + { + var orientation = Quaternion.LookRotation(Random.onUnitSphere, Random.onUnitSphere); + for (int i = 0; i < parameters.QUADS_PER_LEAF; i++) + { + var normal = orientation * leafDirections[i]; + var tangent1 = orientation * tangents1[i]; + var tangent2 = orientation * tangents2[i]; + + vertices[vertexIndex + 0] = node.Position + tangent1 * this.parameters.LeafQuadRadius; + vertices[vertexIndex + 1] = node.Position + tangent2 * this.parameters.LeafQuadRadius; + vertices[vertexIndex + 2] = node.Position - tangent1 * this.parameters.LeafQuadRadius; + vertices[vertexIndex + 3] = node.Position - tangent2 * this.parameters.LeafQuadRadius; + normals[vertexIndex + 0] = normal; + normals[vertexIndex + 1] = normal; + normals[vertexIndex + 2] = normal; + normals[vertexIndex + 3] = normal; + uvs[vertexIndex + 0] = new Vector2(0f, 1f); + uvs[vertexIndex + 1] = new Vector2(1f, 1f); + uvs[vertexIndex + 2] = new Vector2(1f, 0f); + uvs[vertexIndex + 3] = new Vector2(0f, 0f); + leafTriangles[triangleIndex++] = vertexIndex + 0; + leafTriangles[triangleIndex++] = vertexIndex + 1; + leafTriangles[triangleIndex++] = vertexIndex + 2; + leafTriangles[triangleIndex++] = vertexIndex + 2; + leafTriangles[triangleIndex++] = vertexIndex + 3; + leafTriangles[triangleIndex++] = vertexIndex + 0; + vertexIndex += 4; + } + } + } + + var mesh = new Mesh(); + mesh.subMeshCount = 2; + mesh.vertices = vertices; + mesh.normals = normals; + mesh.uv = uvs; + mesh.SetTriangles(treeTriangles, 0); + if (this.parameters.GenerateLeaves) + { + mesh.SetTriangles(leafTriangles, 1); + } + return mesh; + } + + private void createBranchColliders() + { + foreach (Node node in this.Root.GetTree()) + { + if (node.Parent == null || node.Depth > 6) + continue; + + Vector3 position1 = node.Parent.Position; + Vector3 position2 = node.Position; + + GameObject container = new GameObject(); + container.name = "Branch Collider"; + container.transform.SetParent(this.transform); + container.transform.localPosition = (position1 + position2) * 0.5f; + container.transform.localRotation = Quaternion.LookRotation(position2 - position1); + + CapsuleCollider collider = container.AddComponent(); + float radius = this.getBranchRadius(node.Parent); + collider.radius = radius; + collider.height = (position2 - position1).magnitude + radius * 2f; + collider.direction = 2; + } + } + + private void generateColor() + { + float totalProbability = this.ColorSchemes.Sum(s => s.Probability); + float roll = Random.Range(0f, totalProbability); + foreach (var item in this.ColorSchemes) + { + if (item.Probability > roll) + { + this.meshRenderer.materials[1].color = item.GetColor(); + return; + } + else + { + roll -= item.Probability; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/TreeGrowth/Scripts/Trees/Scripts/TreeGenerator.cs.meta b/Assets/TreeGrowth/Scripts/Generation/TreeGenerator.cs.meta similarity index 100% rename from Assets/TreeGrowth/Scripts/Trees/Scripts/TreeGenerator.cs.meta rename to Assets/TreeGrowth/Scripts/Generation/TreeGenerator.cs.meta diff --git a/Assets/TreeGrowth/Scripts/Generation/TreeTester.cs b/Assets/TreeGrowth/Scripts/Generation/TreeTester.cs new file mode 100644 index 0000000..9541dd1 --- /dev/null +++ b/Assets/TreeGrowth/Scripts/Generation/TreeTester.cs @@ -0,0 +1,49 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace TreeGrowth.Generation +{ + public class TreeTester : MonoBehaviour + { + public bool Generate = false; + public bool GrowTick = false; + public TreeParameters Parameters; + + private TreeGenerator gen; + + void Start() + { + gen = GetComponent(); + } + + void Update() + { + Random.State origState = Random.state; + Random.InitState(Parameters.Seed); + + if (Generate) + { + Generate = false; + + gen.Build(Parameters); + } + + if (GrowTick) + { + GrowTick = false; + + gen.IterateGrowth(Parameters); + } + + tickTree(); + + Random.state = origState; + } + + private void tickTree() + { + + } + } +} \ No newline at end of file diff --git a/Assets/TreeGrowth/Scripts/Trees/Scripts/TreePlacer.cs.meta b/Assets/TreeGrowth/Scripts/Generation/TreeTester.cs.meta similarity index 83% rename from Assets/TreeGrowth/Scripts/Trees/Scripts/TreePlacer.cs.meta rename to Assets/TreeGrowth/Scripts/Generation/TreeTester.cs.meta index 0e9deee..5fda9eb 100644 --- a/Assets/TreeGrowth/Scripts/Trees/Scripts/TreePlacer.cs.meta +++ b/Assets/TreeGrowth/Scripts/Generation/TreeTester.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 68f61647aad0b9c47af6679d2fdd9005 +guid: 9bbd394eafb6db14b90ea1a78711a61e MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/TreeGrowth/Scripts/TreeCellData.cs b/Assets/TreeGrowth/Scripts/TreeCellData.cs index ee1cde5..2cf48b4 100644 --- a/Assets/TreeGrowth/Scripts/TreeCellData.cs +++ b/Assets/TreeGrowth/Scripts/TreeCellData.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using SimDataStructure.Data; using UnityEngine; +using TreeGrowth.Generation; namespace TreeGrowth { diff --git a/Assets/TreeGrowth/Scripts/TreeManager.cs b/Assets/TreeGrowth/Scripts/TreeManager.cs index f06a8fc..e4f8cc7 100644 --- a/Assets/TreeGrowth/Scripts/TreeManager.cs +++ b/Assets/TreeGrowth/Scripts/TreeManager.cs @@ -7,6 +7,7 @@ using SimDataStructure.Data; using SimDataStructure.Interfaces; using UnityEngine; +using TreeGrowth.Generation; namespace TreeGrowth { @@ -20,14 +21,17 @@ public class TreeManager : MonoBehaviour, ITickableSystem, IReadCellData, IWrite [SerializeReference] public List nulledTrees = new List(); - public bool first = true; + public bool GenerateInitialTrees = true; + public bool CollectInitialChildTrees = true; + public int InitialTreeCount = 100; + public Bounds InitialTreeGenerationBounds = new Bounds(new Vector3(-50, 0, -50), new Vector3(50, 0, 50)); public GameObject TestTreePrefab; - - public Bounds initialTreeGenerationBounds = new Bounds(new Vector3(-50, 0, -50), new Vector3(50, 0, 50)); - + public TreeParameters TestParameters; #endregion #region Private + private bool collectedChildren = false; + #region Interface Stuff // [Header("Data Structure")] private Dictionary _readDataNames = new Dictionary() { @@ -47,6 +51,7 @@ public class TreeManager : MonoBehaviour, ITickableSystem, IReadCellData, IWrite public int TickInterval { get { return 5; } } public int ticksSinceLastTick { get; set; } public bool willTickNow { get; set; } + public bool shouldTick { get { return this.isActiveAndEnabled; } } #endregion #endregion @@ -61,13 +66,37 @@ public void BeginTick(float deltaTime) { this.newTrees.Clear(); this.nulledTrees.Clear(); + + if (CollectInitialChildTrees == true && !collectedChildren) + { + collectedChildren = true; + + foreach (Transform child in transform) + { + GameObject childGO = child.gameObject; + TreeGenerator treeGen = childGO.GetComponent(); + + if (treeGen != null) + { + Mesh mesh = childGO.GetComponent().mesh; + MeshCollider collider = childGO.GetComponent(); + + // treeGen.StartCoroutine(treeGen.BuildCoroutine(TestParameters)); + treeGen.Build(TestParameters); + + TreeCellData tree = new TreeCellData(childGO, treeGen, mesh, collider, null); + + newTrees.Add(tree); + } + } + } } public void Tick(float deltaTime) { - if (first == true) + if (GenerateInitialTrees == true) { - first = false; + GenerateInitialTrees = false; createInitialTrees(); } @@ -110,7 +139,10 @@ public Dictionary, List> writeCellDataToAdd List treeData = new List(); foreach (TreeCellData tree in this.newTrees) + { treeData.Add(tree); + trees.Add(tree); + } if (treeData.Count > 0) data.Add(new Tuple(readWriteName, readWriteLevel), treeData); @@ -126,7 +158,10 @@ public Dictionary, List> writeCellDataToRem List treeData = new List(); foreach (TreeCellData tree in this.nulledTrees) + { treeData.Add(tree); + trees.Remove(tree); + } if (treeData.Count > 0) data.Add(new Tuple(readWriteName, readWriteLevel), treeData); @@ -135,16 +170,18 @@ public Dictionary, List> writeCellDataToRem } #endregion + #region Tree Growth private void createInitialTrees() { - for (int i = 0; i < 100; i++) + for (int i = 0; i < InitialTreeCount; i++) { - Vector3 randPos = new Vector3(UnityEngine.Random.Range(initialTreeGenerationBounds.min.x, initialTreeGenerationBounds.max.x), 0, UnityEngine.Random.Range(initialTreeGenerationBounds.min.z, initialTreeGenerationBounds.max.z)); + Vector3 randPos = new Vector3(UnityEngine.Random.Range(InitialTreeGenerationBounds.min.x, InitialTreeGenerationBounds.max.x), 0, UnityEngine.Random.Range(InitialTreeGenerationBounds.min.z, InitialTreeGenerationBounds.max.z)); GameObject testTree = Instantiate(this.TestTreePrefab, randPos, Quaternion.identity); TreeGenerator gen = testTree.GetComponent(); - gen.StartCoroutine(gen.BuildCoroutine()); + // gen.StartCoroutine(gen.BuildCoroutine(TestParameters)) + gen.Build(TestParameters); Mesh mesh = testTree.GetComponent().mesh; MeshCollider collider = testTree.GetComponent(); @@ -158,6 +195,10 @@ private void createInitialTrees() private void tickTree(TreeCellData tree) { // if () + // { + + // } } + #endregion } } \ No newline at end of file diff --git a/Assets/TreeGrowth/Scripts/TreeParameters.cs b/Assets/TreeGrowth/Scripts/TreeParameters.cs index a648a69..0b8441a 100644 --- a/Assets/TreeGrowth/Scripts/TreeParameters.cs +++ b/Assets/TreeGrowth/Scripts/TreeParameters.cs @@ -1,13 +1,14 @@ using UnityEngine; using System.Collections; using System.Collections.Generic; +using TreeGrowth.Generation; namespace TreeGrowth { [System.Serializable] public record TreeParameters { - private const int QUADS_PER_LEAF = 16; + public int QUADS_PER_LEAF = 16; [Range(0.0f, 0.6f)] public float StemSize = 0.3f; @@ -36,21 +37,18 @@ public record TreeParameters [Range(10, 1000)] public int Iterations = 100; - public Node Root; - public bool GenerateLeaves = true; [Range(0.2f, 1f)] public float LeafQuadRadius = 0.3f; - [HideInInspector] - public int RayCastCount; - public int MaxChildrenPerNode = 3; public int MeshSubdivisions = 5; [Range(1, 20)] public int BatchSize = 5; + + public int Seed = 0; } } \ No newline at end of file diff --git a/Assets/TreeGrowth/Scripts/Trees.meta b/Assets/TreeGrowth/Scripts/Trees.meta deleted file mode 100644 index fe954bf..0000000 --- a/Assets/TreeGrowth/Scripts/Trees.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d75424271af7fd14fad927d76edaab9b -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/TreeGrowth/Scripts/Trees/Art.meta b/Assets/TreeGrowth/Scripts/Trees/Art.meta deleted file mode 100644 index 2e8886e..0000000 --- a/Assets/TreeGrowth/Scripts/Trees/Art.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b32baf520f05b7b42a7c9ad63c970f09 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/TreeGrowth/Scripts/Trees/Scenes.meta b/Assets/TreeGrowth/Scripts/Trees/Scenes.meta deleted file mode 100644 index 59d78ac..0000000 --- a/Assets/TreeGrowth/Scripts/Trees/Scenes.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e7cc82ace921dd244b3ba33df873aeb4 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/TreeGrowth/Scripts/Trees/Scripts/ColorGenerator.cs b/Assets/TreeGrowth/Scripts/Trees/Scripts/ColorGenerator.cs deleted file mode 100644 index 92f2bce..0000000 --- a/Assets/TreeGrowth/Scripts/Trees/Scripts/ColorGenerator.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -[System.Serializable] -public class ColorGenerator { - public float Probability = 1; - - [Range(0f, 1f)] - public float HueMin; - [Range(0f, 1f)] - public float HueMax; - - [Range(0f, 1f)] - public float SaturationMin; - [Range(0f, 1f)] - public float SaturationMax; - - [Range(0f, 1f)] - public float ValueMin; - [Range(0f, 1f)] - public float ValueMax; - - public Color GetColor() { - return Color.HSVToRGB( - Random.Range(this.HueMin, this.HueMax), - Random.Range(this.SaturationMin, this.SaturationMax), - Random.Range(this.ValueMin, this.ValueMax) - ); - } -} diff --git a/Assets/TreeGrowth/Scripts/Trees/Scripts/Node.cs b/Assets/TreeGrowth/Scripts/Trees/Scripts/Node.cs deleted file mode 100644 index 5077d77..0000000 --- a/Assets/TreeGrowth/Scripts/Trees/Scripts/Node.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using System.Linq; -using UnityEditor; -using System; - -public class Node { - public readonly Vector3 Position; - public readonly Vector3 Direction; - public readonly TreeGenerator Tree; - - public readonly int Depth; - public float Energy; - - public readonly Node Parent; - public Node[] Children; - - public SphereCollider LeafCollider; - public Vector3 MeshOrientation; - - public int SubtreeSize { - get; - private set; - } - - public Node(Vector3 position, TreeGenerator tree) { - this.Position = position; - this.Direction = Vector3.up; - this.Depth = 0; - this.Children = new Node[] { }; - this.Tree = tree; - } - - public Node(Vector3 position, Node parent) { - this.Position = position; - this.Direction = (this.Position - parent.Position).normalized; - this.Depth = parent.Depth + 1; - this.Children = new Node[] { }; - parent.Children = parent.Children.Concat(new Node[] { this }).ToArray(); - this.Tree = parent.Tree; - this.CrateLeafCollider(); - this.Parent = parent; - } - - public void CrateLeafCollider() { - this.LeafCollider = this.Tree.LeafColliders.AddComponent(); - this.LeafCollider.center = this.Position; - this.LeafCollider.radius = this.Tree.LeafColliderSize; - } - - public void RemoveLeafCollider() { - if (this.LeafCollider == null) { - return; - } - GameObject.DestroyImmediate(this.LeafCollider); - } - - public IEnumerable GetTree() { - yield return this; - Node currentNode = this; - var positions = new Stack(); - int currentPosition = 0; - - while (true) { - if (currentPosition < currentNode.Children.Length) { - var child = currentNode.Children[currentPosition]; - currentPosition++; - yield return child; - if (child.Children.Length > 0) { - currentNode = child; - positions.Push(currentPosition); - currentPosition = 0; - } - } else if (currentNode.Parent != null) { - currentPosition = positions.Pop(); - currentNode = currentNode.Parent; - } else { - yield break; - } - } - } - - private float raycast(Vector3 position, Vector3 direction, float skip = 0f) { - this.Tree.RayCastCount++; - var ray = new Ray(this.Tree.transform.position + position + direction.normalized * skip, direction); - RaycastHit hit; - if (Physics.Raycast(ray, out hit)) { - return hit.distance + skip; - } else { - return System.Single.PositiveInfinity; - } - } - - - public void Branch() { - if (this.Children.Count() == 0) { - return; - } - - float length = this.Tree.BranchLength * Mathf.Pow(this.Tree.BranchLengthFalloff, this.Depth); - var childDir = this.Children[0].Direction; - var direction = this.getGrowthDirection(() => childDir * Mathf.Cos(this.Tree.BranchAngle * Mathf.Deg2Rad) + Vector3.Cross(childDir, UnityEngine.Random.onUnitSphere) * Mathf.Sign(this.Tree.BranchAngle * Mathf.Rad2Deg), length); - - if (!Mathf.Approximately(direction.magnitude, 0)) { - new Node(this.Position + direction * length, this); - } - } - - private Vector3 getGrowthDirection(Func vectorGenerator, float minDistance) { - Vector3 result = Vector3.zero; - float longestDistance = minDistance; - - for (int i = 0; i < 20; i++) { - var direction = vectorGenerator.Invoke().normalized; - float range = this.raycast(this.Position, direction, 0.01f); - if (System.Single.IsPositiveInfinity(range)) { - return direction; - } - if (range > longestDistance) { - result = direction; - longestDistance = range; - } - } - return result; - } - - public void Grow() { - if (this.Children.Count() != 0) { - return; - } - - float length = this.Tree.BranchLength * Mathf.Pow(this.Tree.BranchLengthFalloff, this.Depth); - var direction = this.getGrowthDirection(() => this.Direction + this.Tree.Distort * UnityEngine.Random.onUnitSphere, length); - - if (!Mathf.Approximately(direction.magnitude, 0)) { - new Node(this.Position + direction * length, this); - } - } - - public void CalculateEnergy() { - this.Energy = 1f -0.001f * this.Depth - Mathf.Exp(-this.raycast(this.Position, Vector3.up, this.Tree.LeafColliderSize * 1.1f)); - } - - public void CalculateSubtreeSize() { - if (this.Children.Length == 0) { - this.SubtreeSize = 1; - } else { - foreach (var child in this.Children) { - child.CalculateSubtreeSize(); - } - this.SubtreeSize = this.Children.Sum(child => child.SubtreeSize) + 1; - } - } -} \ No newline at end of file diff --git a/Assets/TreeGrowth/Scripts/Trees/Scripts/TreeGenerator.cs b/Assets/TreeGrowth/Scripts/Trees/Scripts/TreeGenerator.cs deleted file mode 100644 index 4f056d8..0000000 --- a/Assets/TreeGrowth/Scripts/Trees/Scripts/TreeGenerator.cs +++ /dev/null @@ -1,306 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEditor; -using UnityEngine; - -[RequireComponent(typeof(MeshRenderer))] -[RequireComponent(typeof(MeshFilter))] -public class TreeGenerator : MonoBehaviour { - private const int QUADS_PER_LEAF = 16; - - [Range(0.0f, 0.6f)] - public float StemSize = 0.3f; - - [Range(0.0f, 0.1f)] - public float BranchSize = 0.1f; - - [Range(0.1f, 4f)] - public float SizeFalloff = 0.9f; - - [Range(0f, 0.5f)] - public float Distort = 0.5f; - - [Range(0f, 1.2f)] - public float BranchLength = 2f; - - [Range(0.1f, 0.5f)] - public float LeafColliderSize = 0.2f; - - [Range(0f, 90f)] - public float BranchAngle = 30f; - - [Range(0.9f, 1f)] - public float BranchLengthFalloff = 0.9f; - - [Range(10, 1000)] - public int Iterations = 100; - - public Node Root; - - public bool GenerateLeaves = true; - - [Range(0.2f, 1f)] - public float LeafQuadRadius = 0.3f; - - [HideInInspector] - public int RayCastCount; - - public int MaxChildrenPerNode = 3; - - public int MeshSubdivisions = 5; - - [Range(1, 20)] - public int BatchSize = 5; - - [HideInInspector] - public GameObject LeafColliders; - - public ColorGenerator[] ColorSchemes; - - private static float map(float inLower, float inUpper, float outLower, float outUpper, float value) { - return outLower + (value - inLower) * (outUpper - outLower) / (inUpper - inLower); - } - - private void calculateEnergy() { - foreach (var node in this.Root.GetTree()) { - if (node.Children.Length >= MaxChildrenPerNode) { - continue; - } - node.CalculateEnergy(); - } - } - - public void Reset() { - this.transform.DeleteChildren(); - this.Root = new Node(Vector3.zero, this); - this.RayCastCount = 0; - this.calculateEnergy(); - - this.LeafColliders = new GameObject(); - this.LeafColliders.name = "Leaf Colliders"; - this.LeafColliders.transform.SetParent(this.transform); - this.LeafColliders.transform.localPosition = Vector3.zero; - } - - public void Grow(int batchSize) { - var nodes = this.Root.GetTree().OrderByDescending(n => n.Energy).ToArray(); - - int remainingOperations = batchSize; - foreach (var node in nodes) { - if (node.Children.Length == 0) { - node.Grow(); - remainingOperations--; - } else if (node.Children.Length < this.MaxChildrenPerNode && node.Depth > 1) { - node.Branch(); - remainingOperations--; - } - if (remainingOperations == 0) { - break; - } - } - - this.calculateEnergy(); - } - - public void Prune(float amount) { - var nodes = this.Root.GetTree().Where(n => n.Children.Length == 0).OrderByDescending(n => n.Energy).ToArray(); - - for (int i = 0; i < nodes.Length * amount; i++) { - if (nodes[i].Parent == null) { - continue; - } - nodes[i].RemoveLeafCollider(); - nodes[i].Parent.Children = nodes[i].Parent.Children.Where(n => n != nodes[i]).ToArray(); - } - } - - public void Build() { - var iterator = this.BuildCoroutine(); - while (iterator.MoveNext()); - } - - public IEnumerator BuildCoroutine() { - this.Reset(); - for (int i = 0; i < this.Iterations / this.BatchSize; i++) { - this.Grow(this.BatchSize); - yield return null; - } - - this.Prune(0.2f); - this.GetComponent().sharedMesh = this.CreateMesh(this.MeshSubdivisions); - this.createBranchColliders(); - this.LeafColliders.layer = 9; - if (this.GenerateLeaves) { - this.generateColor(); - } - } - - private float getBranchRadius(Node node) { - return node.Children.Length == 0 ? 0 : map(0, 1, this.StemSize, this.BranchSize, Mathf.Pow(map(1, this.Root.SubtreeSize, 1, 0, node.SubtreeSize), this.SizeFalloff)); - } - - public Mesh CreateMesh(int subdivisions) { - this.Root.CalculateSubtreeSize(); - var nodes = this.Root.GetTree().ToArray(); - var leafNodes = nodes.Where(node => node.Children.Length == 0).ToArray(); - int edgeCount = nodes.Sum(node => node.Children.Length); - int vertexCount = nodes.Length * subdivisions; - - if (edgeCount == 0) { - return null; - } - - var treeTriangles = new int[(edgeCount * 6 - leafNodes.Length * 3) * (subdivisions - 1)]; - int[] leafTriangles = null; - if (this.GenerateLeaves) { - vertexCount += leafNodes.Length * QUADS_PER_LEAF * 4; - leafTriangles = new int[leafNodes.Length * QUADS_PER_LEAF * 6]; - } - var vertices = new Vector3[vertexCount]; - var normals = new Vector3[vertexCount]; - var uvs = new Vector2[vertexCount]; - var indices = new Dictionary(); - - int vertexIndex = 0; - foreach (var node in nodes) { - indices[node] = vertexIndex; - var direction = (node.Children.Any() && node.Parent != null) ? node.Children.Aggregate(Vector3.zero, (v, n) => v + n.Direction).normalized : node.Direction; - if (node.Parent == null) { - node.MeshOrientation = Vector3.Cross(Vector3.forward, direction); - } else { - node.MeshOrientation = (node.Parent.MeshOrientation - direction * Vector3.Dot(direction, node.Parent.MeshOrientation)).normalized; - } - for (int i = 0; i < subdivisions; i++) { - float progress = (float)i / (subdivisions - 1); - var normal = Quaternion.AngleAxis(360f * progress, direction) * node.MeshOrientation; - normal.Normalize(); - normals[vertexIndex] = normal; - float offset = 0; - if (node.Depth < 4) { - offset = Mathf.Pow(Mathf.Abs(Mathf.Sin(progress * 2f * Mathf.PI * 5f)), 0.5f) * 0.5f * (3 - node.Depth) / 3f; - } - vertices[vertexIndex] = node.Position + normal * this.getBranchRadius(node) * (1f + offset); - uvs[vertexIndex] = new Vector2(progress * 6f, (node.Depth % 2) * 3f); - vertexIndex++; - } - } - - int triangleIndex = 0; - foreach (var node in nodes) { - int nodeIndex = indices[node]; - - foreach (var child in node.Children) { - int childIndex = indices[child]; - - for (int i = 0; i < subdivisions - 1; i++) { - treeTriangles[triangleIndex++] = nodeIndex + i; - treeTriangles[triangleIndex++] = nodeIndex + i + 1; - treeTriangles[triangleIndex++] = childIndex + i; - } - - if (child.Children.Length != 0) { - for (int i = 0; i < subdivisions - 1; i++) { - treeTriangles[triangleIndex++] = nodeIndex + i + 1; - treeTriangles[triangleIndex++] = childIndex + i + 1; - treeTriangles[triangleIndex++] = childIndex + i; - } - } - } - } - triangleIndex = 0; - - if (this.GenerateLeaves) { - var leafDirections = new Vector3[QUADS_PER_LEAF]; - var tangents1 = new Vector3[QUADS_PER_LEAF]; - var tangents2 = new Vector3[QUADS_PER_LEAF]; - float increment = Mathf.PI * (3f - Mathf.Sqrt(5f)); - - for (int i = 0; i < QUADS_PER_LEAF; i++) { - float y = ((i * 2f / QUADS_PER_LEAF) - 1) + (1f / QUADS_PER_LEAF); - float r = Mathf.Sqrt(1 - Mathf.Pow(y, 2f)); - float phi = (i + 1f) * increment; - leafDirections[i] = new Vector3(Mathf.Cos(phi) * r, y, Mathf.Sin(phi) * r); - } - for (int i = 0; i < QUADS_PER_LEAF; i++) { - tangents1[i] = Vector3.Cross(leafDirections[i], leafDirections[(i + 1) % QUADS_PER_LEAF]); - tangents2[i] = Vector3.Cross(leafDirections[i], tangents1[i]); - } - - foreach (var node in leafNodes) { - var orientation = Quaternion.LookRotation(Random.onUnitSphere, Random.onUnitSphere); - for (int i = 0; i < QUADS_PER_LEAF; i++) { - var normal = orientation * leafDirections[i]; - var tangent1 = orientation * tangents1[i]; - var tangent2 = orientation * tangents2[i]; - - vertices[vertexIndex + 0] = node.Position + tangent1 * this.LeafQuadRadius; - vertices[vertexIndex + 1] = node.Position + tangent2 * this.LeafQuadRadius; - vertices[vertexIndex + 2] = node.Position - tangent1 * this.LeafQuadRadius; - vertices[vertexIndex + 3] = node.Position - tangent2 * this.LeafQuadRadius; - normals[vertexIndex + 0] = normal; - normals[vertexIndex + 1] = normal; - normals[vertexIndex + 2] = normal; - normals[vertexIndex + 3] = normal; - uvs[vertexIndex + 0] = new Vector2(0f, 1f); - uvs[vertexIndex + 1] = new Vector2(1f, 1f); - uvs[vertexIndex + 2] = new Vector2(1f, 0f); - uvs[vertexIndex + 3] = new Vector2(0f, 0f); - leafTriangles[triangleIndex++] = vertexIndex + 0; - leafTriangles[triangleIndex++] = vertexIndex + 1; - leafTriangles[triangleIndex++] = vertexIndex + 2; - leafTriangles[triangleIndex++] = vertexIndex + 2; - leafTriangles[triangleIndex++] = vertexIndex + 3; - leafTriangles[triangleIndex++] = vertexIndex + 0; - vertexIndex += 4; - } - } - } - - var mesh = new Mesh(); - mesh.subMeshCount = 2; - mesh.vertices = vertices; - mesh.normals = normals; - mesh.uv = uvs; - mesh.SetTriangles(treeTriangles, 0); - if (this.GenerateLeaves) { - mesh.SetTriangles(leafTriangles, 1); - } - return mesh; - } - - private void createBranchColliders() { - foreach (var node in this.Root.GetTree()) { - if (node.Parent == null || node.Depth > 6) { - continue; - } - var position1 = node.Parent.Position; - var position2 = node.Position; - - var container = new GameObject(); - container.name = "Branch Collider"; - container.transform.SetParent(this.transform); - container.transform.localPosition = (position1 + position2) * 0.5f; - container.transform.localRotation = Quaternion.LookRotation(position2 - position1); - - var collider = container.AddComponent(); - float radius = this.getBranchRadius(node.Parent); - collider.radius = radius; - collider.height = (position2 - position1).magnitude + radius * 2f; - collider.direction = 2; - } - } - - private void generateColor() { - float totalProbability = this.ColorSchemes.Sum(s => s.Probability); - float roll = Random.Range(0f, totalProbability); - foreach (var item in this.ColorSchemes) { - if (item.Probability > roll) { - this.GetComponent().materials[1].color = item.GetColor(); - return; - } else { - roll -= item.Probability; - } - } - } -} diff --git a/Assets/TreeGrowth/Scripts/Trees/Scripts/TreePlacer.cs b/Assets/TreeGrowth/Scripts/Trees/Scripts/TreePlacer.cs deleted file mode 100644 index 5ce82ea..0000000 --- a/Assets/TreeGrowth/Scripts/Trees/Scripts/TreePlacer.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using System.Linq; - -public class TreePlacer : MonoBehaviour -{ - public TreeGenerator TreeGenerator; - public bool Generate = false; - - public void Update() - { - if (Generate) - { - Generate = false; - - GenerateTree(TreeGenerator.transform.position); - } - } - - public void GenerateTree(Vector3 position) - { - this.TreeGenerator.StartCoroutine(TreeGenerator.BuildCoroutine()); - } -} \ No newline at end of file diff --git a/Assets/Visuals/Visuals.asmdef b/Assets/Visuals/Visuals.asmdef deleted file mode 100644 index 23e04bb..0000000 --- a/Assets/Visuals/Visuals.asmdef +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "Visualas" -} diff --git a/Assets/Visuals/Visuals.asmdef.meta b/Assets/Visuals/Visuals.asmdef.meta deleted file mode 100644 index 1a57599..0000000 --- a/Assets/Visuals/Visuals.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: b927d37d0b629bd479ea58987b1a8879 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/WaterSimulation/Scripts/WaterSimDebug.cs b/Assets/WaterSimulation/Scripts/WaterSimDebug.cs index 37adc18..3608c5f 100644 --- a/Assets/WaterSimulation/Scripts/WaterSimDebug.cs +++ b/Assets/WaterSimulation/Scripts/WaterSimDebug.cs @@ -33,6 +33,7 @@ public class WaterSimDebug : MonoBehaviour, ITickableSystem, IReadGridData public int TickInterval { get { return 5; } } public int ticksSinceLastTick { get; set; } public bool willTickNow { get; set; } + public bool shouldTick { get { return this.isActiveAndEnabled; } } private Dictionary _readDataNames = new Dictionary() { { "waterHeight", 0 }, diff --git a/Assets/WaterSimulation/Scripts/WaterSimulation.cs b/Assets/WaterSimulation/Scripts/WaterSimulation.cs index 89c7a45..3fb3eb5 100644 --- a/Assets/WaterSimulation/Scripts/WaterSimulation.cs +++ b/Assets/WaterSimulation/Scripts/WaterSimulation.cs @@ -144,6 +144,7 @@ public class WaterSimulation : MonoBehaviour, ITickableSystem, IReadGridData, IW public int TickInterval { get { return 5; } } public int ticksSinceLastTick { get; set; } public bool willTickNow { get; set; } + public bool shouldTick { get { return this.isActiveAndEnabled; } } #endregion #endregion diff --git a/ProjectSettings/BurstAotSettings_StandaloneWindows.json b/ProjectSettings/BurstAotSettings_StandaloneWindows.json new file mode 100644 index 0000000..e02ae33 --- /dev/null +++ b/ProjectSettings/BurstAotSettings_StandaloneWindows.json @@ -0,0 +1,17 @@ +{ + "MonoBehaviour": { + "Version": 4, + "EnableBurstCompilation": true, + "EnableOptimisations": true, + "EnableSafetyChecks": false, + "EnableDebugInAllBuilds": false, + "UsePlatformSDKLinker": false, + "CpuMinTargetX32": 0, + "CpuMaxTargetX32": 0, + "CpuMinTargetX64": 0, + "CpuMaxTargetX64": 0, + "CpuTargetsX32": 6, + "CpuTargetsX64": 72, + "OptimizeFor": 0 + } +} diff --git a/ProjectSettings/BurstAotSettings_WSAPlayer.json b/ProjectSettings/BurstAotSettings_WSAPlayer.json new file mode 100644 index 0000000..64de35e --- /dev/null +++ b/ProjectSettings/BurstAotSettings_WSAPlayer.json @@ -0,0 +1,16 @@ +{ + "MonoBehaviour": { + "Version": 4, + "EnableBurstCompilation": true, + "EnableOptimisations": true, + "EnableSafetyChecks": false, + "EnableDebugInAllBuilds": false, + "CpuMinTargetX32": 0, + "CpuMaxTargetX32": 0, + "CpuMinTargetX64": 0, + "CpuMaxTargetX64": 0, + "CpuTargetsX32": 6, + "CpuTargetsX64": 72, + "OptimizeFor": 0 + } +} diff --git a/ProjectSettings/CommonBurstAotSettings.json b/ProjectSettings/CommonBurstAotSettings.json new file mode 100644 index 0000000..0293daf --- /dev/null +++ b/ProjectSettings/CommonBurstAotSettings.json @@ -0,0 +1,6 @@ +{ + "MonoBehaviour": { + "Version": 4, + "DisabledWarnings": "" + } +} diff --git a/ProjectSettings/EditorSettings.asset b/ProjectSettings/EditorSettings.asset index 1e44a0a..fc4345d 100644 --- a/ProjectSettings/EditorSettings.asset +++ b/ProjectSettings/EditorSettings.asset @@ -4,7 +4,6 @@ EditorSettings: m_ObjectHideFlags: 0 serializedVersion: 11 - m_ExternalVersionControlSupport: Visible Meta Files m_SerializationMode: 2 m_LineEndingsForNewScripts: 0 m_DefaultBehaviorMode: 0 @@ -12,19 +11,34 @@ EditorSettings: m_PrefabUIEnvironment: {fileID: 0} m_SpritePackerMode: 0 m_SpritePackerPaddingPower: 1 + m_Bc7TextureCompressor: 0 m_EtcTextureCompressorBehavior: 1 m_EtcTextureFastCompressor: 1 m_EtcTextureNormalCompressor: 2 m_EtcTextureBestCompressor: 4 m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref m_ProjectGenerationRootNamespace: - m_CollabEditorSettings: - inProgressEnabled: 1 m_EnableTextureStreamingInEditMode: 1 m_EnableTextureStreamingInPlayMode: 1 m_AsyncShaderCompilation: 1 - m_EnterPlayModeOptionsEnabled: 0 - m_EnterPlayModeOptions: 3 - m_ShowLightmapResolutionOverlay: 1 + m_CachingShaderPreprocessor: 1 + m_PrefabModeAllowAutoSave: 1 + m_EnterPlayModeOptionsEnabled: 1 + m_EnterPlayModeOptions: 0 + m_GameObjectNamingDigits: 1 + m_GameObjectNamingScheme: 0 + m_AssetNamingUsesSpace: 1 m_UseLegacyProbeSampleCount: 0 m_SerializeInlineMappingsOnOneLine: 1 + m_DisableCookiesInLightmapper: 0 + m_AssetPipelineMode: 1 + m_RefreshImportMode: 0 + m_CacheServerMode: 0 + m_CacheServerEndpoint: + m_CacheServerNamespacePrefix: default + m_CacheServerEnableDownload: 1 + m_CacheServerEnableUpload: 1 + m_CacheServerEnableAuth: 0 + m_CacheServerEnableTls: 0 + m_CacheServerValidationMode: 2 + m_CacheServerDownloadBatchSize: 128 diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset index 36c0dad..1fe2c63 100644 --- a/ProjectSettings/QualitySettings.asset +++ b/ProjectSettings/QualitySettings.asset @@ -18,7 +18,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 - blendWeights: 1 + skinWeights: 1 textureQuality: 1 anisotropicTextures: 0 antiAliasing: 0 @@ -40,6 +40,7 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} excludedTargetPlatforms: [] - serializedVersion: 2 name: Low @@ -53,7 +54,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 - blendWeights: 2 + skinWeights: 2 textureQuality: 0 anisotropicTextures: 0 antiAliasing: 0 @@ -75,6 +76,7 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} excludedTargetPlatforms: [] - serializedVersion: 2 name: Medium @@ -88,7 +90,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 - blendWeights: 2 + skinWeights: 2 textureQuality: 0 anisotropicTextures: 1 antiAliasing: 0 @@ -110,6 +112,7 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} excludedTargetPlatforms: [] - serializedVersion: 2 name: High @@ -123,7 +126,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 - blendWeights: 2 + skinWeights: 2 textureQuality: 0 anisotropicTextures: 1 antiAliasing: 0 @@ -145,6 +148,7 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} excludedTargetPlatforms: [] - serializedVersion: 2 name: Very High @@ -158,7 +162,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 - blendWeights: 4 + skinWeights: 4 textureQuality: 0 anisotropicTextures: 2 antiAliasing: 2 @@ -180,6 +184,7 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} excludedTargetPlatforms: [] - serializedVersion: 2 name: Ultra @@ -193,7 +198,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 - blendWeights: 4 + skinWeights: 4 textureQuality: 0 anisotropicTextures: 2 antiAliasing: 2 @@ -215,16 +220,18 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} excludedTargetPlatforms: [] m_PerPlatformDefaultQuality: Android: 2 - Lumin: 5 GameCoreScarlett: 5 GameCoreXboxOne: 5 + Lumin: 5 Nintendo 3DS: 5 Nintendo Switch: 5 PS4: 5 PS5: 5 + Server: 0 Stadia: 5 Standalone: 5 WebGL: 3