⛏️

003 광석 캐기

1. 실행 코드

import pygame as pg import math # 이미지 초기화 def 스프라이트생성(이미지, 위치, 상태=None): 스프라이트 = pg.sprite.Sprite() 스프라이트.image = 이미지 스프라이트.rect = 스프라이트.image.get_rect() 스프라이트.rect.x, 스프라이트.rect.y = 위치[0], 위치[1] if 상태 != None: 스프라이트.상태 = 상태 return 스프라이트 pg.init() # 게임기본설정 실행여부 = True 화면가로길이, 화면세로길이 = 952, 913 화면 = pg.display.set_mode([화면가로길이, 화면세로길이]) pg.display.set_caption('광석채굴!') # 색깔 설정 흰색 = (255, 255, 255) 검은색 = (0, 0, 0) # 글꼴 설정 글꼴 = pg.font.SysFont('hy얕은샘물m', 50) 작은글꼴 = pg.font.SysFont('hy얕은샘물m', 40) # 게임 요소 초기화 소울곰위치 = [화면가로길이 // 2, 화면세로길이 // 2] 소울곰속도 = 100 소울곰파워 = 1 광석최대상태 = 5 코인 = 0 전체시간 = 0 배경이미지 = pg.image.load('img/배경.png') 배경이미지 = pg.transform.scale(배경이미지, (화면가로길이, 화면세로길이)) 시간이미지 = pg.image.load('img/시간-바.png') 시간이미지크기 = (337, 89) 시간이미지 = pg.transform.scale(시간이미지, 시간이미지크기) 코인이미지 = pg.image.load('img/코인-바.png') 코인이미지크기 = (337, 89) 코인이미지 = pg.transform.scale(코인이미지, 코인이미지크기) 게임요소크기 = (152, 152) 소울곰이미지딕셔너리 = {"이동": [], "반대이동" : [], "캐기" : []} 소울곰멈춤이미지 = pg.image.load(f'img/소울곰_멈춘상태.png') 소울곰멈춤이미지 = pg.transform.scale(소울곰멈춤이미지, 게임요소크기) 소울곰이미지딕셔너리["멈춤"] = 소울곰멈춤이미지 for 인덱스 in range(4): 소울곰뛰는모습이미지 = pg.image.load(f'img/소울곰_뛰는모습_{인덱스 + 1}.png') 소울곰뛰는모습이미지 = pg.transform.scale(소울곰뛰는모습이미지, 게임요소크기) 소울곰이미지딕셔너리["이동"].append(소울곰뛰는모습이미지) 소울곰뛰는모습반전이미지 = pg.image.load(f'img/소울곰_뛰는모습_반전_{인덱스 + 1}.png') 소울곰뛰는모습반전이미지 = pg.transform.scale(소울곰뛰는모습반전이미지, 게임요소크기) 소울곰이미지딕셔너리["반대이동"].append(소울곰뛰는모습반전이미지) for 인덱스 in range(3): 소울곰캐는모습이미지 = pg.image.load(f'img/소울곰_캐는모습_{인덱스 + 1}.png') 소울곰캐는모습이미지 = pg.transform.scale(소울곰캐는모습이미지, 게임요소크기) 소울곰이미지딕셔너리["캐기"].append(소울곰캐는모습이미지) 소울곰이미지상태 = "멈춤" 소울곰이미지인덱스 = 0 소울곰이미지흐름 = 1 소울곰스프라이트 = 스프라이트생성(소울곰이미지딕셔너리[소울곰이미지상태], 소울곰위치) 광석이미지리스트 = [] for 인덱스 in range(5): 광석이미지 = pg.image.load(f'img/광석_{5 - 인덱스}.png') 광석이미지 = pg.transform.scale(광석이미지, 게임요소크기) 광석이미지리스트.append(광석이미지) 광석스프라이트리스트 = [] 광석스프라이트리스트.append(스프라이트생성(광석이미지리스트[-1], (200, 200), 광석최대상태)) # 오른쪽 하단 능력치 아이콘 이미지 능력치이미지 = pg.image.load('img/능력치.png') 능력치이미지크기 = (545, 190) 능력치이미지 = pg.transform.scale(능력치이미지, 능력치이미지크기) 시계 = pg.time.Clock() 이미지움직임최대시간 = 0.2 이미지움직임시간 = 0 while 실행여부: 화면.blit(배경이미지, (0, 0)) 흐른시간 = 시계.tick(60)/ 1000 전체시간 += 흐른시간 시간문자열 = '%02d:%05.2f' % (전체시간 / 60, 전체시간 % 60) 게임시작시간글자 = 글꼴.render(시간문자열, True, 검은색) 화면.blit(시간이미지, (30, 10)) 화면.blit(게임시작시간글자, (시간이미지크기[0] - 21 * len(시간문자열), 40)) 코인문자열 = str(코인) 코인글자 = 글꼴.render(코인문자열, True, 검은색) 화면.blit(코인이미지, (화면가로길이 - 30 - 코인이미지크기[0], 10)) 화면.blit(코인글자, (화면가로길이 - 70 - 21 * len(코인문자열), 40)) for 광석_스프라이트 in 광석스프라이트리스트: 화면.blit(광석_스프라이트.image, 광석_스프라이트.rect) 소울곰스프라이트.rect.x, 소울곰스프라이트.rect.y = 소울곰위치[0], 소울곰위치[1] 화면.blit(소울곰스프라이트.image, 소울곰스프라이트.rect) 화면.blit(능력치이미지, (화면가로길이 - 능력치이미지크기[0], 화면세로길이 - 능력치이미지크기[1])) 파워글자 = 작은글꼴.render(str(1), True, 검은색) 화면.blit(파워글자, (500, 화면세로길이 - 능력치이미지크기[1] + 55)) 속도글자 = 작은글꼴.render(str(1), True, 검은색) 화면.blit(속도글자, (610, 화면세로길이 - 능력치이미지크기[1] + 55)) 광석글자 = 작은글꼴.render(str(1), True, 검은색) 화면.blit(광석글자, (720, 화면세로길이 - 능력치이미지크기[1] + 55)) for 이벤트 in pg.event.get(): if 이벤트.type == pg.QUIT: 실행여부 = False # 캐릭터 움직이기 keys = pg.key.get_pressed() if keys[pg.K_SPACE]: if 소울곰이미지상태 == '캐기': 이미지움직임시간 -= 흐른시간 if 이미지움직임시간 <= 0: 이미지움직임시간 = 이미지움직임최대시간 소울곰이미지인덱스 += 소울곰이미지흐름 소울곰스프라이트.image = 소울곰이미지딕셔너리[소울곰이미지상태][소울곰이미지인덱스] if 소울곰이미지인덱스 == 0 or 소울곰이미지인덱스 == len(소울곰이미지딕셔너리[소울곰이미지상태]) - 1: 소울곰이미지흐름 *= -1 if 소울곰이미지인덱스 == len(소울곰이미지딕셔너리[소울곰이미지상태]) - 1: for 광석스프라이트 in 광석스프라이트리스트: if pg.sprite.collide_mask(소울곰스프라이트, 광석스프라이트): 광석스프라이트.상태 -= 소울곰파워 if 광석스프라이트.상태 <= 0: 코인 += 1 광석스프라이트리스트.remove(광석스프라이트) else: 광석스프라이트.image = 광석이미지리스트[math.ceil(광석스프라이트.상태) - 1] break else: 이미지움직임시간 = 이미지움직임최대시간 소울곰이미지상태 = "캐기" 소울곰이미지인덱스 = 0 소울곰이미지흐름 = 1 소울곰스프라이트.image = 소울곰이미지딕셔너리[소울곰이미지상태][소울곰이미지인덱스] elif keys[pg.K_LEFT] or keys[pg.K_RIGHT] or keys[pg.K_UP] or keys[pg.K_DOWN]: 이미지움직임시간 -= 흐른시간 if keys[pg.K_LEFT] or keys[pg.K_RIGHT]: if keys[pg.K_LEFT]: if 소울곰이미지상태 != '이동': 소울곰이미지상태 = '이동' 이미지움직임시간 = 0 if 소울곰위치[0] >= 0: 소울곰위치[0] -= 소울곰속도 * 흐른시간 if keys[pg.K_RIGHT]: if 소울곰이미지상태 != "반대이동": 소울곰이미지상태 = "반대이동" 이미지움직임시간 = 0 if 소울곰위치[0] < 화면가로길이 - 게임요소크기[0] + 20: 소울곰위치[0] += 소울곰속도 * 흐른시간 if keys[pg.K_UP] or keys[pg.K_DOWN]: if 소울곰이미지상태 != '이동' and 소울곰이미지상태 != '반대이동': 소울곰이미지상태 = '이동' if keys[pg.K_UP] and 소울곰위치[1] >= 시간이미지크기[1]: 소울곰위치[1] -= 소울곰속도 * 흐른시간 elif keys[pg.K_DOWN] and 소울곰위치[1] < 화면세로길이-능력치이미지크기[1] - 게임요소크기[1]: 소울곰위치[1] += 소울곰속도 * 흐른시간 if 이미지움직임시간 <= 0: 이미지움직임시간 = 이미지움직임최대시간 소울곰이미지인덱스 += 소울곰이미지흐름 # 현재1 소울곰스프라이트.image = 소울곰이미지딕셔너리[소울곰이미지상태][소울곰이미지인덱스] if 소울곰이미지인덱스==0 or 소울곰이미지인덱스==len(소울곰이미지딕셔너리[소울곰이미지상태]) -1: 소울곰이미지흐름 *= -1 else: 이미지움직임시간 = 0 소울곰이미지상태 = '멈춤' 소울곰이미지흐름 = 1 소울곰이미지인덱스 = 0 소울곰스프라이트.image = 소울곰이미지딕셔너리[소울곰이미지상태] pg.display.update() pg.display.quit()
 

2. 상세 내용

import math
  • 파이썬에서 수학에 관련된 함수가 저장된 라이브러리입니다.
  • 여기서는 올림함수인 ceil 함수를 사용할 예정입니다.
 
소울곰파워 = 1
  • 광석을 캘 때의 파워를 나타내는 변수입니다.
 
if keys[pg.K_SPACE]: if 소울곰이미지상태 == '캐기': 이미지움직임시간 -= 흐른시간 if 이미지움직임시간 <= 0: 이미지움직임시간 = 이미지움직임최대시간 소울곰이미지인덱스 += 소울곰이미지흐름 소울곰스프라이트.image = 소울곰이미지딕셔너리[소울곰이미지상태][소울곰이미지인덱스] if 소울곰이미지인덱스 == 0 or 소울곰이미지인덱스 == len(소울곰이미지딕셔너리[소울곰이미지상태]) - 1: 소울곰이미지흐름 *= -1 if 소울곰이미지인덱스 == len(소울곰이미지딕셔너리[소울곰이미지상태]) - 1: for 광석스프라이트 in 광석스프라이트리스트: if pg.sprite.collide_mask(소울곰스프라이트, 광석스프라이트): 광석스프라이트.상태 -= 소울곰파워 if 광석스프라이트.상태 <= 0: 코인 += 1 광석스프라이트리스트.remove(광석스프라이트) else: 광석스프라이트.image = 광석이미지리스트[math.ceil(광석스프라이트.상태) - 1] break else: 이미지움직임시간 = 이미지움직임최대시간 소울곰이미지상태 = "캐기" 소울곰이미지인덱스 = 0 소울곰이미지흐름 = 1 소울곰스프라이트.image = 소울곰이미지딕셔너리[소울곰이미지상태][소울곰이미지인덱스]
  • 알고리즘
    • 이미지상태가 캐기일 때
      • 이동 기능 당시 설명한 것처럼 이미지움직임시간에 따라 이미지를 변경하고 이미지흐름을 변경합니다.
      • 이미지인덱스가 2(캐기 동작의 마지막 인덱스)일 때 광석을 캐는 로직이 추가됩니다.
        • 광석스프라이트리스트를 돌면서 광석이 캐는 지점을 발견합니다.
        • pg.sprite.collide_mask(left, right)는 pg.sprite.collide_rect나 rect.collidepoint와는 다르게 실제 이미지가 존재 하는 부분들로만 충돌을 검사하는 함수로 png 파일처럼 이미지의 빈 부분은 충돌 검사에서 제외됩니다.
        • 스프라이트생성() 함수에서 상태를 넣어주는 부분이 있었는데 이 상태가 여기서 사용됩니다. 광석의 상태를 파워만큼 제외하고 상태에 따라 처리를 해줍니다.
          • 상태가 0이하 일 때는 광석을 다 캔 것이기 때문에 코인을 더하고 해당 객체를 제거합니다.
          • 그 외에는 광석 이미지를 상태에 따라 바꿔주는 때 올림함수를 사용하는 이유
            • 먼저 이미지를 표시할 때 상태 - 1을 해주는 이유는 아직 업그레이드를 하기 이전에는 파워가 1입니다. 그러면 광석의 상태는 5-4-3-2-1-0이 되는데 상태가 0인 경우는 무시됩니다. 즉 이미지의 상태가 2개에서 바로 사라지는 것 처럼 보이는데 이런 버그를 방지하기 위해서입니다.
            • 나중에 파워를 업그레이드를 할 때 파워가 소수 단위로 증가하게 됩니다.
            • 이 때 파워가 증가하여 상태가 0.8과 같은 상황이 있을 때 소수는 리스트의 인덱스가 아니므로 버림 또는 올림 함수를 사용해야 합니다. 그런데 내림 함수를 사용할 경우 -0.2 → -1이 되어 초기이미지로 되돌아 가므로 올림 함수를 사용하여 -0.2 → 0으로 만들어 줌으로써 올바른 이미지가 보일 수 있도록 합니다.
    • 그 외 : 이동, 반대이동, 멈춤일 때
      • 이미지 상태를 캐기로 변경한 후
      • 나머지 요소를 초기화 하고 이미지를 바꿔줍니다.

3. 실행 결과

notion imagenotion image