프로젝트 개요
- pygame을 사용하여 Pirate Mario제작
- Youtube Clear Code의 Platformer in Pygame을 따라하며 진행
- 주요 과제: 체력바와 코인 점수를 화면에 보여주고 적과 충돌시 발생하는 이벤트를 구현
프로젝트 내용
- 플레이어가 적의 위로 떨어지면 적을 처치하고 플레이어는 처치와 동시에 자동으로 점프하도록 설정
- 플레이어가 좌우 측면에서 적과 충돌하면 데미지를 받고 잠시동안 반투명 상태가 되면서 데미지를 받지 않고 만약 체력이 0이 되면 월드맵으로 이동
- 실버코인은 1점 골드코인은 5점으로 설정
- 체력바와 코인점수는 화면 좌측 상단에 출력
![](https://velog.velcdn.com/images/sh97818/post/b439775c-9161-4119-b46b-1ffcccae7372/image.gif)
KEEP
PROBLEM
- 플레이어가 일부 지형을 갈 수 없을 정도로 레벨이 잘못 디자인되었고 구조물과 적의 배치가 매우 난잡
- 데미지를 받고 나서 무적시간이 끝나지 않고 지속 (player.py에서 문제가 발생했을 것으로 예상)
import pygame
from support import import_folder
from math import sin
class Player(pygame.sprite.Sprite):
def __init__(self, pos, surface, create_jump_particles, change_health):
super().__init__()
self.import_character_assets()
self.frame_index = 0
self.animation_speed = 0.15
self.image = self.animations['idle'][self.frame_index]
self.rect = self.image.get_rect(topleft = pos)
self.import_dust_run_particles()
self.dust_frame_index = 0
self.dust_animation_speed = 0.15
self.display_surface = surface
self.create_jump_particles = create_jump_particles
self.direction = pygame.math.Vector2(0, 0)
self.player_speed = 8
self.gravity = 0.8
self.jump_speed = -16
self.status = 'idle'
self.facing_right = True
self.on_ground = False
self.on_ceiling = False
self.on_left = False
self.on_right = False
self.change_health = change_health
self.invincible = False
self.invincibility_duration = 450
self.hurt_time = 0
def import_character_assets(self):
character_path = '../graphics/character/'
self.animations = {'idle': [], 'run': [], 'jump': [], 'fall': []}
for animation in self.animations.keys():
full_path = character_path + animation
self.animations[animation] = import_folder(full_path)
def import_dust_run_particles(self):
self.dust_run_particles = import_folder('../graphics/character/dust_particles/run')
def animate(self):
animation = self.animations[self.status]
self.frame_index += self.animation_speed
if self.frame_index >= len(animation):
self.frame_index = 0
image = animation[int(self.frame_index)]
if self.facing_right:
self.image = image
else:
flipped_image = pygame.transform.flip(image, True, False)
self.image = flipped_image
if self.invincible:
alpha = self.wave_value()
self.image.set_alpha(alpha)
else:
self.image.set_alpha(255)
if self.on_ground and self.on_right:
self.rect = self.image.get_rect(bottomright = self.rect.bottomright)
elif self.on_ground and self.on_left:
self.rect = self.image.get_rect(bottomleft = self.rect.bottomleft)
elif self.on_ground:
self.rect = self.image.get_rect(midbottom = self.rect.midbottom)
elif self.on_ceiling and self.on_right:
self.rect = self.image.get_rect(topright = self.rect.topright)
elif self.on_ceiling and self.on_left:
self.rect = self.image.get_rect(topleft = self.rect.topleft)
elif self.on_ceiling:
self.rect = self.image.get_rect(midtop = self.rect.midtop)
def run_dust_animation(self):
if self.status == 'run' and self.on_ground:
self.dust_frame_index += self.dust_animation_speed
if self.dust_frame_index >= len(self.dust_run_particles):
self.dust_frame_index = 0
dust_particle = self.dust_run_particles[int(self.dust_frame_index)]
if self.facing_right:
pos = self.rect.bottomleft - pygame.math.Vector2(6, 10)
self.display_surface.blit(dust_particle, pos)
else:
pos = self.rect.bottomright - pygame.math.Vector2(6, 10)
flipped_dust_particle = pygame.transform.flip(dust_particle, True, False)
self.display_surface.blit(flipped_dust_particle, pos)
def get_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
self.direction.x = 1
self.facing_right = True
elif keys[pygame.K_LEFT]:
self.direction.x = -1
self.facing_right = False
else: self.direction.x = 0
if keys[pygame.K_SPACE] and self.on_ground:
self.jump()
self.create_jump_particles(self.rect.midbottom)
def get_status(self):
if self.direction.y < 0:
self.status = 'jump'
elif self.direction.y > 1:
self.status = 'fall'
else:
if self.direction.x != 0:
self.status = 'run'
else:
self.status = 'idle'
def apply_gravity(self):
self.direction.y += self.gravity
self.rect.y += self.direction.y
def jump(self):
self.direction.y = self.jump_speed
def get_damage(self):
if not self.invincible:
self.change_health(-10)
self.invincible = True
self.hurt_time = pygame.time.get_ticks()
def invincibility_timer(self):
if self.invincible:
current_time = pygame.time.get_ticks()
if current_time - self.hurt_time >= self.invincibility_duration:
self.invincibility_duration = False
def wave_value(self):
value = sin(pygame.time.get_ticks())
if value >= 0: return 255
else: return 0
def update(self):
self.get_input()
self.get_status()
self.animate()
self.run_dust_animation()
self.invincibility_timer()
- 일부 지형에서 비정상적인 움직임이 간헐적으로 발생
- 적의 움직임이 비정상적인 경우가 간헐적으로 발생
- 4, 5, 6단계의 레벨이 3단계의 레벨과 동일
TRY
- 버그 수정을 위해 코드 분석을 진행하는 동시에 게임을 처음부터 다시 작성해보는 것을 시도하고 기존 코드와 다른 부분이 생길 경우 주석처리
- 레벨 재디자인