VChuckShunA
VChuckShunA

Reputation: 25

How do I instantiate an object based on the ending of a string? (This is for an L System)

So I'm working on this L system, and I have it set up like this:

private const string axiom = "X";

private string currentString = string.Empty;

I am calling a method called Generate.

    private void Generate() { currentString = axiom; StringBuilder sb = new StringBuilder();for(int i=0; i < iterations; i++) {
        //loop through current string and create a new string based on the rules
        foreach (char c in currentString){
            sb.Append(rules.ContainsKey(c) ? rules[c] : c.ToString());
        }

        //Set currentString to the new string we just generated.
        currentString = sb.ToString();
        sb = new StringBuilder();
    }

And then I'm using a foreach loop and a switch statement to go through the string, and generate the tree:

foreach (char c in currentString) { 
            switch(c){
                case 'F':
                    //Draw a straight line
                    Vector3 initialPosition = transform.position;
                    transform.Translate(Vector3.up * length);
                    GameObject treeSegment;
                    if (currentString[(c + 1) % currentString.Length] == 'X' || 
                        currentString[(c + 4) % currentString.Length] == 'F' && currentString[(c + 5) % currentString.Length] == 'X')
                    {
                         treeSegment = Instantiate(leaf);
                        Debug.Log("LEAF!");
                    }
                    else{
                         treeSegment = Instantiate(branch);
                    }
                    treeSegment.GetComponent<LineRenderer>().SetPosition(0, initialPosition);
                    treeSegment.GetComponent<LineRenderer>().SetPosition(1, transform.position);
                    break;

                case 'X':
                    //does nothing, generate more Fs
                    break;

                case '+':
                    //Rotates clockwise
                    transform.Rotate(Vector3.back * angle);
                    break;

                case '-':
                    //Rotates counter-clockwise
                    transform.Rotate(Vector3.forward * angle);
                    break;

                case '[':
                    //Save current transform info
                    transformStack.Push(new TransformInfo(){
                        position = transform.position,
                        rotation = transform.rotation
                    });
                    break;

                case ']':
                    //Return to our previously saved transform info
                    TransformInfo ti = transformStack.Pop();
                    transform.position = ti.position;
                    transform.rotation = ti.rotation;
                    break;

                default:
                    throw new InvalidOperationException("Invalid L-tree operation");
            }
        }

The tutorial which I'm basing this off checks for position to place branches and leaves like this:

for (int i = 0; i < currentString.Length; i++) 
{
    switch (currentString[i]) 
    { 
        case 'F':
             initialPosition = transform.position; 
             transform.Translate(Vector3.up * 2 * length);

             GameObject fLine = currentString[(i + 1) % currentString.Length] == 'X' || currentString[(i + 3) % currentString.Length] == 'F' && currentString[(i + 4) % currentString.Length] == 'X' ? Instantiate(leaf) : Instantiate(branch);

I have no idea what's happening here. I don't get why he's adding seemingly random numbers and then using modulus.

Any help at all will be appreciated.

Upvotes: 0

Views: 36

Answers (1)

derHugo
derHugo

Reputation: 90659

In the original one you are accessing next characters! Like a look ahead with wrap around

currentString[(i + 1) % currentString.Length]

basically goes to the next index but if the index reaches currentString.Length it is wrapped around thanks to the % and becomes 0 again.

As an example lets say your string looks like

0 1 2 3 4 5
A B C D E F
      |
      | current index = 3

Then (i + 4) % length would mean 7 % 6 = 1

0 1 2 3 4 5
A B C D E F
  |
  | new index after shifting 4 with wrap around = 1

So the entire line

GameObject fLine = currentString[(i + 1) % currentString.Length] == 'X' || currentString[(i + 3) % currentString.Length] == 'F' && currentString[(i + 4) % currentString.Length] == 'X' ? Instantiate(leaf) : Instantiate(branch);

Basically translates to

  • (The current char is an F) - from the switch
  • IF
    • The next char is an X
    • OR
      • the char 3 to the right (with wrap around) is an F
      • AND the char after that is an X
  • THEN
    • Instantiate(leaf)
  • ELSE
    • Instantiate(branch);

HOWEVER

In your code you are doing

currentString[(c + 1) % currentString.Length]

BUT c is the actual value of a character like e.g. A == 65. It makes absolutely no sense to use this as an index in your original string!

=> You want to stick to a for loop in order to have the actual current index of your chracter

Upvotes: 0

Related Questions