로그인

검색

MoA
조회 수 1317 추천 수 0 댓글 5
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 게시글 수정 내역 댓글로 가기 인쇄 첨부
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 게시글 수정 내역 댓글로 가기 인쇄 첨부

4_main.png

 

 

 

1. 준비

 

이번엔 펜스를 그려보자. 펜스는 농부가 이동할 수 있는 지역의 경계가 된다. 이 게임의 특징은 펜스나 상점 등의 위치 데이터를 파일에서 가져오는 것이다. 소스 디렉토리에 보면 data 폴더 아래에 level.txt 파일을 열어보자

 

 

FFFFFFFFFF
FLLLLLLLLF
F        F
F   P    F
F       CF
F        F
FW      SF
FFFFFFFFFF

 

 

 

알파벳으로 이루어진 텍스트이다. 게임을 해봤다면 F가 뭔지 L은 뭔지 등을 짐작할 수 있을 것이다. F가 우리가 이 강좌에서 그릴 펜스이다. 파일을 열기 전에 펜스 클래스부터 정의하자.

 

2. Fence 클래스

 

 

class Fence(pygame.sprite.Sprite):

    def __init__(self, x, y):
        self.fence_ = load_img('fence', 'fence_.png')
        self.fence_u = load_img('fence', 'fence_u.png')
        self.fence_d = load_img('fence', 'fence_d.png')
        self.fence_l = load_img('fence', 'fence_l.png')
        self.fence_r = load_img('fence', 'fence_r.png')
        self.fence_ud = load_img('fence', 'fence_ud.png')
        self.fence_ul = load_img('fence', 'fence_ul.png')
        self.fence_ur = load_img('fence', 'fence_ur.png')
        self.fence_dl = load_img('fence', 'fence_dl.png')
        self.fence_dr = load_img('fence', 'fence_dr.png')
        self.fence_lr = load_img('fence', 'fence_lr.png')
        self.fence_udl = load_img('fence', 'fence_udl.png')
        self.fence_udr = load_img('fence', 'fence_udr.png')
        self.fence_ulr = load_img('fence', 'fence_ulr.png')
        self.fence_dlr = load_img('fence', 'fence_dlr.png')
        self.fence_udlr = load_img('fence', 'fence_udlr.png')

        pygame.sprite.Sprite.__init__(self)
        self.image = self.fence_
        self.rect = self.image.get_rect()
        self.rect.topleft = x, y
        fences.append(self)

    def assign_image(self):
        imagename = "fence_"
        if self.rect.move(0, -64).collidelistall(fences) != []: imagename = imagename + "u"
        if self.rect.move(0, 64).collidelistall(fences) != []: imagename = imagename + "d"
        if self.rect.move(-64, 0).collidelistall(fences) != []: imagename = imagename + "l"
        if self.rect.move(64, 0).collidelistall(fences) != []: imagename = imagename + "r"
        exec('self.image = self.%s' % imagename)

 

 

 

3번 강좌에서 본 HUD_Sprite 클래스보다 꽤 복잡하다. 사실 난 이 클래스에 불만이 하나 있다. 펜스를 생성할 때마다 생성자에서 이미지를 16개씩 불러오고 저장하기 때문이다. static 메쏘드나 global 메쏘드로 정의를 하는게 좋을 것 같다. 그리고 펜스 이미지가 16개씩 있는 이유는 이미지를 직접 열어보면 된다. 펜스 자신의 주변에 아무 펜스가 없는 경우, 오른쪽에 펜스가 있는 경우 아래쪽에 펜스가 있는 경우 등등을 다 고려해야 하기 때문이다. 이미지 이름에서 _ 뒤에 있는 문자의 의미는 u = up, d = down, l = left, r = right이다. 자신의 위쪽에 펜스가 있는 경우 u, 아래쪽에 있는 경우 d 등을 붙이는 것이다.

 

생성자에서는 fences 리스트에 자신을 추가한다. 그리고 기본으로는 주변에 펜스가 없는 경우의 이미지를 할당한다. assign_image() 함수는 주변에 펜스가 있는지 없는지를 체크하여 그에 해당하는 이미지를 다시 할당한다. 주변에 펜스가 있는지 없는지는 collidelistall 함수를 이용한다. 이는 파라메터의 리스트 안에 있는 오브젝트들과 충돌 여부를 조사하여 충돌하는 오브젝트들을 모은 리스트를 리턴한다. (collidelistall 함수의 파라메터는 사실 Rect 오브젝트의 리스트여야 하지만 Sprite 클래스의 오브젝트도 가능하다.) 펜스를 상하좌우로 움직여 충돌하는 펜스가 있다면 경우에 따라 이미지 이름의 끝에 u, d, l, r 를 붙인다. 그리고 그 이름의 이미지를 자신의 이미지로 할당한다.

 

3. 맵 데이터 불러오기

 

이제 맵 데이터가 들어가 있는 파일을 불러온다.

 

 

# Sprites/Objects를 생성한다
    fencenum = 1
    blockx = 0
    blocky = 0
    level = open('data/level.txt', 'r')

    for line in level:
        for char in line:
            if char == 'F':
                exec('fence%i = Fence(blockx, blocky)' % fencenum)
                exec('scenerylist.append(fence%i)' % fencenum)
                fencenum += 1
            blockx += 64
        blocky += 64
        blockx = 0
    for fence in fences:
        fence.assign_image()
    
    global allscenery
    allscenery = pygame.sprite.RenderPlain(scenerylist)


open('data/level.txt', 'r') 문장은 data폴더의 level.txt 파일을 읽기모드로 연다. 그 결과 level에는 level.txt 파일 내용이 들어가 있다. for 문을 통해 각 라인에 있는 문자를 하나씩 하나씩 읽어 들인다. F라는 문자가 보이면 exec 함수를 이용하여 펜스 클래스의 오브젝트를 생성한다. 그리고 여기에 blockx, blocky 변수를 이용하여 펜스의 x,y 위치를 넣어준다. 두 번째 exec 문장은 개발자가 게임을 만들다 말았다는 것을 보여준다. scenerylist에 펜스뿐만 아니라 다른 장애물도 넣으려 한 것으로 보인다. 하지만 장애물은 펜스밖에 없다. 펜스 클래스에서 초기화할 때 자신을 펜스 리스트에도 넣어주므로 사실은 필요 없는 문장.

 

또한 읽은 문자가 F가 아니더라도 blockx 즉 오브젝트의 위치는 64씩 증가한다. F가 아닌 문자에 대해서는 아무 처리도 안했으므로 오브젝트가 생성되지 않은 상태로 blockx 가 증가한다. 공백도 문자임에 유의하자.

 

펜스를 다 읽은 후 assign_image 함수로 적절한 이미지를 할당하는 것도 확인하자.

 

그 외 부분은 이전 강의에서 언급한 내용이므로 충분히 이해할 수 있을 것이다. 여기서 펜스를 화면에 그리는 부분은 설명하지 않았는데 어디에 어떻게 펜스 그리는 코드를 넣어야할지 생각해보자. 첨부한 코드에 답이 있다.

 

덧 : 이 코드에는 에러 처리하는 부분이 없다. 이 게임은 640x640 해상도의 게임이고 하나의 타일은 64x64픽셀이므로 맵데이터가 10x10개의 텍스트가 아니면 화면을 다 못채우거나 화면 밖으로 그려질 수도 있다. 다른 사람들에게 게임을 공개하려면 이런 경우의 에러 처리가 있어야 한다.

 

 

 

 

 

 

 

 

 

 

 

?
  • ?
    큰돼지 2014.04.30 13:47
    팬스 종류 총 16개 중에 안쓰는게 많네요.
    게임 만들다가 만건가여?
  • ?
    큰돼지 2014.04.30 15:48
    올ㄷㄷㄷ 충돌 함수 어려워요
  • profile
    MoA 2014.04.30 15:17

    그런거지.
    맵 데이터 바꾸면 다른 모양이 나오긴 할거야.

  • ?
    큰돼지 2014.04.30 18:39
    오 펜스 완전 신기하네여 ㄷㄷㄷ
    level.txt 바꾸니까 알아서 그려주네요 ㄷㄷㄷ
  • ?
    큰돼지 2014.04.30 18:39
    개신기

List of Articles
번호 분류 제목 글쓴이 날짜 조회 수
공지 Tool/etc Programming 게시판 관련 2 MoA 2014.11.01 5303
108 API/MFC 비주얼 스튜디오 2005 단축키 MoA 2013.07.28 1512
107 API/MFC VC의 소스 파일, sln파일 관리 MoA 2013.07.28 1194
106 API/MFC 비베의 MSCOMM.OCX VC++에서 불러쓰기 MoA 2013.07.28 1582
105 API/MFC VC++6.0 에서 VC++ 2005로 변환할 경우 형변환 경고 대응방법 MoA 2013.07.28 1353
104 C/C++ ofstream ifstream MoA 2013.07.28 1376
103 API/MFC MFC기반의 CSocket 사용 방법과 예제 MoA 2013.07.28 2037
102 API/MFC Sleep() 함수 대신 프로그램 딜레이 시키기 (Wait) MoA 2013.07.28 5839
101 C/C++ C, C++ 에서의 불(bool, boolean) 타입의 동작 MoA 2013.07.28 1148
100 C/C++ Simplified Logger Class MoA 2013.07.28 1225
99 C/C++ Buffer Overrun MoA 2013.07.28 1326
98 C/C++ Google의 C++ 라이브러리 MoA 2013.07.28 1426
97 C/C++ fwrite(), fread() MoA 2013.07.28 1361
96 C/C++ Binary 데이터 저장 by Google MoA 2013.07.28 1172
95 API/MFC 후킹 링크 MoA 2013.07.28 1498
94 API/MFC 모달창 세팅값 저장 MoA 2013.07.28 798
93 API/MFC DoModal Dialog 기초 MoA 2013.07.28 862
92 C/C++ C 언어의 문자형 변수 char - 8비트 정수형 변수 MoA 2013.07.28 2829
91 C/C++ C언어의 변수 float와 double - Float Point 처리 MoA 2013.07.28 1012
90 Site 알고리즘 정리된 블로그 MoA 2013.07.28 718
89 C/C++ 비트연산자 MoA 2013.07.28 1166
Board Pagination Prev 1 ... 5 6 7 8 9 10 11 12 13 14 15 Next
/ 15