메뉴 건너뛰기

OBG

Programming

MoA
조회 수 2033 추천 수 0 댓글 6
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄 첨부
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄 첨부

3_main.png.

 

1. 실습 준비

 

1번 강좌에서 받은 소스에서 NubcakeFarms.py를 지우고 새로운 py 파일을 생성한다.

그리고 코드 작성을 시작한다.

완성된 코드는 첨부 파일을 참고한다.

 

2. 풀밭 그리기

 

처음엔 일단 뭐라도 그려놓아야 시작한 느낌이 난다.

 

이미지를 pygame.image.load() 함수로 불러오고 바로 출력할 수도 있지만 이미지 파일 불러올 때 에러가 나는 경우도 있으니 로드하는 함수를 따로 만들자.

 

 

def load_img(subdir, name):
    """ 이미지를 불러온 후 이미지 오브젝트를 리턴한다 """
    if subdir != None:
        fullname = os.path.join('images', subdir, name)
    else:
        fullname = os.path.join('images', name)
    try:
        image = pygame.image.load(fullname)
        if image.get_alpha() is None:
            image = image.convert()
        else:
            image = image.convert_alpha()
    except pygame.error, message:
            print 'Cannot load image:', fullname
            raise SystemExit, message
    return image


인자로 subdir과 name을 받아들인다.

 

 

 

우리가 받은 소스코드의 폴더 구조를 보면 images 아래에 이미지 종류에 따라 폴더가 나뉘어져 있다. subdir에는 해당 폴더명을 적어주고 name에는 이미지의 파일명을 적어준다. 여기서 os.path.join이 하는 역할은 이 이름을 연결하여 폴더명으로 만들어주는 것이다. 예를 들면

 

subdir = "grass"

name = "grass1.png"

 

이면

 

os.path.join('images', subdir, name) = "images\grass\grass1.png" 가 된다. 가 아니라 \인 이유는 파이썬에서 텍스트 변수를 구성할 때 특수 문자는 를 이용하여 만들기 때문이다. http://lapee79.blogspot.kr/2013/08/python-strings.html 를 참고하자.

 

try ~ except 구문이 보이는데 이는 일단 try 블럭의 코드를 실행해보고 에러가 나면 except 블럭을 실행하는 구문이다. 즉 이미지를 불러오고 나서 에러가 나면 예외 처리를 하는 것이다. 이미지를 pygame.image.load()함수로 불러오고 그 후 convert() 또는 convert_alpha() 함수를 호출하는 것을 볼 수 있는데 사실 없어도 상관없다. 하지만 이것을 해야 이미지 그리는 속도가 더 빨라지므로 게임에선 꼭 써야한다. 다음 레퍼런스를 참고하자.

 

http://www.pygame.org/docs/ref/image.html#pygame.image.load

http://www.pygame.org/docs/ref/surface.html#pygame.Surface.convert

 

get_alpha()함수는 불러온 이미지에 알파채널이 있는지 없는지 검사한다. 알파채널은 이미지의 투명도 관련 정보가 있는 채널이다. rgb 채널처럼 알파채널도 픽셀마다 정보가 있는데 값이 0이면 해당 픽셀의 rgb가 안보이는 것이고 255면 보인다. 그 사이의 값이면 적당히 투명하게 보인다. 포토샵에서 알파채널을 열면 값이 0인 부분은 검은색, 255인 부분은 흰색으로 보인다.

 

('게임 프로그래밍의 정석'에선 이 알파채널 이미지를 불러와 화면에 뿌려줄 때에도 알파 블렌딩의 혼합 공식을 이용하여 직접 구현한다. Pygame은 그런 함수가 있으니 얼마나 편리한가!)

 

자 그럼 이걸로 풀밭을 그려보자. main함수를 만들고 다음 부분을 추가하자. (그 전에 첨부한 파일을 참고하여 초기화 부분을 더 넣어주어야 한다)

 

 

# 풀밭을 그린다 
    bgimage1 = load_img("grass", "grass1.png")
    bgimage2 = load_img("grass", "grass2.png")
    bgimage3 = load_img("grass", "grass3.png")
    background = pygame.Surface(screen.get_size())
    background = background.convert()
    for y in range(10):
        for x in range(10):
            exec('image = bgimage%d' % random.randint(1,3))
            background.blit(image, (64*x, 64*y))


여기서 앞선 첫게임(Bunny) 만들기 강좌와 차이가 나는 부분은 background = pygame.Surface(screen.get_size()) 이다. 그 전엔 screen에 직접 이미지를 뿌려주었지만 이번엔 screen과 같은 크기의 background Surface를 만들어주고 여기에 이미지를 뿌린 후 background를 다시 screen에 뿌려준다. Surface는 포토샵의 레이어와 같다. 그래서 배경 Suface와 게임 오브젝트의 Surface를 만들어 따로따로 그림을 그리고 나중에 다시 스크린에다 합쳐주는 것이다.

 

exec()함수는 괄호안의 문장을 파이썬 코드로 변환하여 실행해준다. 즉, 위 코드는 배경을 랜덤으로 만들어준다. 배경이미지는 3개가 있으며 모두 64*64 픽셀 이미지이다. 그리고 for루프를 돌면서 (0,0), (0, 64), ... , (64,0), (64,64), ... 위치에 이미지를 그린다. 이렇게 하면 640, 640 픽셀의 스크린에 100개의 타일을 붙이는 셈이 되는 것이다.

 

물론 위 코드는 background Surface에 그린 것이므로 화면에 뿌리려면 다음 코드가 더 있어야 한다.

 

 

# 이벤트 루프
    while 1:
        # 현재 시간을 업데이트한다
        current_time = time_in_ms()

        # 입력 체크
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return

        # 게임 구역 업데이트
        screen.blit(background, (0, 0))

        # 모든 것을 렌더링한다 (화면에 출력)
        pygame.display.flip()

 

3. HUD 그리기

 

 

먼저 클래스부터 보자.

 

 

class HUD_Sprite(pygame.sprite.Sprite):
    """
    HUD == Head-up Display 클래스
    """
    def __init__(self, img, x, y, name):
        """ HUD 클래스 오브젝트 생성 후 x,y에 위치시키고 리스트에 추가한다 """
        pygame.sprite.Sprite.__init__(self)
        self.name = name
        self.image = img
        self.rect = self.image.get_rect()
        self.rect.topleft = x, y
        hudspritelist.append(self)


맨 처음 눈에 들어오는 것은 상속 부분이다. 이 클래스는 pygame.sprite.Sprite 클래스를 상속받는다. 그럼 먼저 pygame.sprite.Sprite 클래스의 레퍼런스부터 보자.

 

http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Sprite

 

뭔지 감이 오는가? 앞선 강좌에서 Sprite클래스는 게임 오브젝트를 표현하는 것이라고 했다. 얘만 상속받으면 이 클래스의 오브젝트들을 그룹으로 묶을 수 있고 얘네들끼리 충돌체크도 할 수 있다. 한꺼번에 그릴 수도 있다. 위 코드에서 맨 마지막 hudspritelist.append(self) 부분만 보자. 클래스 오브젝트를 초기화하면서 hudspritelist 리스트에 추가한다. 이걸 어디서 써먹는지 다음 코드를 보자.

 

 

# HUD를 생성한다
    global hud
    hud = pygame.Surface((340, 112))
    hud.convert()
    hudimage = load_img("hud", "hud.png")
    hud.blit(hudimage, (0, 0))
    hud_seeds = HUD_Sprite(load_img('hud', 'wheat_seeds.png'), 17, 16, "Seeds")
    hud_wheat = HUD_Sprite(load_img('hud', 'wheat.png'), 98, 16, "Wheat")
    hud_watering_can = HUD_Sprite(load_img('hud', 'watering_can_small.png'), 179, 16, "Watering Can")
    hud_coin = HUD_Sprite(load_img('hud', 'coin.png'), 260, 16, "Gold")
    global allhudsprites
    allhudsprites = pygame.sprite.RenderPlain(hudspritelist)

 

hud_seeds = .... 부분부터 4개의 HUD_Sprite 클래스의 오브젝트를 생성한다. 이 때 파라메터 중 좌표에 해당하는 부분(17, 16 등)은 2번째 줄에서 생성한 hud Surface 상의 좌표이다. 그리고 마지막 부분에서 hudspritelist 리스트에 추가된 4개의 오브젝트를 그룹으로 묶는다. ( pygame.sprite.RenderPlain() 함수는 pygame.sprite.Group() 함수와 동일하다. 왜 함수 이름만 다르고 동작은 동일한 함수를 더 추가한지 모르겠다)

 

 

# HUD 업데이트
        screen.blit(hud, (150, 520))
        hud.blit(hudimage, (0, 0))
        allhudsprites.draw(hud)

 

 

 

while 문 안의 코드이다. 첫 줄에서 화면에 hud Surface를 뿌리고 그 다음 hud Surface에 hudimage를 0,0에 그린다. (hudimage는 4개의 네모가 그려진 hud의 배경이다) 마지막 코드가 중요하다. 아까 hud 오브젝트들을 묶은 allhudsprites 그룹을 한꺼번에 hud Surface에 그린다. hud Surface의 어디에 그려질지는 오브젝트 초기화할 때 좌표값을 넣어주어 결정하였다.

 

정리하자면 HUD는 다음과 같이 그려졌다.

 

1. pygame.sprite.Sprite를 상속받는 클래스를 정의한다.

2. 초기화할 때 그려질 이미지는 self.image 변수에, 이미지의 rect 변수는 self.rect 변수에, 그려질 위치는 self.topleft 변수에 정의한다.

3. 오브젝트를 리스트에 추가한다.

4. 리스트를 sprite 그룹으로 묶는다.

5. sprite 그룹을 한꺼번에 그린다.

 

이해가 되는가? 이해가 되지 않는다면 변수 값을 바꿔보고 일부 코드를 주석처리하거나 추가하면서 이것저것 테스트해보자. 클래스를 잘 모른다면 클래스도 공부해두자.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

?
  • ?
    큰돼지 2014.04.28 23:27
    # 게임 구역 업데이트
    screen.blit(background, (0, 0))
    (0, 0) 부터 끝까지 호면 업데이트 하는거에요?
  • profile
    MoA 2014.04.29 04:13

    위에서는 단어를 바꾸어야 이해가 쉽겠다. 게임 구역 -> 배경. (원래 다른 코드도 같이 들어감)
    배경을 그리는 거야.
    screen이랑 background는 사이즈가 같아.
    background = pygame.Surface(screen.get_size())로 background를 생성했기 때문이지.
    그래서 background를 screen의 (0,0) 좌표에 뿌리면 배경을 화면에 꽉 채우게 돼.

  • ?
    큰돼지 2014.04.29 14:34
    이해가 쏙쏙 되네염 ㅋ
  • ?
    큰돼지 2014.04.29 14:36
    load_img 함수는 쓸때없이 만든거네여 ㄷㄷㄷ
  • profile
    MoA 2014.04.30 02:20
    근데 에러 처리를 하려면 저렇게 해야돼
  • ?
    사월의눈 2016.05.11 18:01
    강좌 잘보고있습니다.
    중간중간 넘어가는부분이 많지만 이해가 잘되고 재미있네요. 감사합니다~

List of Articles
번호 분류 제목 글쓴이 날짜 조회 수
공지 Tool/etc Programming 게시판 관련 2 MoA 2014.11.01 1591
282 JAVA/Android XML 파싱하기 MoA 2013.08.06 7042
281 API/MFC Visual C++ 시리얼 통신(RS-232) 강좌 (1) MoA 2013.07.28 6652
280 Library AS3 Code Library MoA 2013.10.11 4995
279 API/MFC Sleep() 함수 대신 프로그램 딜레이 시키기 (Wait) MoA 2013.07.28 4607
278 API/MFC Visual C++ 시리얼 통신(RS-232) 강좌 (2) 1 MoA 2013.07.28 4419
277 API/MFC MFC 리본 사용하기 (아이콘 제작 포함) 너울 2012.02.09 4304
276 JAVA/Android logcat 사용법 MoA 2013.05.28 3461
275 API/MFC 프린터 출력하기 MoA 2013.10.16 3383
274 Deeplearning 직접 보고 추천하는 머신러닝 & 딥러닝 & 수학 총정리(2022) OBG 2022.07.24 3096
273 Python [액션게임 만들기] 3. 클래스 다이어그램 기초 file OBG 2014.05.07 2668
272 API/MFC DLL 생성 시 주의 MoA 2013.08.22 2659
271 Python [농장게임 만들기] 10. 상점을 추가하자 file MoA 2014.05.01 2635
270 API/MFC Thread와 SendMessage를 통해 DeadLock을 만드는 방법 MoA 2013.07.28 2600
269 API/MFC 다국어를 위한 StringTable, LoadString 1 MoA 2013.12.22 2389
268 C/C++ C 언어의 문자형 변수 char - 8비트 정수형 변수 MoA 2013.07.28 2169
» Python [농장게임 만들기] 3. 배경을 그리자 6 file MoA 2014.04.28 2033
266 Python 파이썬에서 C모듈 사용하기 MoA 2014.02.10 1899
265 API/MFC 프로세스 - 생성과 종료 그리고 이것 저것 너울 2011.10.12 1807
264 Site 졸업작품 및 각종 과제물 프로그램은 어떻게 만들어야 하나? (윈도우즈 응용프로그램) MoA 2013.09.10 1611
263 API/MFC 다른 스레드에서 메인다이얼로그 포인터 받아오기 AfxGetMainWnd() 1 MoA 2013.07.28 1574
Board Pagination Prev 1 2 3 4 5 6 7 8 9 10 ... 15 Next
/ 15
위로