> For the complete documentation index, see [llms.txt](https://jjlee.gitbook.io/python-pygame_zero/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jjlee.gitbook.io/python-pygame_zero/flappy_bird/5.7_pipe_random.md).

# 5.7 플래피버드 게임 추가기능 구현하기 (파이프 위치 랜덤화)

만일 당신이 [엔트리-파이썬 책](https://jjlee.gitbook.io/entry-python/)부터 잘 따라왔다면 랜덤화(무작위화)는 낯선 것은 아니다. 엔트리-파이썬 책에 [무작위 수 챕터](https://jjlee.gitbook.io/entry-python/basic_syntax/3.7-random)에서 이미 다룬적이 있기 때문이다. 거기에서 엔트리-파이썬과 오리지널 파이썬에서 약간의 차이가 있다고 언급했던 부분 있는데 그것은 바로 랜덤기능을 코딩하기 위해서는 실제 파이썬의 경우, 랜덤(random)이라는 모듈을 불러오는 부분이 선행되어야 한다고 언급했었는데 그 부분부터 시작해 보도록 하자. 따라서 우리는 **오리지널 파이썬이기 때문에 랜덤을 활용하기 위해 코드의 맨 첫번째 라인에서 random 모듈을 import하는 것부터 시작하자.**

우리의 코드 안에서 파이프 위치가 랜덤화 되어야 할 때는 언제인가? 적어도 최소한 2번의 시점에서 필요한데, 첫번째로 파이프가 화면 좌측으로 빠져나가면서 우측화면부터 재등장해야하는 시점에서 필요하고, 두번째로 게임이 첨부터 재시작하는 시점에서도 파이프의 위치가 무작위로 등장하면 좋을 것이다. ***이렇게 적어도 2번 이상 같은 코드가 활용될 것으로 예상되기 때문에 이런 경우, 이 부분을 함수화하는 것을 고려하면 좋을 것이다.***&#x20;

<pre class="language-python" data-line-numbers><code class="lang-python"><strong>import random
</strong><strong>
</strong><strong>TITLE = 'Flappy Bird'
</strong>WIDTH = 400
HEIGHT = 708

GRAVITY = 0.3
drop_speed = 0
GAP = 140
PIPE_SPEED = -3
bird_alive = True
score = 0

# Actor 객체들
flappy_bird = Actor('bird1', (75, 350))
top_pipe = Actor('top', (350,0))
bottom_pipe = Actor('bottom', (350, top_pipe.height + GAP))

def draw():
    screen.blit('background', (0, 0))
    flappy_bird.draw()
    top_pipe.draw()
    bottom_pipe.draw()
    
    screen.draw.text(
        str(score),
        color = 'white',
        midtop = (WIDTH/2, 10),
        fontsize = 70,
        shadow = (1, 1)
    )

def reset_pipes():
    random_y = random.randint(-100, 100)
    top_pipe.y = random_y
    bottom_pipe.y = top_pipe.height + GAP + random_y
    top_pipe.x = WIDTH
    bottom_pipe.x = WIDTH

def update():
    global drop_speed, bird_alive, score
    drop_speed += GRAVITY
    flappy_bird.y += drop_speed
    top_pipe.x += PIPE_SPEED
    bottom_pipe.x += PIPE_SPEED
    
    # 파이프의 무한순환
    if top_pipe.right &#x3C; 0 or bottom_pipe.right &#x3C; 0: 
        reset_pipes()
        if bird_alive == True:
            score += 1
        
    # 파이프와의 충돌
    if flappy_bird.colliderect(top_pipe) or flappy_bird.colliderect(bottom_pipe): 
        flappy_bird.image = "birddead"
        bird_alive = False
        
    # 게임의 재시작
    if flappy_bird.y > HEIGHT or flappy_bird.y &#x3C; 0: 
        flappy_bird.image = "bird1"
        bird_alive = True
        flappy_bird.center = (75, 350)
        drop_speed = 0
        reset_pipes()
        score = 0

def on_mouse_down():
    global drop_speed
    if bird_alive == True:
        drop_speed = -6.5
</code></pre>

:1234: 위에서 언급했던 것처럼 33\~38번 라인에서 그 부분을 reset\_pipes 라는 이름으로 함수화 하였다. 그리고, 해당 함수를 호출은 위에서 언급한 바로 그 두 시점(게임의 재시작, 파이프의 무한순환)에서 호출하고 있다. 이제 이 함수코드를 자세히 이해해 보자. 먼저 랜덤값(무작위값)을 얻기 위해 random  모듈 안에 있는 [randint](https://docs.python.org/3/library/random.html#random.randint) 함수를 호출하는데 이 함수는 이름에서 알 수 있듯이 램덤으로 생성할 정수값(integer)의 최소값과 최대값의 범위를 파라미터로 갖는다. 우리는 randint(-100, 100) 이라고 호출했는데 이 의미는 -100 \~ 100 사이의 랜덤한 정수값을 얻겠다는 것이고, 더 궁극적인 의미는 파이프들의 위치를 그 범위 사이에서 위아래로 랜덤(무작위)하게 움직이게 하려는 목적에서다. 35-36번 라인의 코드에서 확인할 수 있듯이, 기존 top\_pipe.y 와 bottom\_pipe.y 값에 파이프들의 기존 기본 위치에 랜덤값(random\_y)을 추가로 덧붙혀 줌으로써 두 파이프는 일제히 랜덤값이 반영된 최종 위치를 갖게 되는데, 결과적으로 만약 랜덤값이 음수값 일 경우는 기존 원래 위치보다 더 위쪽으로, 양수값 일 경우는 더 아래쪽으로 이동하게 된다.

이제 마지막으로 게임성을 높이기 위해 구현해 볼 것은 플래피버드가 하늘을 날 때, 날개 펄럭임의 애니메이션을 추가해 게임의 그래픽 퀄러티 수준을 높히는(?) 것이 남아있다.
