Skip to content

Instantly share code, notes, and snippets.

@michidk
Last active November 23, 2023 02:01
Show Gist options
  • Save michidk/ced97c81388fa8a0d6d9 to your computer and use it in GitHub Desktop.
Save michidk/ced97c81388fa8a0d6d9 to your computer and use it in GitHub Desktop.
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();
}
}
@monzeralkhalil
Copy link

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