from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class WindowClass(QWidget):
def __init__(self):
super().__init__()
self.key = None
self.img_bg = [ # 맵 칩
QImage('Python_workspace\python_game\image\dot_eat\chip00.png'),
QImage('Python_workspace\python_game\image\dot_eat\chip01.png'),
QImage('Python_workspace\python_game\image\dot_eat\chip02.png'),
QImage('Python_workspace\python_game\image\dot_eat\chip03.png')
]
self.img_pen = [ # 캐릭터 이미지
QImage('Python_workspace\python_game\image\dot_eat\pen00.png'), # 위쪽
QImage('Python_workspace\python_game\image\dot_eat\pen01.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen02.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen03.png'), # 아래쪽
QImage('Python_workspace\python_game\image\dot_eat\pen04.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen05.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen06.png'), # 왼쪽
QImage('Python_workspace\python_game\image\dot_eat\pen07.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen08.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen09.png'), # 오른쪽
QImage('Python_workspace\python_game\image\dot_eat\pen10.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen11.png')
]
self.map_data = [ # 미로 데이터
[0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0],
[0, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 0],
[0, 3, 0, 0, 3, 3, 3, 3, 0, 0, 3, 0],
[0, 3, 1, 1, 3, 0, 0, 3, 1, 1, 3, 0],
[0, 3, 2, 2, 3, 0, 0, 3, 2, 2, 3, 0],
[0, 3, 0, 0, 3, 1, 1, 3, 0, 0, 3, 0],
[0, 3, 1, 1, 3, 3, 3, 3, 1, 1, 3, 0],
[0, 2, 3, 3, 2, 0, 0, 2, 3, 3, 2, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
self.DIR_UP = 0 # 캐릭터 방향 정의 변수(위쪽)
self.DIR_DOWN = 1 # 캐릭터 방향 정의 변수(아래쪽)
self.DIR_LEFT = 2 # 캐릭터 방향 정의 변수(왼쪽)
self.DIR_RIGHT = 3 # 캐릭터 방향 정의 변수(오른쪽)
self.ANIMATION = [0, 1, 0, 2]
self.tmr = 0
self.score = 0 # 점수
self.pen_x = 60 # 펜펜의 X 좌표
self.pen_y = 60 # 펜펜의 Y 좌표
self.pen_d = 0 # 펜펜의 방향
self.pen_a = 0 # 펜펜의 이미지 번호
self.initUI()
timer = QTimer(self)
timer.setInterval(100)
timer.timeout.connect(self.main_proc)
timer.start()
def initUI(self):
self.setFixedSize(720, 540) # 창 크기 고정
self.setWindowTitle('Eat candy')
def check_wall(self, cx, cy, di, dot): # 지정한 방향에 벽 존재 여부 확인 함수
chk = False # chk에 False 대입
if di == self.DIR_UP: # 위쪽일 경우
mx = int(cx / 60) # mx와 my에 리스트의 좌상 방향 확인용 값 대입
my = int((cy - dot) / 60)
if self.map_data[my][mx] <= 1: # 좌상
chk = True # chk에 True 대입
mx = int((cx + 59) / 60) # 리스트의 우상 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 우상
chk = True # chk에 True 대입
if di == self.DIR_DOWN: # 아래쪽일 경우
mx = int(cx / 60) # mx와 my에 리스트의 좌하 방향 확인용 값 대입
my = int((cy + 59 + dot) / 60)
if self.map_data[my][mx] <= 1: # 좌하
chk = True
mx = int((cx + 59) / 60) # 리스트의 우하 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 우하
chk = True
if di == self.DIR_LEFT: # 왼쪽일 경우
mx = int((cx - dot) / 60) # mx와 my에 리스트의 좌상 방향 확인용 값 대입
my = int(cy / 60)
if self.map_data[my][mx] <= 1: # 좌상
chk = True
my = int((cy + 59) / 60) # 리스트의 좌하 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 좌하
chk = True
if di == self.DIR_RIGHT: # 오른쪽일 경우
mx = int((cx + 59 + dot) / 60) # mx와 my에 리스트의 우상 방향 확인용 값 대입
my = int(cy / 60)
if self.map_data[my][mx] <= 1: # 우상
chk = True
my = int((cy + 59) / 60) # 리스트의 우하 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 우하
chk = True
return chk # chk 값 반환
def move_penpen(self): # 펜펜(캐릭터) 이동 함수
if self.key == Qt.Key_Up: # 위쪽 방향키를 눌렀다면
self.pen_d = self.DIR_UP # 펜펜의 방향을 위쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False: # 해당 방향이 벽이 아니라면
self.pen_y = self.pen_y - 20 # 위쪽으로 이동
if self.key == Qt.Key_Down: # 아래쪽
self.pen_d = self.DIR_DOWN # 펜펜의 방향을 아래쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False:
self.pen_y = self.pen_y + 20
if self.key == Qt.Key_Left: # 왼쪽
self.pen_d = self.DIR_LEFT # 펜펜의 방향을 왼쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False:
self.pen_x = self.pen_x - 20
if self.key == Qt.Key_Right: # 오른쪽
self.pen_d = self.DIR_RIGHT # 펜펜의 방향을 오른쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False:
self.pen_x = self.pen_x + 20
self.pen_a = self.pen_d * 3 + self.ANIMATION[self.tmr % 4] # 펜펜 애니메이션(이미지) 번호 계산
mx = int(self.pen_x / 60) # mx, my에 펜펜이 있는 위치의 리스트로 확인할 값 대입
my = int(self.pen_y / 60)
if self.map_data[my][mx] == 3: # 사탕 위치에 들어가면
self.score = self.score + 100 # 점수 추가
self.map_data[my][mx] = 2 # 사탕 삭제
def main_proc(self):
self.tmr = self.tmr + 1 # 타이머 값 증가
self.move_penpen()
self.update()
def draw_text(self, qp, txt, x, y, siz, col): # 그림자를 포함한 문자열을 표시
qp.setFont(QFont('Times New Roman', siz, QFont.Bold)) # 폰트 정의
qp.setPen(Qt.black) # 문자열 그림자(2픽셀 어긋나게 검게 표시)
qp.drawText(x + 2, y + 2, txt)
qp.setPen(col) # 지정한 색으로 문자열 표시
qp.drawText(x, y, txt)
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
for y in range(9):
for x in range(12):
qp.drawImage(QRect(x * 60, y * 60, 60, 60), self.img_bg[self.map_data[y][x]]) # 맵 칩으로 미로 그리기
qp.drawImage(QRect(self.pen_x, self.pen_y, 60, 60), self.img_pen[self.pen_a]) # PenPen 표시
self.draw_text(qp, 'SCORE ' + str(self.score), 100, 30, 30, Qt.white)
qp.end()
def keyPressEvent(self, e):
self.key = e.key()
def keyReleaseEvent(self, e):
self.key = None
if __name__ == "__main__":
app = QApplication(sys.argv)
main_W = WindowClass()
main_W.show()
sys.exit(app.exec_())
펜펜의 좌표를 맵 칩 크기로 나눠서, 2차원 리스트 map_data의 인덱스를 구하여 그 위치가 어느 칸인지 확인하는 것이다.
그 결과 사탕이 있는 칸의 값인 3이면 점수를 올리고, 사탕이 없는 바닥인 2로 값을 변경하여 사탕을 없앤다.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
import random
class WindowClass(QWidget):
def __init__(self):
super().__init__()
self.key = None
self.img_bg = [ # 맵 칩
QImage('Python_workspace\python_game\image\dot_eat\chip00.png'),
QImage('Python_workspace\python_game\image\dot_eat\chip01.png'),
QImage('Python_workspace\python_game\image\dot_eat\chip02.png'),
QImage('Python_workspace\python_game\image\dot_eat\chip03.png')
]
self.img_pen = [ # 캐릭터 이미지
QImage('Python_workspace\python_game\image\dot_eat\pen00.png'), # 위쪽
QImage('Python_workspace\python_game\image\dot_eat\pen01.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen02.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen03.png'), # 아래쪽
QImage('Python_workspace\python_game\image\dot_eat\pen04.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen05.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen06.png'), # 왼쪽
QImage('Python_workspace\python_game\image\dot_eat\pen07.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen08.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen09.png'), # 오른쪽
QImage('Python_workspace\python_game\image\dot_eat\pen10.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen11.png')
]
self.img_red = [
QImage('Python_workspace/python_game/image/dot_eat/red00.png'),
QImage('Python_workspace/python_game/image/dot_eat/red01.png'),
QImage('Python_workspace/python_game/image/dot_eat/red02.png'),
QImage('Python_workspace/python_game/image/dot_eat/red03.png'),
QImage('Python_workspace/python_game/image/dot_eat/red04.png'),
QImage('Python_workspace/python_game/image/dot_eat/red05.png'),
QImage('Python_workspace/python_game/image/dot_eat/red06.png'),
QImage('Python_workspace/python_game/image/dot_eat/red07.png'),
QImage('Python_workspace/python_game/image/dot_eat/red08.png'),
QImage('Python_workspace/python_game/image/dot_eat/red09.png'),
QImage('Python_workspace/python_game/image/dot_eat/red10.png'),
QImage('Python_workspace/python_game/image/dot_eat/red11.png')
]
self.map_data = [ # 미로 데이터
[0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0],
[0, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 0],
[0, 3, 0, 0, 3, 3, 3, 3, 0, 0, 3, 0],
[0, 3, 1, 1, 3, 0, 0, 3, 1, 1, 3, 0],
[0, 3, 2, 2, 3, 0, 0, 3, 2, 2, 3, 0],
[0, 3, 0, 0, 3, 1, 1, 3, 0, 0, 3, 0],
[0, 3, 1, 1, 3, 3, 3, 3, 1, 1, 3, 0],
[0, 2, 3, 3, 2, 0, 0, 2, 3, 3, 2, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
self.DIR_UP = 0 # 캐릭터 방향 정의 변수(위쪽)
self.DIR_DOWN = 1 # 캐릭터 방향 정의 변수(아래쪽)
self.DIR_LEFT = 2 # 캐릭터 방향 정의 변수(왼쪽)
self.DIR_RIGHT = 3 # 캐릭터 방향 정의 변수(오른쪽)
self.ANIMATION = [0, 1, 0, 2]
self.tmr = 0
self.score = 0 # 점수
self.pen_x = 60 # 펜펜의 X 좌표
self.pen_y = 60 # 펜펜의 Y 좌표
self.pen_d = 0 # 펜펜의 방향
self.pen_a = 0 # 펜펜의 이미지 번호
self.red_x = 600 # 레드의 X 좌표
self.red_y = 420 # 레드의 Y 좌표
self.red_d = 0 # 레드의 방향
self.red_a = 0 # 레드의 이미지 번호
self.initUI()
timer = QTimer(self)
timer.setInterval(100)
timer.timeout.connect(self.main_proc)
timer.start()
def initUI(self):
self.setFixedSize(720, 540) # 창 크기 고정
self.setWindowTitle('Add Enemy')
def check_wall(self, cx, cy, di, dot): # 지정한 방향에 벽 존재 여부 확인 함수
chk = False # chk에 False 대입
if di == self.DIR_UP: # 위쪽일 경우
mx = int(cx / 60) # mx와 my에 리스트의 좌상 방향 확인용 값 대입
my = int((cy - dot) / 60)
if self.map_data[my][mx] <= 1: # 좌상
chk = True # chk에 True 대입
mx = int((cx + 59) / 60) # 리스트의 우상 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 우상
chk = True # chk에 True 대입
if di == self.DIR_DOWN: # 아래쪽일 경우
mx = int(cx / 60) # mx와 my에 리스트의 좌하 방향 확인용 값 대입
my = int((cy + 59 + dot) / 60)
if self.map_data[my][mx] <= 1: # 좌하
chk = True
mx = int((cx + 59) / 60) # 리스트의 우하 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 우하
chk = True
if di == self.DIR_LEFT: # 왼쪽일 경우
mx = int((cx - dot) / 60) # mx와 my에 리스트의 좌상 방향 확인용 값 대입
my = int(cy / 60)
if self.map_data[my][mx] <= 1: # 좌상
chk = True
my = int((cy + 59) / 60) # 리스트의 좌하 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 좌하
chk = True
if di == self.DIR_RIGHT: # 오른쪽일 경우
mx = int((cx + 59 + dot) / 60) # mx와 my에 리스트의 우상 방향 확인용 값 대입
my = int(cy / 60)
if self.map_data[my][mx] <= 1: # 우상
chk = True
my = int((cy + 59) / 60) # 리스트의 우하 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 우하
chk = True
return chk # chk 값 반환
def move_penpen(self): # 펜펜(캐릭터) 이동 함수
if self.key == Qt.Key_Up: # 위쪽 방향키를 눌렀다면
self.pen_d = self.DIR_UP # 펜펜의 방향을 위쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False: # 해당 방향이 벽이 아니라면
self.pen_y = self.pen_y - 20 # 위쪽으로 이동
if self.key == Qt.Key_Down: # 아래쪽
self.pen_d = self.DIR_DOWN # 펜펜의 방향을 아래쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False:
self.pen_y = self.pen_y + 20
if self.key == Qt.Key_Left: # 왼쪽
self.pen_d = self.DIR_LEFT # 펜펜의 방향을 왼쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False:
self.pen_x = self.pen_x - 20
if self.key == Qt.Key_Right: # 오른쪽
self.pen_d = self.DIR_RIGHT # 펜펜의 방향을 오른쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False:
self.pen_x = self.pen_x + 20
self.pen_a = self.pen_d * 3 + self.ANIMATION[self.tmr % 4] # 펜펜 애니메이션(이미지) 번호 계산
mx = int(self.pen_x / 60) # mx, my에 펜펜이 있는 위치의 리스트로 확인할 값 대입
my = int(self.pen_y / 60)
if self.map_data[my][mx] == 3: # 사탕 위치에 들어가면
self.score = self.score + 100 # 점수 추가
self.map_data[my][mx] = 2 # 사탕 삭제
def move_enemy(self): # 레드(적) 이동 함수
speed = 10 # 레드의 이동 속도
if self.red_x % 60 == 0 and self.red_y % 60 == 0: # 칸의 정확한 위치에 있는 경우
self.red_d = random.randint(0, 3) # 무작위로 방향 변경
if self.red_d == self.DIR_UP: # 레드가 위쪽을 향한 경우
if self.check_wall(self.red_x, self.red_y, self.red_d, speed) == False: # 해당 방향이 벽이 아니라면
self.red_y = self.red_y - speed # 이동
if self.red_d == self.DIR_DOWN:
if self.check_wall(self.red_x, self.red_y, self.red_d, speed) == False:
self.red_y = self.red_y + speed
if self.red_d == self.DIR_LEFT:
if self.check_wall(self.red_x, self.red_y, self.red_d, speed) == False:
self.red_x = self.red_x - speed
if self.red_d == self.DIR_RIGHT:
if self.check_wall(self.red_x, self.red_y, self.red_d, speed) == False:
self.red_x = self.red_x + speed
self.red_a = self.red_d * 3 + self.ANIMATION[self.tmr % 4] # 레드의 애니메이션 번호 계산
def main_proc(self):
self.tmr = self.tmr + 1 # 타이머 값 증가
self.move_penpen()
self.move_enemy()
self.update()
def draw_text(self, qp, txt, x, y, siz, col): # 그림자를 포함한 문자열을 표시
qp.setFont(QFont('Times New Roman', siz, QFont.Bold)) # 폰트 정의
qp.setPen(Qt.black) # 문자열 그림자(2픽셀 어긋나게 검게 표시)
qp.drawText(x + 2, y + 2, txt)
qp.setPen(col) # 지정한 색으로 문자열 표시
qp.drawText(x, y, txt)
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
for y in range(9):
for x in range(12):
qp.drawImage(QRect(x * 60, y * 60, 60, 60), self.img_bg[self.map_data[y][x]]) # 맵 칩으로 미로 그리기
qp.drawImage(QRect(self.pen_x, self.pen_y, 60, 60), self.img_pen[self.pen_a]) # PenPen 표시
qp.drawImage(QRect(self.red_x, self.red_y, 60, 60), self.img_red[self.red_a])
self.draw_text(qp, 'SCORE ' + str(self.score), 100, 30, 30, Qt.white)
qp.end()
def keyPressEvent(self, e):
self.key = e.key()
def keyReleaseEvent(self, e):
self.key = None
if __name__ == "__main__":
app = QApplication(sys.argv)
main_W = WindowClass()
main_W.show()
sys.exit(app.exec_())
이제 적인 빨간색 펭귄이 미로안을 돌아다닌다. 하지만 펜펜을 추격하지 않고, 접촉해도 아무 일도 일어나지 않는다.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
import random
class WindowClass(QWidget):
def __init__(self):
super().__init__()
self.key = None
self.img_title = QImage('Python_workspace/python_game/image/dot_eat/title.png')
self.img_bg = [ # 맵 칩
QImage('Python_workspace\python_game\image\dot_eat\chip00.png'),
QImage('Python_workspace\python_game\image\dot_eat\chip01.png'),
QImage('Python_workspace\python_game\image\dot_eat\chip02.png'),
QImage('Python_workspace\python_game\image\dot_eat\chip03.png')
]
self.img_pen = [ # 캐릭터 이미지
QImage('Python_workspace\python_game\image\dot_eat\pen00.png'), # 위쪽
QImage('Python_workspace\python_game\image\dot_eat\pen01.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen02.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen03.png'), # 아래쪽
QImage('Python_workspace\python_game\image\dot_eat\pen04.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen05.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen06.png'), # 왼쪽
QImage('Python_workspace\python_game\image\dot_eat\pen07.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen08.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen09.png'), # 오른쪽
QImage('Python_workspace\python_game\image\dot_eat\pen10.png'),
QImage('Python_workspace\python_game\image\dot_eat\pen11.png')
]
self.img_red = [
QImage('Python_workspace/python_game/image/dot_eat/red00.png'),
QImage('Python_workspace/python_game/image/dot_eat/red01.png'),
QImage('Python_workspace/python_game/image/dot_eat/red02.png'),
QImage('Python_workspace/python_game/image/dot_eat/red03.png'),
QImage('Python_workspace/python_game/image/dot_eat/red04.png'),
QImage('Python_workspace/python_game/image/dot_eat/red05.png'),
QImage('Python_workspace/python_game/image/dot_eat/red06.png'),
QImage('Python_workspace/python_game/image/dot_eat/red07.png'),
QImage('Python_workspace/python_game/image/dot_eat/red08.png'),
QImage('Python_workspace/python_game/image/dot_eat/red09.png'),
QImage('Python_workspace/python_game/image/dot_eat/red10.png'),
QImage('Python_workspace/python_game/image/dot_eat/red11.png')
]
self.DIR_UP = 0 # 캐릭터 방향 정의 변수(위쪽)
self.DIR_DOWN = 1 # 캐릭터 방향 정의 변수(아래쪽)
self.DIR_LEFT = 2 # 캐릭터 방향 정의 변수(왼쪽)
self.DIR_RIGHT = 3 # 캐릭터 방향 정의 변수(오른쪽)
self.ANIMATION = [0, 1, 0, 2]
self.idx = 0
self.tmr = 0
self.score = 0 # 점수
self.candy = 0 # 각 스테이지에 있는 사탕 수
self.pen_x = 0 # 펜펜의 X 좌표
self.pen_y = 0 # 펜펜의 Y 좌표
self.pen_d = 0 # 펜펜의 방향
self.pen_a = 0 # 펜펜의 이미지 번호
self.red_x = 0 # 레드의 X 좌표
self.red_y = 0 # 레드의 Y 좌표
self.red_d = 0 # 레드의 방향
self.red_a = 0 # 레드의 이미지 번호
self.initUI()
timer = QTimer(self)
timer.setInterval(100)
timer.timeout.connect(self.main_proc) # 100밀리초마다 main_proc 실행
timer.start()
def initUI(self):
self.setFixedSize(720, 540) # 창 크기 고정
self.setWindowTitle('PenPen\'s Maze Adventure')
self.set_stage()
self.set_chara_pos()
def set_stage(self): # 스테이지 데이터 설정 함수
self.map_data = [ # 미로 데이터
[0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0],
[0, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 0],
[0, 3, 0, 0, 3, 3, 3, 3, 0, 0, 3, 0],
[0, 3, 1, 1, 3, 0, 0, 3, 1, 1, 3, 0],
[0, 3, 2, 2, 3, 0, 0, 3, 2, 2, 3, 0],
[0, 3, 0, 0, 3, 1, 1, 3, 0, 0, 3, 0],
[0, 3, 1, 1, 3, 3, 3, 3, 1, 1, 3, 0],
[0, 2, 3, 3, 2, 0, 0, 2, 3, 3, 2, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
self.candy = 32 # 사탕 수
def set_chara_pos(self): # 캐릭터 시작 위치 설정 함수
self.pen_x = 60 # 펜펜의 시작 x, y 좌표 대입
self.pen_y = 60
self.pen_d = self.DIR_DOWN # 펜펜의 방향을 아래로
self.pen_a = 3 # 펜펜 그림 번호 대입
self.red_x = 600 # 레드의 시작 x, y 좌표 대입
self.red_y = 420
self.red_d = self.DIR_DOWN # 레드의 방향을 아래로
self.red_a = 3 # 레드 그림 번호 대입
def check_wall(self, cx, cy, di, dot): # 지정한 방향에 벽 존재 여부 확인 함수
chk = False # chk에 False 대입
if di == self.DIR_UP: # 위쪽일 경우
mx = int(cx / 60) # mx와 my에 리스트의 좌상 방향 확인용 값 대입
my = int((cy - dot) / 60)
if self.map_data[my][mx] <= 1: # 좌상
chk = True # chk에 True 대입
mx = int((cx + 59) / 60) # 리스트의 우상 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 우상
chk = True # chk에 True 대입
if di == self.DIR_DOWN: # 아래쪽일 경우
mx = int(cx / 60) # mx와 my에 리스트의 좌하 방향 확인용 값 대입
my = int((cy + 59 + dot) / 60)
if self.map_data[my][mx] <= 1: # 좌하
chk = True
mx = int((cx + 59) / 60) # 리스트의 우하 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 우하
chk = True
if di == self.DIR_LEFT: # 왼쪽일 경우
mx = int((cx - dot) / 60) # mx와 my에 리스트의 좌상 방향 확인용 값 대입
my = int(cy / 60)
if self.map_data[my][mx] <= 1: # 좌상
chk = True
my = int((cy + 59) / 60) # 리스트의 좌하 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 좌하
chk = True
if di == self.DIR_RIGHT: # 오른쪽일 경우
mx = int((cx + 59 + dot) / 60) # mx와 my에 리스트의 우상 방향 확인용 값 대입
my = int(cy / 60)
if self.map_data[my][mx] <= 1: # 우상
chk = True
my = int((cy + 59) / 60) # 리스트의 우하 방향 확인용 값 대입
if self.map_data[my][mx] <= 1: # 우하
chk = True
return chk # chk 값 반환
def move_penpen(self): # 펜펜(캐릭터) 이동 함수
if self.key == Qt.Key_Up: # 위쪽 방향키를 눌렀다면
self.pen_d = self.DIR_UP # 펜펜의 방향을 위쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False: # 해당 방향이 벽이 아니라면
self.pen_y = self.pen_y - 20 # 위쪽으로 이동
if self.key == Qt.Key_Down: # 아래쪽
self.pen_d = self.DIR_DOWN # 펜펜의 방향을 아래쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False:
self.pen_y = self.pen_y + 20
if self.key == Qt.Key_Left: # 왼쪽
self.pen_d = self.DIR_LEFT # 펜펜의 방향을 왼쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False:
self.pen_x = self.pen_x - 20
if self.key == Qt.Key_Right: # 오른쪽
self.pen_d = self.DIR_RIGHT # 펜펜의 방향을 오른쪽으로
if self.check_wall(self.pen_x, self.pen_y, self.pen_d, 20) == False:
self.pen_x = self.pen_x + 20
self.pen_a = self.pen_d * 3 + self.ANIMATION[self.tmr % 4] # 펜펜 애니메이션(이미지) 번호 계산
mx = int(self.pen_x / 60) # mx, my에 펜펜이 있는 위치의 리스트로 확인할 값 대입
my = int(self.pen_y / 60)
if self.map_data[my][mx] == 3: # 사탕 위치에 들어가면
self.score = self.score + 100 # 점수 추가
self.map_data[my][mx] = 2 # 사탕 삭제
self.candy = self.candy - 1 # 사탕 개수 감소
def move_enemy(self): # 레드(적) 이동 함수
speed = 10 # 레드의 이동 속도
if self.red_x % 60 == 0 and self.red_y % 60 == 0: # 칸의 정확한 위치에 있는 경우
self.red_d = random.randint(0, 6) # 무작위로 방향 변경
if self.red_d >= 4: # 난수가 4 이상인 경우 주인공 추적
if self.pen_y < self.red_y: # 펜펜이 위쪽에 있다면
self.red_d = self.DIR_UP # 레드의 방향을 위쪽으로
if self.pen_y > self.red_y:
self.red_d = self.DIR_DOWN
if self.pen_x < self.red_x:
self.red_d = self.DIR_LEFT
if self.pen_x > self.red_x:
self.red_d = self.DIR_RIGHT
if self.red_d == self.DIR_UP: # 레드가 위쪽을 향한 경우
if self.check_wall(self.red_x, self.red_y, self.red_d, speed) == False: # 해당 방향이 벽이 아니라면
self.red_y = self.red_y - speed # 이동
if self.red_d == self.DIR_DOWN:
if self.check_wall(self.red_x, self.red_y, self.red_d, speed) == False:
self.red_y = self.red_y + speed
if self.red_d == self.DIR_LEFT:
if self.check_wall(self.red_x, self.red_y, self.red_d, speed) == False:
self.red_x = self.red_x - speed
if self.red_d == self.DIR_RIGHT:
if self.check_wall(self.red_x, self.red_y, self.red_d, speed) == False:
self.red_x = self.red_x + speed
self.red_a = self.red_d * 3 + self.ANIMATION[self.tmr % 4] # 레드의 애니메이션 번호 계산
if abs(self.red_x - self.pen_x) <= 40 and abs(self.red_y - self.pen_y) <= 40: # 펜펜과 접촉했는지 판단해서 접촉했다면
self.idx = 2 # 게임 오버 처리로 이동
self.tmr = 0
def main_proc(self):
self.tmr = self.tmr + 1 # 타이머 값 증가
if self.idx == 0: # 인덱스 0 처리(타이틀 화면)
if self.key == Qt.Key_Space: # [SPACE]키를 누르면
self.score = 0 # 점수 0 대입
self.set_stage() # 스테이지 데이터 세트
self.set_chara_pos() # 각 캐릭터 시작 위치 설정
self.idx = 1 # 인덱스를 1로 변경, 게임 시작
if self.idx == 1: # 인덱스 1 처리(게임 플레이)
self.move_penpen() # 펜펜 이동
self.move_enemy() # 레드 이동
if self.candy == 0: # 사탕을 모두 먹었다면
self.idx = 4 # 스테이지 클리어 처리로 이동
self.tmr = 0
if self.idx == 2: # 인덱스 2 처리(게임 오버)
if self.tmr == 50:
self.idx = 0 # 타이틀 화면으로 이동
if self.idx == 4: # 인덱스 4 처리(스테이지 클리어)
if self.tmr == 50:
self.idx = 0 # 타이틀 화면으로 이동
self.update()
def draw_text(self, qp, txt, x, y, siz, col): # 그림자를 포함한 문자열을 표시
qp.setFont(QFont('Times New Roman', siz, QFont.Bold)) # 폰트 정의
qp.setPen(Qt.black) # 문자열 그림자(2픽셀 어긋나게 검게 표시)
qp.drawText(x + 2, y + 2, txt)
qp.setPen(col) # 지정한 색으로 문자열 표시
qp.drawText(x, y, txt)
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
for y in range(9):
for x in range(12):
qp.drawImage(QRect(x * 60, y * 60, 60, 60), self.img_bg[self.map_data[y][x]]) # 맵 칩으로 미로 그리기
qp.drawImage(QRect(self.pen_x, self.pen_y, 60, 60), self.img_pen[self.pen_a]) # PenPen 표시
qp.drawImage(QRect(self.red_x, self.red_y, 60, 60), self.img_red[self.red_a]) # 레드 표시
self.draw_text(qp, 'SCORE ' + str(self.score), 100, 30, 30, Qt.white) # 점수 표시
if self.idx == 0: # 타이틀 화면 표시
qp.drawImage(QRect(35, 100, self.img_title.width(), self.img_title.height()), self.img_title)
if self.tmr % 10 < 5: # 문자열이 깜빡거리는 처리
self.draw_text(qp, 'Press SPACE !', 250, 380, 30, Qt.yellow)
if self.idx == 2: # 게임 오버 문자 표시
self.draw_text(qp, 'GAME OVER', 200, 270, 40, Qt.red)
if self.idx == 4: # 스테이지 클리어 문자 표시
self.draw_text(qp, 'STAGE CLEAR', 180, 270, 40, QColor(255, 170, 170))
qp.end()
def keyPressEvent(self, e):
self.key = e.key()
def keyReleaseEvent(self, e):
self.key = None
if __name__ == "__main__":
app = QApplication(sys.argv)
main_W = WindowClass()
main_W.show()
sys.exit(app.exec_())
idx 값 | 처리 |
---|---|
0 | 타이틀 화면 - 스페이스키를 누르면 각 변수에 초기값 대입, idx를 1로 변경 |
1 | 게임 플레이 중 화면 - 펜펜 이동, 레드 이동 수행 - 레드 처리 중 펜펜과 접촉했다면 idx를 2로 변경 - 사탕을 모두 주우면 idx를 4로 변경 |
2 | 게임 오버 화면 - 약 5초간 대기한 뒤 idx 0으로 이동 |
4 | 게임 클리어 화면 - 약 5초간 대기한 뒤 idx 0으로 이동 |
이제 레드가 펜펜을 추적할 수도 있게 되었다.
if self.red_x % 60 == 0 and self.red_y % 60 == 0: # 칸의 정확한 위치에 있는 경우
self.red_d = random.randint(0, 6) # 무작위로 방향 변경
if self.red_d >= 4: # 난수가 4 이상인 경우 주인공 추적
if self.pen_y < self.red_y: # 펜펜이 위쪽에 있다면
self.red_d = self.DIR_UP # 레드의 방향을 위쪽으로
if self.pen_y > self.red_y:
self.red_d = self.DIR_DOWN
if self.pen_x < self.red_x:
self.red_d = self.DIR_LEFT
if self.pen_x > self.red_x:
self.red_d = self.DIR_RIGHT
0, 1, 2, 3, 4, 5, 6 중에서 하나를 뽑는데 0, 1, 2, 3인 경우에는 상하좌우 방향으로 바꾸고 4, 5, 6인 경우에는 펜펜이 어디있는지 확인하고 펜펜이 있는 방향으로 향한다.
펭귄의 이미지는 60 * 60 픽셀이지만 접촉 판정 부분을 보면 40픽셀로 되어 있는 것을 볼 수 있는데 이렇게 한 이유는 60픽셀로 하면 눈으로 볼 때는 닿지 않았는데 닿았다고 판정하기 때문이다.
그렇기에 40으로 판정해서 유저가 납득할 수 있는 히트박스를 지정해야 한다.