내일배움캠프 - python 게임 만들기 - (3) 2일차 개발일지

Dongwoo Kim·2022년 4월 26일
0

스파르타 코딩클럽

내일배움캠프 AI 웹개발자양성과정 2회차

2022.04.26. python 게임만들기 - (3) 2일차 개발일지

1. 프로젝트 정보

1) 스파르타 파이터 - pygame을 이용한 격투게임 만들기
2) 목적 : 직접 게임을 설계해보고 python을 이용하여 설계한 내용을 구현해봄으로써 설계과 구현에 익숙해지고 python 실력을 향상시키고자 함
3) 진행상황 : 공격준비동작, 타이머, hp게이지, 크리티컬, 넉백 구현, 타격, 수비 이펙트 추가
4) 더 개발할 부분 : 궁극기, 캐릭터 다양화, 공격콤보, 태그매치

2. 캐릭터 정의부분

class Fighter:
	...
    damages = [0, 15, 5, 10]  # 0, 상단, 중단, 하단 공격 데미지
    critical_p = 4  # 크리티컬 확률 = 1/critical_p
    critical_d = 2  # 크리티컬 데미지 ( critical_d배)

    # 공격 모션
    attack_delay = 0.5  # 모션 시간
    attack_ticks = 0  # 공격 성공한 시간
    attack_temp = 0  # 공격의 종류를 담는 변수
    ready_delay = 0.7  # 공격 전 준비동작 시간

    # 피격 모션
    hit_delay = 0.7  # 피격 당하는 시간
    hit_ticks = 0  # 피격 당한 시간
    hit_type = 0  # 피격 종류 - 0:피격아님, 1:상단피격, 2:중단피격, 3:하단피격
    critical_hit = False  # 크리티컬 피격 여부 - True:크리티컬발생, False:크리티컬발생안함
    effect_delay = 0.5  # 공격 / 수비 이펙트 지속 시간
    effect_bool = False  # 수비 이펙트 여부 - True:이펙트나오는중, False:이펙트안나오는중
    effect_ticks = 0  # 수비 이펙트 시작 시간
    
    ... 
    # pygame 캐릭터 생성
    # images_path : 캐릭터 이지미 경로 / image : 이미지 명
    def __init__(self, images_path, image):
    ...
        self.attack_high_ready = pygame.image.load(os.path.join(images_path, 'attack_high_ready.png'))
        self.attack_middle_ready = pygame.image.load(os.path.join(images_path, 'attack_middle_ready.png'))
        self.attack_low_ready = pygame.image.load(os.path.join(images_path, 'attack_low_ready.png'))
        self.attack_effect = pygame.image.load(os.path.join(images_path, 'attack_effect.png'))
        self.font = pygame.font.Font(None, 30)  # 효과 폰트
        self.defend_effect = self.font.render('defend!!', True, (0, 0, 0))  # 수비 성공시 이펙트 메시지
        self.critical_effect = self.font.render('critical!!', True, (0, 0, 0))  # 크리티컬시 이펙트 메시지

3. 수정된 함수 (핵심적인부분만)

1) attack()

  • 공격 시 critical 여부 판단
    # 상단/중단/하단 공격
    # attack_type : 공격 종류 - 1:상단, 2:중단, 3:하단
    # enemy : 적의 캐릭터
    def attack(self, attack_type, enemy):
        if self.attack_check(attack_type, enemy):
            critical = False  # 크리티컬 발생 유무
            p = random.randint(1, self.critical_p)
            if p == 1:
                critical = True
            if critical:
                damage = self.critical_d * self.damages[attack_type]
            else:
                damage = self.damages[attack_type]

            enemy.get_hit(attack_type, critical, damage)

2) draw_char()

  • 그리기 함수에 공격준비동작, 공격, 수비 이펙트 추가

    # 캐릭터 그리기
    # screen        : 화면
    # enemy         : 적의 캐릭터
    # attack_bool   : 공격 모션 중인지 여부
    # attack_delay  : 공격 모션 시간
    # attack_ticks  : 공격 성공한 시간
    # attack_temp   : 공격의 종류를 담는 변수
    def draw_char(self, screen, enemy):
        if self.hit_bool:
            # 피격 상태이면 다른 행동 못함
            screen.blit(self.hit_img, (self.x_pos, self.y_pos))
            hit_time = (pygame.time.get_ticks() - self.hit_ticks) / 1000
            if hit_time < self.effect_delay:
                if self.hit_type == 1:
                    screen.blit(self.attack_effect, (self.x_pos + 50 * -1 * self.position, self.y_pos - 50))
                    if self.critical_hit:
                        screen.blit(self.critical_effect, (self.x_pos + 50 * -1 * self.position, self.y_pos - 50))
                elif self.hit_type == 2:
                    screen.blit(self.attack_effect,
                                (self.x_pos + 50 * -1 * self.position, self.y_pos - 50 + self.high_rage))
                    if self.critical_hit:
                        screen.blit(self.critical_effect,
                                    (self.x_pos + 50 * -1 * self.position, self.y_pos - 50 + self.high_rage))
                elif self.hit_type == 3:
                    screen.blit(self.attack_effect, (
                    self.x_pos + 50 * -1 * self.position, self.y_pos - 50 + self.high_rage + self.middle_rage))
                    if self.critical_hit:
                        screen.blit(self.critical_effect, (
                        self.x_pos + 50 * -1 * self.position, self.y_pos - 50 + self.high_rage + self.middle_rage))
            if hit_time > self.hit_delay:
                self.hit_bool = False
                self.hit_ticks = 0
                self.critical_hit = False
        else:
            screen.blit(self.char, (self.x_pos, self.y_pos))

            # 공격 그리기
            # 수비 중이 아닐 때만 가능
            if self.defend_mode == 0:
                # 공격 준비 중인지 확인
                if self.ready_bool:
                    # 공격 후 흐른 시간
                    ready_time = (pygame.time.get_ticks() - self.attack_ticks) / 1000
                    if ready_time > self.ready_delay:
                        self.ready_bool = False
                        self.attack_bool = True
                    else:
                        if self.attack_mode == 1:
                            screen.blit(self.attack_high_ready, (self.x_pos, self.y_pos))
                        elif self.attack_mode == 2:
                            screen.blit(self.attack_middle_ready, (self.x_pos, self.y_pos + self.high_rage))
                        elif self.attack_mode == 3:
                            screen.blit(self.attack_low_ready,
                                        (self.x_pos, self.y_pos + self.high_rage + self.middle_rage))

                # 공격 모션 중인지 확인
                if self.attack_bool:
                    attack_time = (pygame.time.get_ticks() - self.attack_ticks) / 1000 - self.ready_delay
                    if attack_time > self.attack_delay:
                        self.attack_mode = 0
                        self.attack_bool = False
                    else:
                        self.attack(self.attack_mode, enemy)
                        if self.attack_mode == 1:
                            screen.blit(self.attack_high_img, (self.x_pos + self.vector, self.y_pos))
                        elif self.attack_mode == 2:
                            screen.blit(self.attack_middle_img, (self.x_pos + self.vector, self.y_pos + self.high_rage))
                        elif self.attack_mode == 3:
                            screen.blit(self.attack_low_img,
                                        (self.x_pos + self.vector, self.y_pos + self.high_rage + self.middle_rage))

                # 공겨 준비 중 아니고
                # 공격 모션 중 아니면 공격 가능
                if not self.ready_bool and not self.attack_bool:
                    # 최초 공격 버튼 눌렀을 때
                    if self.attack_temp != 0:
                        self.attack_ticks = pygame.time.get_ticks()
                        self.attack_mode = self.attack_temp
                        self.ready_bool = True

            # 수비 그리기
            # 공격 중이 아닐 때, 점프 중이 아닐 때만 가능
            elif self.attack_mode == 0 and self.defend_mode != 0:
                if self.defend_mode == 1:
                    screen.blit(self.defend_high_img, (self.x_pos, self.y_pos))
                elif self.defend_mode == 2:
                    screen.blit(self.defend_middle_img, (self.x_pos, self.y_pos + self.high_rage))
                elif self.defend_mode == 3:
                    screen.blit(self.defend_low_img, (self.x_pos, self.y_pos + self.high_rage + self.middle_rage))

                if self.effect_bool:
                    defend_time = (pygame.time.get_ticks() - self.effect_ticks) / 1000
                    if defend_time < self.effect_delay:
                        if self.defend_mode == 1:
                            screen.blit(self.defend_effect, (self.x_pos + 50 * -1 * self.position, self.y_pos - 20))
                        elif self.defend_mode == 2:
                            screen.blit(self.defend_effect,
                                        (self.x_pos + 50 * -1 * self.position, self.y_pos + self.high_rage + 20))
                        elif self.defend_mode == 3:
                            screen.blit(self.defend_effect,
                                        (self.x_pos + 50 * -1 * self.position,
                                         self.y_pos + self.high_rage + self.middle_rage - 10))

                    else:
                        self.effect_bool = False
                        self.effect_ticks = 0

3) 타이머, hp 바 추가


    # 타이머
    elapsed_time = (pygame.time.get_ticks() - start_ticks) / 1000
    current_time = int(total_time - elapsed_time)
    if current_time < 10:
        time_text = '0' + str(current_time)
        timer = game_font.render(time_text, True, (255, 0, 0))
    else:
        time_text = str(current_time)
        timer = game_font.render(time_text, True, (0, 0, 0))
    screen.blit(timer, (460, 45))

    # 타임 아웃 시 체력이 더 많은 캐릭터가 승리, 체력이 같으면 무승부
    if total_time - elapsed_time <= 0:
        if a.hp > b.hp:
            winner = a.name
        elif b.hp > a.hp:
            winner = b.name
        else:
            winner = 0

        if winner == 0:
            game_result = f'Time out - Draw'
        else:
            game_result = f'Time out - Winner {winner}'

        running = False
    # 체력바 그리기
    screen.blit(hp_bar, (50, 50))
    screen.blit(hp_bar, (550, 50))
    if a.hp > 0:
        a_hp_width = a.hp / 100 * 400
        a_hp_x_pos = 450 - a_hp_width
        while a_hp_width > 0:
            a_hp_width -= 20
            if a.hp > 30:
                screen.blit(hp_point, (a_hp_x_pos, 50))
            else:
                screen.blit(hp_point_red, (a_hp_x_pos, 50))
            a_hp_x_pos += 20
    if b.hp > 0:
        b_hp_width = b.hp / 100 * 400
        b_hp_x_pos = 550
        while b_hp_width > 0:
            b_hp_width -= 20
            if b.hp > 30:
                screen.blit(hp_point, (b_hp_x_pos, 50))
            else:
                screen.blit(hp_point_red, (b_hp_x_pos, 50))
            b_hp_x_pos += 20
profile
kimphysicsman

1개의 댓글

comment-user-thumbnail
2022년 4월 27일

와.... 진짜 잘해주셨네요
해당 기능을 함수 단위로 한번 더 짜보시는 것도 해보세요!

답글 달기