1학년 2학기 전공 과제로 제작한 tkinter 기반 슈팅 게임 bug_catcher입니다.
해당 과제의 요구 사항은 다음과 같았습니다.
- 주제는 슈팅 또는 어드벤처
-
tkinter모듈을 위주로 제작할 것 - 사운드 기능을 제외한
pygame모듈 사용 금지 - IDE는 Visual Studio로 고정
이러한 조건 내에서 슈팅 게임을 선택한 이유는 가장 단순한 구조이기에 기본적인 게임 구조를 가장 잘 이해할 수 있다고 생각했습니다.
또한 어릴 적 자주 하던 게임인 드래곤 플라이트에서 영감을 받아 종스크롤 슈팅 게임을 선택하였습니다.
하지만 게임 컨셉 상 코드 블록 등의 에셋을 찾기에는 쉽지 않았기 때문에 직접 제작하여 에셋의 퀄리티가 낮았습니다.
그래서 저는 시각적 퀄리티 보다 유저 편의성, 애니메이션 그리고 bgm 등에 더욱 치중하였습니다.
다음은 제가 구현한 기능입니다.
- 메뉴 선택에 대한 방향키와 마우스 동시 지원
- 키 커스터마이징
- 일시정지
- 보스전 시스템
- 플레이어 체력에 따른 bgm 변경
- 게임 오버 애니메이션
아래부터 그 일부를 서술하도록 합니다.
main
메인 구조는 다음과 같습니다.
class SceneChange:
def __init__(self):
self.setting = Setting()
self.window = Tk()
self.window.title("BugCatcher")
self.window.geometry(f"{self.setting.CANVAS_WIDTH}x{self.setting.CANVAS_HEIGHT}")
self.window.resizable(0,0)
self.window.bind("<KeyPress>", self.keyPressHandler)
self.window.bind("<KeyRelease>", self.keyReleaseHandler)
self.window.protocol("WM_DELETE_WINDOW", self.onClose)
self.title_scene = TitleScene(self) # 0
self.game_scene = MainGameScene(self) # 1
# scene list ...
self.scene_list = [self.title_scene, self.game_scene, self.how_scene, self.setting_scene, self.over_scene, self.boss_spagetti_scene, self.vs_boss_clear_scene]
self.scene_idx = 0
self.current_scene = self.scene_list[self.scene_idx]
self.current_scene.pack()
pygame.init()
while True:
try:
self.current_scene.run()
except TclError:
return
self.window.after(16)
self.window.update()
def sceneChange(self, next_scene, **kwargs):
self.current_scene.unpack()
self.scene_idx = next_scene
self.current_scene = self.scene_list[self.scene_idx]
self.current_scene.pack(kwargs) if kwargs else self.current_scene.pack()
# func ...
if __name__ == "__main__":
SceneChange()
각 scene을 class로 구현한 뒤 모든 scene을 handler class에서 관리하는 구조를 선택하였습니다. 또한 각 scene은 BaseScene class를 상속하도록 하였습니다.
애니메이션
게임에서 기능만큼 중요한 것이 시각적인 부분이라고 생각합니다. 때문에 애니메이션을 구현할 필요가 있었는데 pygame 모듈을 사용하지 않고 tkinter 만을 사용하여 애니메이션을 구현하는 것은 한계가 있었습니다.
따라서 요소가 사라졌다가 나타나거나 하는 등의 방식을 사용하였습니다.
def blinkStartText(self):
self.canvas.itemconfig(self.start_text, text="") if self.is_text_visible else self.canvas.itemconfig(self.start_text, text="< Press ENTER or Click to play >")
self.is_text_visible = not self.is_text_visible
self.blink_id = self.window.after(300, self.blinkStartText)
애니메이션 함수를 구현한 뒤 window.after 함수를 이용하여 애니메이션 함수를 재호출 하는 방식으로 애니메이션이 흘러가는 것처럼 보이도록 구현하였습니다.
if self.blink_id is not None:
self.window.after_cancel(self.blink_id)
self.blink_id = None
또한 해당 scene이 unpack 되면 애니메이션이 종료되도록 unpack 함수 내부에서 window.after_cancel 함수를 사용하여 애니메이션을 종료하도록 구현하였습니다.
해당 과제는 A, B, C... 중 B를 받았고 30점 만점에 27점을 받았습니다.
과제의 채점 기준이 코드의 완성도보다는 게임의 시각적 퀄리티에 더 큰 비중을 두고 있었습니다.
제 게임은 기능적인 차원에서는 다른 학생들보다 더 많은 것이 구현되어 있었습니다. 하지만 시각적인 퀄리티가 떨어졌으며 단순한 구조인 슈팅 게임의 한계에 부딪혀 감점을 받은 것으로 예상됩니다.
교수님의 피드백으로는 기존 게임을 개선하는 것보다는 다른 게임을 만들어 보는 것이 좋을 것 같다고 하셨습니다.
이번 프로젝트를 통해 얻은 경험을 바탕으로 다음에는 다른 장르와 개선된 에셋, 더 나은 구조 설계를 이용하여 새롭고 더욱 완성도 높은 결과물을 만들어보고자 합니다.
전체 코드와 자세한 설명은 Github에 있습니다.

Top comments (0)