Last active
August 22, 2024 04:03
-
-
Save michidk/ced97c81388fa8a0d6d9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System; | |
using System.Text; | |
using System.Collections; | |
using System.Collections.Generic; | |
public class LSystemGenerator : MonoBehaviour | |
{ | |
[Serializable] | |
class State | |
{ | |
public float size; | |
public float angle; | |
public float x; | |
public float y; | |
public float dir; | |
public State Clone() { | |
return (State) this.MemberwiseClone(); | |
} | |
} | |
[Serializable] | |
class Node | |
{ | |
public int x, y; | |
public bool isStreet; | |
public Node(int x, int y) | |
{ | |
this.x = x; | |
this.y = y; | |
} | |
} | |
public string input = "LSYG"; | |
public float sizeValue = 15f; | |
public float sizeGrowth = -1.5f; | |
public float angleValue = 90f; | |
public float angleGrowth = 0f; | |
public Dictionary<char, string> rules = new Dictionary<char, string>(); | |
public int width, height = 80; | |
public GameObject custom; | |
private Node[,] nodes; | |
private State state; | |
private Stack<State> states = new Stack<State>(); | |
void Awake() | |
{ | |
nodes = new Node[width, height]; | |
for (int x = 0; x < width; x++) | |
for (int y = 0; y < height; y++) | |
nodes[x, y] = new Node(x, y); | |
rules.Add('L', "|-S!L!Y"); | |
rules.Add('S', "[F[FF-YS]F)G]+"); | |
rules.Add('Y', "--[F-)<F-FG]-"); | |
rules.Add('G', "FGF[Y+>F]+Y"); | |
} | |
void Start() | |
{ | |
input = Replace(input); | |
Generate(); | |
Draw(); | |
} | |
public void Draw() | |
{ | |
for (int x = 0; x < width; x++) | |
{ | |
for (int y = 0; y < height; y++) | |
{ | |
if (nodes[x, y].isStreet) | |
{ | |
GameObject go = (GameObject)Instantiate(custom, new Vector3(x, y, 0), Quaternion.identity); | |
go.transform.parent = this.transform; | |
go.name = "Tile (" + x + "|" + y + ")"; | |
} | |
} | |
} | |
} | |
public void Generate() | |
{ | |
state = new State() | |
{ | |
x = 40, | |
y = 40, | |
dir = 0, | |
size = sizeValue, | |
angle = angleValue | |
}; | |
foreach (char c in input) | |
{ | |
switch (c) | |
{ | |
case 'F': | |
float newX = state.x + state.size * Mathf.Cos(state.dir * Mathf.PI / 180); | |
float newY = state.y + state.size * Mathf.Sin(state.dir * Mathf.PI / 180); | |
Debug.Log(state.x + " -" + state.y); | |
nodes[Mathf.RoundToInt(state.x), Mathf.RoundToInt(state.y)].isStreet = true; | |
nodes[Mathf.RoundToInt(newX), Mathf.RoundToInt(newY)].isStreet = true; | |
//TODO: draw line | |
state.x = newX; | |
state.y = newY; | |
break; | |
case '+': | |
state.dir += state.angle; | |
break; | |
case '-': | |
state.dir -= state.angle; | |
break; | |
case '>': | |
state.size *= (1 - sizeGrowth); | |
break; | |
case '<': | |
state.size *= (1 + sizeGrowth); | |
break; | |
case ')': | |
state.angle *= (1 + angleGrowth); | |
break; | |
case '(': | |
state.angle *= (1 - angleGrowth); | |
break; | |
case '[': | |
states.Push(state.Clone()); | |
break; | |
case ']': | |
state = states.Pop(); | |
break; | |
case '!': | |
state.angle *= -1; | |
break; | |
case '|': | |
state.dir += 180; | |
break; | |
} | |
} | |
} | |
public string Replace(string s) | |
{ | |
StringBuilder sb = new StringBuilder(); | |
foreach (char c in s) | |
{ | |
if (rules.ContainsKey(c)) | |
{ | |
sb.Append(rules[c]); | |
} | |
else | |
{ | |
sb.Append(c); | |
} | |
} | |
return sb.ToString(); | |
} | |
} |
Nice program! I'm looking to modifiy the tree growth algorithm in a way that I can assign a branch length and angle at each iteration. Does anyone have any idea how to do it?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
your system is nice, it creates a structure of "buildings" where is "F". I can't figure how to implement the roads drawing...
I'm using a set of square tiles for the road. how can I figure which tile I need to place on each node and how to rotate it?
and by the way, this line create negetive number which cuase array out of index error:
float newY = state.y + state.size * Mathf.Sin(state.dir * Mathf.PI / 180);
if fixed it by multiply in -1 as quick fix...
as far as I understand 2 following lines do the same thing...
nodes[Mathf.RoundToInt(state.x), Mathf.RoundToInt(state.y)].isStreet = true;
nodes[Mathf.RoundToInt(newX), Mathf.RoundToInt(newY)].isStreet = true;