Game AI & Unity/L-system algorithm

[L-system]Fractal Generation with L-Systems ①

bay07 2024. 4. 12. 09:27

▶ L-system

프랙탈을 통해, 간단한 규칙을 이용해서 복잡한 시스템을 만들 수 있다. 

'선 그리기'를 기본으로 작동하는 L시스템을 만들어보자. 

 

1. matplotlib를 사용하여 선 그리기 

%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('bmh') # 색 설정

plt.plot(
    [0, 1, 2],  # X 값
    [0, 1, 0]   # Y 값
)

plt.xlabel('x')
plt.ylabel('y');

def plot_coords(coords, bare_plot=False):
    if bare_plot:
        plt.axis('off')

  	# .set_aspect('equal', 'eatalim')은 가로세로 비율을 동일하게 설정해준다. 
    plt.axes().set_aspect('equal', 'datalim')
	
    # 각각의 x, y 좌표
    X, Y = zip(*coords)
    
    # 그림 그리기 
    plt.plot(X, Y);
    
plot_coords([
    (0, 0),
    (1, 0),
    (2, 1),
    (3, 1),
    (2, 0)
])

nan = float('nan')
plot_coords([
    (0, 0),
    (1, 1),
    (nan, nan),
    (1, 0),
    (2, 1)
])

 

 


 

2. 거북이 그래픽 

x좌표, y 좌표, 각도 

이렇게 3가지를 입력하면, 거북이는 이동하면서 그림을 그리게 된다. 

'F' move forward one unit and trace the path with a line.
앞으로 이동하면서, 선의 경로를 그린다
'f' move forward one unit but don't draw anything.
앞으로 이동하지만, 선의 경로를 그리지는 않는다 
'-' rotate counter-clockwise but don't move.
반시계방향으로 회전하는데 움직이지는 않는다
'+'  rotate clockwise but don't move.
시계방향으로 회전하는데 움직이지는 않는다

 

%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('bmh')  # Use some nicer default colors

from math import pi, sin, cos
DEGREES_TO_RADIANS = pi / 180

def turtle_to_coords(turtle_program, turn_amount=45):
    # 거북이가 (0,0)으로 시작하고 위쪽을 향해있다. 
    state = (0.0, 0.0, 90.0)
    
    # 거북이가 가는 경로
    yield (0.0, 0.0)
    
    for command in turtle_program:
        x, y, angle = state
        
        if command in 'Ff':      # 거북이를 앞으로 움직인다
            state = (x - cos(angle * DEGREES_TO_RADIANS),
                     y + sin(angle * DEGREES_TO_RADIANS),
                     angle)
            
            if command == 'f':

                yield (float('nan'), float('nan'))
                
            yield (state[0], state[1])
                        
        elif command == '+':     # 움직이지 않고 거북이를 시계방향으로 돌린다 
            state = (x, y, angle + turn_amount)
            
        elif command == '-':     # 움직이지 않고, 거북이를 반시계 방향으로 돌린다 
            state = (x, y, angle - turn_amount)
           
        
plot_coords(turtle_to_coords('FfF++FfF++FfF++FfF'))

3. 거북이 그래픽의 예시

%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('bmh')  # Use some nicer default colors

from math import pi, sin, cos
DEGREES_TO_RADIANS = pi / 180

def turtle_to_coords(turtle_program, turn_amount=45):
    # 거북이가 (0,0)으로 시작하고 위쪽을 향해있다. 
    state = (0.0, 0.0, 90.0)
    
    # 거북이가 가는 경로
    yield (0.0, 0.0)
    
    for command in turtle_program:
        x, y, angle = state
        
        if command in 'Ff':      # 거북이를 앞으로 움직인다
            state = (x - cos(angle * DEGREES_TO_RADIANS),
                     y + sin(angle * DEGREES_TO_RADIANS),
                     angle)
            
            if command == 'f':

                yield (float('nan'), float('nan'))
                
            yield (state[0], state[1])
                        
        elif command == '+':     # 움직이지 않고 거북이를 시계방향으로 돌린다 
            state = (x, y, angle + turn_amount)
            
        elif command == '-':     # 움직이지 않고, 거북이를 반시계 방향으로 돌린다 
            state = (x, y, angle - turn_amount)
           
        
plot_coords(turtle_to_coords('F-F+F+F+f+F+F+F-F'))

%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('bmh')  # Use some nicer default colors

from math import isnan
def print_coords(coords):
    for (x, y) in coords:
        if isnan(x):
            print('<gap>')
        else:
            print('({:.2f}, {:.2f})'.format(x, y))

print_coords(turtle_to_coords('F-F+F+F+f+F+F+F-F'))
(0.00, 0.00)
(-0.00, 1.00)
(-0.71, 1.71)
(-0.71, 2.71)
(-0.00, 3.41)
# <gap>
(1.00, 3.41)
(1.71, 2.71)
(1.71, 1.71)
(1.00, 1.00)
(1.00, -0.00)

plot_coords(turtle_to_coords('F-F+F+F+f+F+F+F-F', 65))

 

거북이 그래픽에서 회전도 잘 된다. 


* 참고 

https://nb.paulbutler.org/l-systems/