[2021/Python] 게임 프로젝트
프로젝트 정보
프로젝트 명 : 개복치 키우기
년도 : 2021년
날짜 : 2021년 11월 18일 -> 2021년 12월 9일
개발 언어 : Python
개복치 키우기
상어와 고래로부터 살아남아라!
개발 목적
파이썬을 공부하면서 언어 활용 능력을 키우고, 프로그램 제작 경험을 쌓기 위해 프로젝트를 진행하였습니다. 가장 흥미로운 게임 프로젝트를 고민하던 중, 적을 피하면서 먹이를 먹어 점수를 얻는 개복치 게임을 구상하게 되었습니다.
기능 구현 및 소개
- 게임 규칙
방향키를 이용해 지나가는 상어와 고래를 피하며 먹이를 먹으세요. 먹이를 먹다 보면 어느새 몸이 커지는 개복치를 발견할 수 있을 것입니다.
- 기능 구현
1. 개복치
방향키로 이동 가능한 플레이어 캐릭터입니다.
먹이를 먹으면 점수가 오르고 적에게 닿으면 돌연사 하게 됩니다.
먹이를 먹을 수록 자신의 몸집이 커지게 됩니다.
코드 보기
개복치 조작
if문으로 방향키 입력에 따라 개복치 사진의 위치를 self.canvas.move() 함수를 통해 이동하는 방법으로 조작합니다. if문의 조건에 and 연산자를 추가하여 화면 내에서만 이동이 가능하도록 조작에 제한을 두었습니다.
#개복치 조작
def display(self):
mola_pos = self.canvas.coords(self.Mola)
for key in self.keys:
if key == 39 and mola_pos[0] < 1366 : # 우
self.canvas.itemconfigure(self.Mola, image=self.molaimg2)
self.canvas.move(self.Mola, 8, 0)
if key == 37 and mola_pos[0] > 0: # 좌
self.canvas.itemconfigure(self.Mola, image=self.molaimg)
self.canvas.move(self.Mola, -8, 0)
if key == 38 and mola_pos[1] > 100: # 위
self.canvas.move(self.Mola, 0, -8)
if key == 40 and mola_pos[1] < 700: # 아래
self.canvas.move(self.Mola, 0, 8)
개복치 성장
먹이를 먹을 때마다 기본 크기 100에서 5만큼 커지도록 하였습니다. 개복치의 이미지 뿐만 아니라 인식 범위도 넓히기 위해 관련된 변수에도 2만큼 늘어날 수 있게 하였습니다.
#개복치 크기
def scale(self):
if self.score % 100 == 0 :
self.w += 5
self.img_resize = self.img.resize((int(100+self.w), int(100+self.w)))
self.img_resize2 = self.img2.resize((int(100+self.w), int(100+self.w)))
self.img_resize3 = self.img3.resize((int(100+self.w), int(100+self.w)))
self.molaimg = ImageTk.PhotoImage(self.img_resize)
self.molaimg2 = ImageTk.PhotoImage(self.img_resize2)
self.molaimg3 = ImageTk.PhotoImage(self.img_resize3)
self.canvas.itemconfigure(self.Mola, image=self.molaimg)
self.canvas.itemconfigure(self.molaimg2, image=self.molaimg2)
self.ex += 2
self.ey += 2
self.fx += 2
self.fy += 2
2. 포식자(상어, 고래)
무작위로 좌우의 화면에서 등장하는 해양 생물입니다.
이 생물들에게 닿으면 개복치가 돌연사하고 게임이 끝나게 됩니다.
코드 보기
포식자 클래스 정의
Shark와 Whale 클래스를 통해 상어와 고래의 등장 방향과 속도를 정의했습니다.
둘은 유사하지만 고래는 상어보다 크기가 큰 대신 느리고, 상어는 조금 작지만 빠르게 하여 위협적인 존재로 등장하게 됩니다.
# 상어 클래스
class Shark:
def __init__(self,canvas,images,direct,id):
self.__frame = 0
self.id = 'e'+str(id)
self.canvas=canvas
self.images = images
self.direct = direct #상어 방향 설정
if self.direct == 0:
self.me = self.canvas.create_image(0,random.randint(100,700), image = self.images[0])
elif self.direct == 1:
self.me = self.canvas.create_image(1366,random.randint(100,700), image = self.images[0])
self.frame = 0
def update(self):
self.canvas.itemconfig(self.me, image = self.images[self.frame%len(self.images)])
if self.direct == 0: # 상어 속도 설정
self.canvas.move(self.me,30,0)
else:
self.canvas.move(self.me,-30,0)
self.frame = self.frame + 1
def getPos(self):
return self.canvas.coords(self.me)
def getId(self):
return self.me
# 고래 클래스
class Whale:
def __init__(self,canvas,images,direct,id):
self.__frame = 0
self.id = 'e'+str(id)
self.canvas=canvas
self.images = images
self.direct = direct #고래 방향 설정
if self.direct == 0:
self.me = self.canvas.create_image(0,random.randint(100,700), image = self.images[0])
elif self.direct == 1:
self.me = self.canvas.create_image(1366,random.randint(100,700), image = self.images[0])
self.frame = 0
def update(self):
self.canvas.itemconfig(self.me, image = self.images[self.frame%len(self.images)])
if self.direct == 0: # 고래 속도 설정
self.canvas.move(self.me,13,0)
else:
self.canvas.move(self.me,-13,0)
self.frame = self.frame + 1
def getPos(self):
return self.canvas.coords(self.me)
def getId(self):
return self.me
포식자 생성과 충돌을 관리하는 함수
난수를 생성하여 등장 방향을 정하고 생성됩니다. 생성되면 인덱스를 1씩 늘려 리스트를 추가하였습니다. 화면 밖으로 나가게 된다면 그 리스트를 삭제하도록 하여 메모리가 과도하게 늘어나지 않도록 하였습니다.
for문으로 개복치와 포식자의 위치를 계속 입력 받아 둘의 범위가 겹치게 되면 ‘돌연사’ 문구와 점수가 뜨고 게임이 중지됩니다.
#고래, 상어 관리
def manageEnemy(self):
if (random.randint(0,70) == 0):
self.direct = random.randint(0,1)
if self.direct == 0:
self.enemy_list.append(Shark(self.canvas,self.sharkimages2,self.direct,self.enemy_id))
else:
self.enemy_list.append(Shark(self.canvas,self.sharkimages,self.direct,self.enemy_id))
if (random.randint(0,70) == 0):
self.direct = random.randint(0,1)
if self.direct == 0:
self.enemy_list.append(Whale(self.canvas,self.whaleimages2,self.direct,self.enemy_id))
else:
self.enemy_list.append(Whale(self.canvas,self.whaleimages,self.direct,self.enemy_id))
self.enemy_id = self.enemy_id + 1
for e in self.enemy_list:
mola_pos = self.canvas.coords(self.Mola)
e_pos =self.canvas.coords(e.getId())
#print(mola_pos)
#print(e_pos)
if(e_pos[0]-self.ex<mola_pos[0] and e_pos[0]+self.ex>mola_pos[0] and e_pos[1]-self.ey<mola_pos[1] and e_pos[1]+self.ey>mola_pos[1] ):
self.gameover = True
self.deadsound.play()
self.canvas.itemconfigure(self.Mola, image=self.molaimg3)
self.canvas.create_text(668,334,font="Times 50 bold", text="돌연사")
self.canvas.create_text(668,434,font="Times 20 bold", text= self.scoretext )
for e in self.enemy_list:
e.update()
if e.getPos()[0]<-100 or e.getPos()[0]>1466:
self.canvas.delete(e.getId())
self.enemy_list.pop(self.enemy_list.index(e))
3. 피식자(새우, 해파리)
무작위로 좌우의 화면에서 등장하는 해양 생물입니다.
이 생물들에게 닿으면 점수를 얻고 몸집이 커지게 됩니다.
코드 보기
피식자 클래스 정의
Shrimp와 Jellyfish클래스를 통해 새우와 해파리의 등장 방향과 속도를 정의했습니다.
둘은 해류의 흐름에 따라 떠다니는 컨셉으로 느리게 움직이도록 했습니다.
# 새우 클래스
class Shrimp:
def __init__(self,canvas,images,direct,id):
self.__frame = 0
self.id = 'e'+str(id)
self.canvas=canvas
self.images = images
self.direct = direct #새우 방향 설정
if self.direct == 0:
self.me = self.canvas.create_image(0,random.randint(100,700), image = self.images[0])
elif self.direct == 1:
self.me = self.canvas.create_image(1366,random.randint(100,700), image = self.images[0])
self.frame = 0
def update(self):
self.canvas.itemconfig(self.me, image = self.images[self.frame%len(self.images)])
if self.direct == 0: # 새우 속도 설정
self.canvas.move(self.me,5,0)
else:
self.canvas.move(self.me,-5,0)
self.frame = self.frame + 1
def getPos(self):
return self.canvas.coords(self.me)
def getId(self):
return self.me
# 해파리 클래스
class Jellyfish:
def __init__(self,canvas,images,direct,id):
self.__frame = 0
self.id = 'e'+str(id)
self.canvas=canvas
self.images = images
self.direct = direct #해파리 방향 설정
if self.direct == 0:
self.me = self.canvas.create_image(0,random.randint(100,700), image = self.images[0])
elif self.direct == 1:
self.me = self.canvas.create_image(1366,random.randint(100,700), image = self.images[0])
self.frame = 0
def update(self):
self.canvas.itemconfig(self.me, image = self.images[self.frame%len(self.images)])
if self.direct == 0: # 해파리 속도 설정
self.canvas.move(self.me,5,0)
else:
self.canvas.move(self.me,-5,0)
self.frame = self.frame + 1
def getPos(self):
return self.canvas.coords(self.me)
def getId(self):
return self.me
피식자 생성과 충돌을 관리하는 함수
난수를 생성하여 등장 방향을 정하고 생성됩니다. 생성되면 인덱스를 1씩 늘려 리스트를 추가하였습니다. 화면 밖으로 나가게 된다면 그 리스트를 삭제하도록 하여 메모리가 과도하게 늘어나지 않도록 하였습니다.
for문으로 개복치와 먹이의 위치를 계속 입력 받아 둘의 범위가 겹치게 되면 개복치의 크기가 커지고 점수가 100점씩 증가 됩니다. 이때 먹이는 사라지게 됩니다.
# 새우, 해파리 관리
def manageFood(self):
if (random.randint(0,70) == 0):
self.direct = random.randint(0,1)
if self.direct == 0:
self.food_list.append(Jellyfish(self.canvas,self.Meduimages,self.direct,self.food_id))
else:
self.food_list.append(Jellyfish(self.canvas,self.Meduimages2,self.direct,self.food_id))
if (random.randint(0,70) == 0):
self.direct = random.randint(0,1)
if self.direct == 0:
self.food_list.append(Shrimp(self.canvas,self.shrimpimages2,self.direct,self.food_id))
else:
self.food_list.append(Shrimp(self.canvas,self.shrimpimages,self.direct,self.food_id))
self.food_id = self.food_id + 1
for f in self.food_list:
mola_pos = self.canvas.coords(self.Mola)
f_pos =self.canvas.coords(f.getId())
if(f_pos[0]-self.fx<mola_pos[0] and f_pos[0]+self.fx>mola_pos[0] and f_pos[1]-self.fy<mola_pos[1] and f_pos[1]+self.fy>mola_pos[1] ):
self.eatsound.play()
self.canvas.delete(f.getId())
self.food_list.pop(self.food_list.index(f))
#점수 추가
self.score = 100 + self.score
self.scoretext = "점수: " + str(self.score)
self.canvas.itemconfigure(self.scoreboard, text=self.scoretext)
self.scale()
for f in self.food_list:
f.update()
if f.getPos()[0]<-100 or f.getPos()[0]>1466:
self.canvas.delete(f.getId())
self.food_list.pop(self.food_list.index(f))
인게임 화면
- 게임 화면
게임 실행 시의 화면입니다. 양쪽에서 생물들이 무작위로 등장하게 됩니다.
- 먹이를 먹고 성장했을 때의 화면
먹이를 먹어 점수를 얻고 크기가 커진 모습입니다.
- 적과 충동했을 때의 화면
적과 충돌하면 화면의 중앙에 ‘돌연사’ 문구와 점수가 뜨며 게임이 멈추게 됩니다.
출처
친구가 그려줬습니다.
개발 후기
처음으로 진행되는 게임 프로젝트인 만큼 부족한 점이 많았지만 그만큼 뜻 깊고 뿌듯했던 프로젝트였습니다. 여러가지 자료도 많이 찾아보고 교수님께 질문을 드려가며 문제를 해결했습니다. 다만 새우와 해파리가 일정하게 움직이는 것이 아닌 자유롭게 화면을 돌아다니는 기능을 구현하고 싶었지만 해결하지 못한 점이 아쉽습니다. 이를 개선하여 다른 게임 프로젝트는 많은 기능을 구현 해볼 계획입니다.