[pygame] 메모리 퍼즐 - (1)

서희찬·2021년 4월 6일
0
post-thumbnail

메모리 퍼즐

메모리 퍼즐이란 상자 안에 어떤 아이콘들이 숨어 있는지 알아맞히는 게임이다.
이를 통하여 중첩for문, 신택틱 슈가, 동일한 프로그램 내의 서로 다른 좌표계 등에 대해 배울 수 있다

플레이어는 한번에 2개의 상자를 클릭해서 뒤에 어떤 아이콘이 있는지 볼 수 있고 두 개가 동일한 아이콘을 가지고 있다면 그 상자는 열린 채 남아 있게된다.
이렇게 하여 모든 상자를 열면 플레이어가 승리 !
힌트를 주기 위해서 게임 스타트에 상자가 한 번 빠르게 열리고 닫힌다.

모듈가져오기/상수선언

import random, pygame, sys 
from pygame.locals import *

FPS = 30 # 초당 프레임
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
REVEALSPEED = 8 # 상자가 보여졌다 가려지는 속도
BOXSIZE = 40 #상자 너비와 높이
GAPSIZE = 10 
BOARDWIDTH = 10
BOARDHEIGHT = 7 #아이콘 가로줄 수 

상수선언을 하지않고 숫자로 10,20 이런식으로 대입하면 이 값이 정히 무엇을 의미하는 것인지 기억하기 어렵다.
그래서 이러한 숫자를 매직 넘버라고 한다.
그러니 자주사용하는 값은 상수설정하는 습관을 기르자 !

assert (BOARDWIDTH*BOARDHEIGHT)%2==0, "Board Needs To have an even Number of boxes for pairs of matches."
XMARGIN = int((WINDOWWIDTH -(BOARDWIDTH*(BOXSIZE+GAPSIZE)))/2)
YMARGIN = int((WINDOWHEIGHT -(BOARDHEIGHT*(BOXSIZE+GAPSIZE)))/2)

asert 문으로 Sanity Checks

asert문은 세부분으로 구성 되는데 첫 번째는 assert 키워드이고 두 번쨰 부분은 표현식이다. 이 표현식이 False 이면 프로그램은 크러쉬를 이르키고 세 번째 부분을 출력한다.
그래서 왜 크러쉬가 일어났는지 알 수 있다.
assert문이 참이면 sanity check를 통과한것이다.
여기서는 카드값이 짝수가 아니면 통과하지 못하게 하였다.

소스 코드 예쁘게 만들기

#            R    G    B
GRAY     = (100, 100, 100)
NAVYBLUE = ( 60,  60, 100)
WHITE    = (255, 255, 255)
RED      = (255,   0,   0)
GREEN    = (  0, 255,   0)
BLUE     = (  0,   0, 255)
YELLOW   = (255, 255,   0)
ORANGE   = (255, 128,   0)
PURPLE   = (255,   0, 255)
CYAN     = (  0, 255, 255)

BGCOLOR = NAVYBLUE
LIGHTBGCOLOR = GRAY
BOXCOLOR = WHITE
HIGHLIGHTCOLOR = BLUE

가끔 이르케 이쁘게 작성하면 가독성이 좋아진당 ~

문자열 대신 상수 변수 사용하기

DONUT = 'donut'
SQUARE = 'square'
DIAMOND = 'diamond'
LINES = 'lines'
OVAL = 'oval'

DONUT 을 DUNOT로 사용하면 에러가 뜨지만
"donut" 를 "dunot"로 사용하면 에러가 안떠서 오류가 뜬 부분을 찾기 어려우니 상수에 문자열을 넣어주는 것은 매우 좋은 습관이다 !

아이콘이 충분한지 확인하기

LLCOLORS = (RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, CYAN)
ALLSHAPES = (DONUT, SQUARE, DIAMOND, LINES, OVAL)
assert len(ALLCOLORS) * len(ALLSHAPES) * 2 >= BOARDWIDTH * BOARDHEIGHT, "Board is too big for the number of shapes/colors defined."

색 * 모양 = 35개 쌍이니 게임판에는 70개의 빈자리가 있어야한다.
튜플을 사용하여 값을 고정시킨다 .
+) 문자열은 값을 확인 할 수 있으니 변경 할 수는 없다.

아이템이 하나인 튜플은 뒤에 쉼표가 따라와야한다.

variableA = (5 * 6) = 계산식이라고 인식
variableB = (5 * 6,) = 튜플이라고 인식!!

전역변수는 지양하라 !

에러가 발생하면 찾기 힘들다 ~

이를 통해 Main 함수를 작성해보자..

설명은 주석에서 ><

def main():
    global FPSCLOCK,DISPLAYSURF #잔역변수 설정 
    pygame.init()
    FPSCLOCK = pygame.time.Clock()
    DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT))

    mousex = 0 # 마우스 이벤트 발생시 x좌표
    mousey = 0 # 마우스 이벤트 발생시 y좌표 

    mainBoard = getRandomizedBoard() #게임판의 상태를 나타내는 함수 
    revealedBoxes = generateRevealedBoxesData(False) #여기에 False를 전달하면 모든 구성요소 불리언 값이 False 가된다
    # False 면 닫힌상태 True이면 상자가 열린 상태이다 
    # 이 함수들이 반환할 값은 2차원 리스트이다. 

    firstSelection = None # 첫 번째 상자를 클릭했을 때 (x,y) 저장
    #프로그램은 이 값을 보고 두 번째 아이콘을 찾는 클릭인지 아닌지 알아낸다. 

    DISPLAYSURF.fill(BGCOLOR)
    startGameAnimation(mainBoard) #미리보여주기 함수 나중에 정의할거 !

    while True: # Game Loop
        mouseClicked = False # 이 값이 true 이면 플레이어가 마우스를 클릭했다고 인식

        DISPLAYSURF.fill(BGCOLOR) #drawing the window
        drawBoard(mainBoard,revealedBoxes)

        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYUP and evnet.key == K_ESCAPE):
                pygame.quit()
                sys.exit() 
            elif event.type == MOUSEMOTION:
                mousex,mousey == event.pos #마우스를 움직였으니 커서위치를 저장 
            elif event.type == MOUSEBUTTONUP:
                mousex,mousey = event.pos 
                mouseClicked = True #클릭했으니 트루 ~ 
        
        boxx, boxy = getBoxAtPixel(mousex,mousey)
        if boxx != None and boxy != None :
            #마우스가 현재 상자 위에 있다.
            if not revealedBoxes[boxx][boxy]: #False 라면 상자는 닫혀있다
                drawHighlightBox(boxx,boxy) #테두리를 그린당 ~ 
            if not revealedBoxes[boxx][boxy] and mouseClicked: #그 박스를 클릭했을 때 
                revealBoxesAnimation(mainBoard,[(boxx,boxy)]) #상자가 열리는 에니메이션 
                revealedBoxes[boxx][boxy] = True # 상자를 보이는 것으로 설정  열어둔다 !
                if firstSelection == None : # 현재의 상자가 처음 클릭 상자
                    firstSelection = (boxx,boxy)
                else: # 두번째 클릭한 상자 
                    #두 아이콘 짝이 맞는지 체크
                    icon1shape,icon1color = getShapeAndColor(mainBoard,firstSelection[0],firstSelection[1])
                    icon2shape,icon2color = getShapeAndColor(mainBoard,boxx,boxy)
                    #getShapeAndColor 는 그 위치에 있는 아이콘의 색깔과 형태를 알아낸다. 
                    if icon1shape != icon2shape or icon1color != icon2color:
                        #아이콘이 서로 맞지 않다면 두 상자 모두 덮는다.
                        pygame.time.wait(1000) #1sec
                        coverBoxesAnimation(mainBoard,[(firstSelection[0],firstSelection[1]),(boxx,boxy)])
                        revealedBoxes[firstSelection[0]][firstSelection[1]] = False #상자 닫아 ! 
                        revealedBoxes[boxx][boxy] = False  
                    elif hasWon(revealedBoxes): #모든 아이콘이 열렸는지 확인한다. 
                        gameWonAnimation(mainBoard)
                        pygame.time.wait(2000)

                        #게임판 재설정
                        mainBoard = getRandomizedBoard()
                        revealedBoxes = generateRevealedBoxesData(False)

                        #잠시 동안 게임판의 상자를 열어서 보여준다.
                         drawBoard(mainBoard,revealedBoxes)
                         pygame.display.update()
                         pygame.time.wait(1000)

                         #게임 시작 에니메이션을 보여준다. 
                         startGameAnimation(mainBoard)
                    firstSelection = None # firstSelection 변수를 리셋 

        #화면을 다시 그린 다음 시간 지연을 기다린다. 
        pygame.display.update()
        FPSCLOCK.tick(FPS)

아직..한참남았다..
이제 전체적인 틀을짠거니 세부적인 에니메이션이나 데이터구조만드는 등등... 함수를 짜러가자..

profile
부족한 실력을 엉덩이 힘으로 채워나가는 개발자 서희찬입니다 :)

0개의 댓글