소연의_개발일지
article thumbnail

첫번째 팀 프로젝트

 

  • 팀이름: 낭만코더 리보키
  • 주제: 미니 rpg 게임을 만드는 팀 프로젝트
  • 프로젝트 기간: 2023/5/11(목) ~ 2023/5/25(목)
  • 개발환경: Window Os, Python, Pyqt, Qt Designer

 

 

개발완료보고서

내 소감

 

요구사항 분석서

 

구현 일정표

 

순서도

 

 

순서도(1차)

 

일반공격순서도

 

 

 

게임 실행 이미지 및 동영상

 

1.일반필드

2.불의지역 전투 이미지

3. 숲의지역 전투 이미지

4. 물의 지역 전투 이미지

5. 눈의 지역 전투 이미지

6. 던전 필드 이미지

7. 던전 필드 이스터에그(유령과 조우시)

 

 

8. 던전 필드 전투 이미지

 

9. 일반필드 전투 동영상

10. 던전전투 동영상

 

포탈위치 강제 변경(일정 횟수 전투 지나면)

 

 

내가 맡은 부분

던전(메인), 전투로직(서브), 일반필드 캐릭터 움직임

 

일반필드 캐릭터 움직임

    def keyPressEvent(self, event):

        # 소연 keypressevent 함수 내 수정(current_index값 받아오기)===========================================================
        # 소연수정추가 - 딕셔너리로 수정
        # 방향키와 좌표 변화값을 저장하는 딕셔너리
        directions = {
            Qt.Key_A: (-20, 0),  # 왼쪽
            Qt.Key_D: (20, 0),  # 오른쪽
            Qt.Key_W: (0, -20),  # 위로
            Qt.Key_S: (0, 20)  # 아래로
        }

        # 현재 스택위젯 값 가져오기
        self.current_index = self.StackWidget_Field.currentIndex()

        ## 일반필드일 때
        if self.current_index == 0:
            self.battle_type = '일반전투'
            # self.portal_sample.show()
            # 움직이는 {라벨} 현재 위치 정보 가져옴 <= 이전위치
            self.normal_previous_position = self.Character_QLabel.geometry()

            if event.key() in directions:  # 방향키 눌렀을 때
                if event.key() == list(directions.keys())[0]:
                    self.Character_QLabel.setPixmap(self.character_left_img)
                if event.key() == list(directions.keys())[1]:
                    self.Character_QLabel.setPixmap(self.character_right_img)
                dx, dy = directions[event.key()]  # 방향키에 해당하는 좌표 변화값을 가져옴
                new_position = self.Character_QLabel.geometry().translated(dx, dy)  # 새 위치 계산
                self.Character_QLabel.move(new_position.x(), new_position.y())  # 새 위치로 이동

                #벽 안나가게 하기
                if self.block_normal_field(new_position.x(), new_position.y()):
                    self.Character_QLabel.setGeometry(self.normal_previous_position)
                    return

                # 왼쪽 상단에 변경된 죄표 값 출력
                self.TopUI_Coordinate_Label.setText(
                    f"x좌표: {self.Character_QLabel.pos().x()} y좌표: {self.Character_QLabel.pos().y()}")

            else:  # 방향키 이외의 키를 눌렀을때를 위한 예외처리
                return

            # 랜덤값 추출 (이동, 전투, 수호대, 포션겟)
            rand_event = random.randrange(1, 11)

            # 50% 확률로 절반 이동
            if rand_event <= 5:
                self.Log_textEdit.append("1칸 이동하였습니다.")

            elif rand_event <= 6:
                self.StackWidget_Item.setCurrentWidget(self.Page_Use_ing)
                for i in range(1, 7):
                    self.damage_status = str(int((self.class_item[i - 1][4].damage * self.guardLevel) * 10))
                    getattr(self, f'Class{i}_DetailsStatus_AtkValue').setText(self.damage_status)
                self.status_page_reset()
                self.low_ui_reset()
                self.HoldSwitch = 1  # 스택 위젯 페이지 이동후에도 캐릭터 이동하는 현상 예외처리
                enemy_rand = random.randrange(4)

                if enemy_rand < 3:
                    self.Log_textEdit.setText("적을 만났습니다.")
                    self.portal_sample.hide()
                    self.StackWidget_Field.setCurrentIndex(2)  # 전투필드로 이동
                    self.Add_Monster_info()
                    self.User_Turn()
                    """
                    적을 만났을때 설정값
                    """
                    self.Widget_Skill.close()
                    #나중에 삭제
                    # self.win_btn.show()

                    # 인벤토리 ui를 소비창으로 변경
                    self.Page_Use.setEnabled(False)
                    self.Btn_Equip.setEnabled(False)
                    self.Btn_Portion.setEnabled(False)
                    self.Btn_Status.setEnabled(False)


                else:
                    self.Log_textEdit.append("타 수호대를 만났습니다.")
                    self.Log_textEdit.setText("적을 만났습니다.")
                    self.portal_sample.hide()
                    self.StackWidget_Field.setCurrentIndex(2)  # 전투필드로 이동
                    self.Add_Monster_info()
                    self.User_Turn()
                    """
                    적을 만났을때 설정값
                    """

                    # 나중에 삭제
                    # self.win_btn.show()

                    # 인벤토리 ui를 소비창으로 변경
                    self.Page_Use.setEnabled(False)
                    self.Btn_Equip.setEnabled(False)
                    self.Btn_Portion.setEnabled(False)
                    self.Btn_Status.setEnabled(False)

            elif rand_event > 6:
                    tent_rate = random.randint(1, 100)
                    if tent_rate < 10:
                        self.item_list[10].stack += 1
                        self.Log_textEdit.append("%s 를 획득하였습니다."
                                                 % self.item_list[10].name)
                        self.consumable_reset()
                    elif self.guardLevel <= 20:
                        self.item_list[0].stack += 1
                        self.item_list[3].stack += 1
                        self.Log_textEdit.append("%s ,%s 를 획득하였습니다."
                                                 % (self.item_list[0].name, self.item_list[3].name))
                        self.consumable_reset()
                    elif 20 < self.guardLevel <= 40:
                        self.item_list[1].stack += 1
                        self.item_list[4].stack += 1
                        self.Log_textEdit.append("%s ,%s 를 획득하였습니다."
                                                 % (self.item_list[1].name, self.item_list[4].name))
                        self.consumable_reset()
                    elif 40 < self.guardLevel <= 60:
                        self.item_list[2].stack += 1
                        self.item_list[5].stack += 1
                        self.Log_textEdit.append("%s ,%s 를 획득하였습니다."
                                                 % (self.item_list[2].name, self.item_list[5].name))
                        self.consumable_reset()
                    elif 60 < self.guardLevel <= 70:
                        self.item_list[6].stack += 1
                        self.Log_textEdit.append("%s 를 획득하였습니다."
                                                 % self.item_list[6].name)
                        self.consumable_reset()
                    elif 70 < self.guardLevel <= 80:
                        self.item_list[7].stack += 1
                        self.Log_textEdit.append("%s 를 획득하였습니다."
                                                 % self.item_list[7].name)
                        self.consumable_reset()
                    else:
                        self.item_list[8].stack += 1
                        self.Log_textEdit.append("%s 를 획득하였습니다."
                                                 % self.item_list[8].name)
                        self.consumable_reset()


            # 일반필드에서 포탈 만났을 때
            if self.Character_QLabel.geometry().intersects(self.portal_sample.geometry()):  # 포탈 만나면
                self.move_to_dungeon()  # 랜덤으로 던전으로 이동


        ## 던전필드일때
        elif self.current_index == 1:
            if event.key() == Qt.Key_M:
                self.teleport_in_dungeon()
            self.battle_type = '던전전투'
            previous_position = self.Character_QLabel_2.geometry()  # 이전 위치

            if event.key() in directions:  # 방향키가 눌렸을 때
                if event.key() == list(directions.keys())[0]:
                    self.Character_QLabel_2.setPixmap(self.character_left_img.scaled(QSize(30, 50), aspectRatioMode=Qt.IgnoreAspectRatio))
                if event.key() == list(directions.keys())[1]:
                    self.Character_QLabel_2.setPixmap(self.character_right_img.scaled(QSize(30, 50), aspectRatioMode=Qt.IgnoreAspectRatio))
                dx, dy = directions[event.key()]  # 방향키에 해당하는 좌표 변화값을 가져옴
                new_position = self.Character_QLabel_2.geometry().translated(dx, dy)  # 새 위치 계산
                self.Character_QLabel_2.move(new_position.x(), new_position.y())  # 새 위치로 이동
            else:
                return

            # 좌표 위에 찍어주기
            self.TopUI_Coordinate_Label.setText(
                f"x좌표: {self.Character_QLabel_2.pos().x()}, y좌표:{self.Character_QLabel_2.pos().y()}")

            ### TODO 랜덤값에 따라 아이템 획득(미완), 던전몬스터들 나오게 하기(완), 1칸 이동
            random_num_for_user_next_action = random.randint(1, 8)
            if random_num_for_user_next_action == 1: #일반던전몬스터
                self.Add_Dungeon_monster_info()
                self.portal_sample.hide()
                self.StackWidget_Field.setCurrentIndex(2)  # 전투필드로 이동
                """
                적을 만났을때 설정값
                """
                self.Widget_Skill.close()
                # 나중에 삭제
                # self.win_btn.show()

                # 인벤토리 ui를 소비창으로 변경
                self.Page_Use.setEnabled(False)
                self.Btn_Equip.setEnabled(False)
                self.Btn_Portion.setEnabled(False)
                self.Btn_Status.setEnabled(False)
                # self.win_btn.show()
                self.User_Turn()

            # 던전에서 MonsterImage 만났을 때 전투 이동
            if self.Character_QLabel_2.geometry().intersects(self.boss_monster.geometry()):
                self.show_messagebox("보스몬스터를 만났습니다!\n전투에 진입합니다.")
                # 전투로 스택위젯 이동 / 전투함수로 이동
                self.user_can_enter_dungeon = True  # 전투에서 이기면 상태 True로 만들어주기
                self.user_meet_boss = True
                self.Add_Dungeon_monster_info() # 보스몬스터 등장
                self.portal_sample.hide()
                self.StackWidget_Field.setCurrentIndex(2)  # 전투필드로 이동
                self.User_Turn()
                """
                적을 만났을때 설정값
                """
                self.Widget_Skill.close()
                # 나중에 삭제
                # self.win_btn.show()

                # 인벤토리 ui를 소비창으로 변경
                self.Page_Use.setEnabled(False)
                self.Btn_Equip.setEnabled(False)
                self.Btn_Portion.setEnabled(False)
                self.Btn_Status.setEnabled(False)
                #find 1111111

            if self.reply_state == False and self.checkCollision(self.Character_QLabel_2, self.ghost_label): #던전 내 포탈 탔을 때
                self.mark_label.move(self.Character_QLabel_2.x() + 10, self.Character_QLabel_2.y())
                self.mark_label.show()
                self.show_messagebox_easter_egg()

            # 보스 몬스터 이기면 던전으로 다시 이동
            #  던전에서 미궁 만났을 때 메세지 출력(임시) -> 코드 합치면 메세지 뜬 후 전투상황으로 이동하도록 하기
            if self.Character_QLabel_2.geometry().intersects(
                    self.entrance.geometry()) and self.user_can_enter_dungeon == True:
                self.show_messagebox("미궁을 만났습니다!")

                #수정필요 수정필요 980625
                self.user_can_enter_dungeon = False
                self.boss_monster.close()
                self.entrance.hide()
                self.ghost_label.hide()
                self.Character_QLabel_2.hide()
                self.move_to_dungeon()

            # 던전 벽 캐릭터가 벗어나지 못하게
            self.block_dungeon_for_type(self.Character_QLabel_2, self.dungeon_number, new_position.x(),
                                        new_position.y(), new_position, previous_position)

            pass
        else: #배틀필드인경우
            if event.key() == Qt.Key_H: # 맵핵 위한 치트키
                self.map_hack()
            if event.key() == Qt.Key_O:
                self.provocation_skill_motion()
            else:
                return




    def user_location(self, x, y):
        """유저의 위치값 반환함"""
        user_present_location = {
            '불': [0, 760, -20, 360],  # 불의지역 x1, x2, y3, y4  값
            '눈': [780, 1560, -20, 360],  # 눈의지역
            '숲': [0, 760, 380, 740],  # 숲의지역
            '물': [780, 1560, 380, 740]  # 물의지역
        }
        for key, value in user_present_location.items():
            if value[0] <= x <= value[1] and value[2] <= y <= value[3]:
                return key

 

 

 

텔레포트

확인을 위해 단축키를 지정해 놨다.

 

 def teleport_in_dungeon(self):
        """던전 내 캐릭터가 텔레포트 하는 함수"""
        # TODO 기능 구현 후 적용하기(구현 완. m키로 단축기 설정)
        random_x = random.randint(self.map_size[self.random_num_for_teleport][0], self.map_size[self.random_num_for_teleport][1])
        random_y = random.randint(self.map_size[self.random_num_for_teleport][2], self.map_size[self.random_num_for_teleport][3])
        self.Character_QLabel_2.move(random_x, random_y)

미하일은 스킬이 없다

우리팀은 불쌍한 미하일을 위해 스킬을 만들기로 했다.

일명 '도발스킬'

3초동안 상대방을 현란하게 하지만 아무런 영향을 주지 않는다.

 
 def move_mihail(self):
        """미하일 움직임 좌표 찍기"""
        random_x = random.randint(self.normal_field_size[0], self.normal_field_size[1])
        random_y = random.randint(self.normal_field_size[2], self.normal_field_size[3])
        self.mihail_label.move(random_x, random_y)

    def provocation_skill_motion(self):
        """미하일의 도발 스킬"""
        # 미하일 번호를 가져와서
        # 테스트 미하일 번호
        for i, j in enumerate(self.list_class):
            if j[0].character_name == '미하일':
                mihail_num = i+1
        if mihail_num == '':
            mihail_num = None

        print('미하일 번호는', mihail_num)

        # 그 라벨의 기본 움직임 x, y를 가져온다.
        lab_basic_position = {
            1: [1300, 25],
            2: [1300, 175],
            3: [1300, 325],
            4: [1300, 500],
            5: [1300, 650],
        }
        # 그 라벨을 가져온다.
        self.mihail_label = self.class_label_list[mihail_num-1]

        # 그 라벨의 이미지를 랜덤으로 배치하게 한다.
        moving_timer = QTimer() #미하일이 움직이는 라벨
        moving_timer.start(100) #100밀리세컨 마다 움직임
        moving_timer.timeout.connect(self.move_mihail) #100세컨마다 미하일 움직임 함수로 이동
        QTimer.singleShot(3000, lambda: moving_timer.stop()) #3초 지나면 움직임 멈춤
        QTimer.singleShot(3000, lambda: self.Log_textEdit.append("미하일의 춤은 현란했다")) #3초 지나면 움직임 멈춤

        QTimer.singleShot(3000, lambda: self.mihail_label.move(lab_basic_position[mihail_num][0], lab_basic_position[mihail_num][1])) #랜덤 숫자만큼 움직임


        # # 그리고 타이머가 끝난 후 그 라벨을 기존 위치로 위치시킨다.

 

맵핵 부분 만들어보기

 

 

누가봐도 나여기 있어요 스킬

옹스짱 과자집 위치 알려주는 느낌처럼 만들고 싶었다.

 

 def portal_hide(self, state):
        """던전 입장할 때 없애줄 라벨들(보스몬스터, 포탈, 캐릭터 라벨)"""
        if state == True:
            self.boss_monster.hide()
            self.entrance.hide()
            self.Character_QLabel_2.hide()
        else:
            self.boss_monster.show()
            self.entrance.show()
            self.Character_QLabel_2.show()

    def map_hack(self):
        """맵핵 구현 함수"""
        self.StackWidget_Field.setCurrentIndex(1) # 던전으로 갔다가
        self.portal_hide(False)

        QTimer.singleShot(3000, lambda: self.StackWidget_Field.setCurrentIndex(2))
        QTimer.singleShot(3000, lambda: self.portal_hide(True))
        QTimer.singleShot(3000, lambda: self.portal_timer.stop())

        #0.5초동안 깜빡거리게
        self.portal_timer = QTimer()
        self.portal_timer.start(100)
        self.portal_timer.timeout.connect(self.blink_portal)

    def blink_portal(self):
        if self.entrance.palette().color(QtGui.QPalette.Background) == QtGui.QColor('transparent'):
            self.entrance.setStyleSheet('background-color: red')
        else:
            self.entrance.setStyleSheet('background-color: transparent')

portal_hide()함수는 여러군데 재활용되게 했다.

 

 


던전 함수  / 던전 내 이벤트 유령 관련 모든 것

 

 # 유령 이미지 불러오기
        self.ghost_img_top = QPixmap('./image/ghost_img/ghost_top.png')  # 귀신 이미지 상
        self.ghost_img_right = QPixmap('./image/ghost_img/ghost_right.png')  # 우
        self.ghost_img_left = QPixmap('./image/ghost_img/ghost_left.png')  # 좌
        self.ghost_img_bottom = QPixmap('./image/ghost_img/ghost_bottom.png')  # 하
        self.ghost_img_right_top = QPixmap('./image/ghost_img/ghost_right_top.png')  # 우상
        self.ghost_img_left_top = QPixmap('./image/ghost_img/ghost_left_top.png')  # 좌상
        self.ghost_img_left_bottom = QPixmap('./image/ghost_img/ghost_left_bottom.png')  # 좌하
        self.ghost_img_right_bottom = QPixmap('./image/ghost_img/ghost_right_bottom.png')  # 좌하
        self.random_num = 1  # 유령 움직임 초기설정

        #라벨 이미지 가져오기
        self.mark_img = QPixmap('./image/mark.png')

        # 느낌표 담을 라벨 만들어주기
        self.mark_label = QLabel(self)
        self.mark_label.setPixmap(self.mark_img.scaled(QSize(50, 50), aspectRatioMode=Qt.IgnoreAspectRatio))
        self.mark_label.setStyleSheet('background-color: transparent')
        self.mark_label.hide()

        # 응답 상태(동시다발적으로 유령만날 때마다 메세지 뜨지 않게)
        self.reply_state = False

        # 이스터에그 리스트
        self.msg_sample_list = {
            1: "그거 아시나요? 우리반에는 점심시간만 되면 배드민턴을 하는 사람들이 있다고 합니다.",
            2: "그거아시나요? 개발원 식당에서 나오는 라면은 물 70퍼 스프 30퍼로 구성되어있습니다.",
            3: "그거 아시나요? 옆팀 팀장님 >시연< 은 가위손 스킬을 지녔습니다.",
            4: "아이템 Hp(소)는 Hp(소) 만큼의 회복량을 가지고있습니다",
            5: "Tip. 그거 아시나요? 스킬 버튼을 누르면 스킬창이 뜹니다",
            6: "사실 미하일은 이혼 전적이 있습니다...",
            7: " 그거 아시나요? 게임 제작자도 엔딩을 못 봤습니다",
            8: "그거 아시나요?? 랜슬롯은 남자를..",
            9: "우리 낭만코더 리보키의 팀장은 커피를 한번에 세잔을 마실 수 있습니다.",
            10: "Tip. 깡깡.... 깡 (파스락)",
            11: "그거 아시나요? 우리반에는 매일 달리는 경주마가 있습니다.",
            12: "그거 아시나요? 이동녀크는 1층의 보스입니다."
        }
 def move_to_dungeon(self):
        """던전으로 랜덤 이동하는 부분"""
        self.StackWidget_Field.setCurrentIndex(1)  # 던전필드로 이동
        self.portal_sample.hide()  # 던전 필드로 이동할 때 포탈 숨겨주기
        # 던전에서 움직일 캐릭터 라벨 만들어주기
        self.Character_QLabel_2 = QLabel(self)
        self.Character_QLabel_2.setFixedSize(30, 50)  # 임시 라벨크기 지정
        self.Character_QLabel_2.setPixmap(
            self.character_right_img.scaled(QSize(30, 50), aspectRatioMode=Qt.IgnoreAspectRatio))
        self.Character_QLabel_2.show()
        # 유령 크기 고정해주기
        self.ghost_fixed_size = 100
        # 던전에서 돌아다닐 유령 담길 라벨 만들어주기
        self.ghost_label = QLabel(self.Page_Dungeon_Field)
        self.ghost_label.setPixmap(self.ghost_img_right.scaled(QSize(self.ghost_fixed_size, self.ghost_fixed_size),
                                                               aspectRatioMode=Qt.IgnoreAspectRatio))  # 이미지 고정
        # 유령 방향 타이머
        self.position = QTimer()
        self.position.setInterval(3000)
        self.position.timeout.connect(self.ghost_direction)
        self.position.start()

        # 유령 타이머
        self.timer = QTimer()
        self.timer.timeout.connect(self.move_label)
        self.timer.start(40)

        # 던전 랜덤으로 가는 부분
        random_dungeon_num = random.randint(1, 4)
        self.random_num_for_teleport = random_dungeon_num
        # 유령 위치 던전 내로 고정하기
        self.ghost_label.move(
            random.randint(self.map_size[random_dungeon_num][0], self.map_size[random_dungeon_num][1]),
            random.randint(self.map_size[random_dungeon_num][2], self.map_size[random_dungeon_num][3]))
        # 유령 라벨 show()시키기
        self.ghost_label.show()
        print('던전번호는', random_dungeon_num)  # 확인용

        self.dungeon_number = random_dungeon_num # 던전 사이즈마다 다르게 이동
        self.dungen_map_dict = {
            1: ['./image/배경/던전_1.png', 592, 631],
            2: ['./image/배경/던전_2.png', 567, 644],
            3: ['./image/배경/던전_3.png', 558, 657],
            4: ['./image/배경/던전_4.png', 504, 674],
        }
        self.dungeon_img_label.setPixmap(QPixmap(self.dungen_map_dict[random_dungeon_num][0]))
        self.Character_QLabel_2.move(self.dungen_map_dict[random_dungeon_num][1], self.dungen_map_dict[random_dungeon_num][2])

        # 던전 입구 만들기
        self.Show_Dungeon_Entrance(random_dungeon_num)
 def Show_Dungeon_Entrance(self, map_num):
        """던전 입구 랜덤으로 만들어주는 함수"""
        # 미궁 버튼 임시로 만들어주기
        self.entrance = QLabel(self)
        self.entrance.setText("미궁")  # 임시지정(이미지 씌우기는 나중에)
        self.entrance.setFixedSize(50, 50)  # 임시 라벨 크기 지정
        self.entrance.setStyleSheet('background-color: transparent')  # 임시 라벨 색 지정
        self.entrance.setPixmap(QtGui.QPixmap('./image/door_closed.png').scaled(QSize(30, 30), aspectRatioMode=Qt.IgnoreAspectRatio))

        self.entrance.move(random.randint(self.map_size[map_num][0], self.map_size[map_num][1]),
                           random.randint(self.map_size[map_num][2], self.map_size[map_num][3]))  # 던전 15*15 사이즈
        self.entrance.show()  # 미궁 띄우기

        # 보스 MonsterImage 위치 임시로 만들어주기
        self.boss_monster = QLabel(self)  # 보스 MonsterImage 나타날 포탈 임시
        self.boss_monster.setText("MonsterImage")
        self.boss_monster.setFixedSize(30, 30)  # 임시 라벨크기지정
        self.boss_monster.setStyleSheet('background-color: red')  # 임시로 빨간색으로
        self.boss_monster.move(random.randint(self.map_size[map_num][0], self.map_size[map_num][1]),
                               random.randint(self.map_size[map_num][2],
                                              self.map_size[map_num][3]))  # 보스 MonsterImage 랜덤으로 등장
        self.boss_monster.show()  # 보스몬스터 띄우기

        # 검은 라벨 만들어서 위에 덮기(유저가 플레이할 때 던전이 안보이게)
        # black_label = QLabel(self)
        # black_label.move(0, 30)
        # black_label.setStyleSheet('background-color: rgba(0, 0, 0, 100)')  # 100으로 설정되어 있는 투명도 높이면 어두워짐
        # black_label.setFixedSize(1580, 780)  # 사이즈고정
        # black_label.show()
 def block_dungeon_for_type(self, character, dungeon_num, new_x, new_y, new_p, before_p):
        """던전 크기별로 맵에서 나가지 못하게 하기"""
        if not ((self.map_size[dungeon_num][0] <= new_x <= self.map_size[dungeon_num][1]) and (
                self.map_size[dungeon_num][2] <= new_y <= self.map_size[dungeon_num][3])):
            character.setGeometry(before_p)
        if self.block_dungeon_wall(new_p, before_p, self.wall_list, dungeon_num):
            character.setGeometry(before_p)

    def block_dungeon_wall(self, new_position, previous_position, wall_list, num):
        """유저가 던전벽에서 나아가지 못하게 하기"""
        for key, value in wall_list.items():
            if key == num:  # 특정 던전 사이즈일때
                for i in value:  # 딕셔너리 내 리스트 x, y값 가져와서 비교(self.wall_list 검색해보면 됨)
                    if i[0] < new_position.x() < i[1] and i[2] < new_position.y() < i[3]:  # 벽 x, y값 사이에 들어가면
                        self.Character_QLabel_2.setGeometry(previous_position)  # 이전 위치로 이동
                        return True  # True 반환
        return False

    def block_normal_field(self, now_x, now_y):
        """일반필드 맵에서 벗어나지 못하게 하기"""


        if not ((self.normal_field_size[0] < now_x < self.normal_field_size[1]) and
                (self.normal_field_size[2] < now_y < self.normal_field_size[3])):
            return True
        return False

    def show_messagebox(self, text):
        """특정 문구 메세지박스 띄워주기"""
        reply = QMessageBox()
        reply.setText(text)
        reply.exec_()
ghost_direction(self):
        """유령 방향 랜덤으로 지정 및 변환"""
        # 랜덤값 따라 방향지정
        self.random_num = random.randint(1, 6)
        # print('유령랜덤값: ',self.random_num)
        ghost_direction = {
            1: self.ghost_img_right_bottom,  # 우하
            2: self.ghost_img_right_top,  # 우상
            3: self.ghost_img_left_top,  # 좌상
            4: self.ghost_img_left_bottom,  # 좌하
            5: self.ghost_img_left,  # 왼쪽
            6: self.ghost_img_right,  # 오른쪽
        }
        self.ghost_label.setPixmap(
            ghost_direction[self.random_num].scaled(QSize(self.ghost_fixed_size, self.ghost_fixed_size),
                                                    aspectRatioMode=Qt.IgnoreAspectRatio))
def move_label(self):
        """유령 움직임 조정 함수"""
        # 현재 라벨 포지션 받기
        current_pos = self.ghost_label.pos()
        # x, y값 조정
        x_start, x_end = self.map_size[self.dungeon_number][0], self.map_size[self.dungeon_number][1]
        y_start, y_end = self.map_size[self.dungeon_number][2], self.map_size[self.dungeon_number][3]

        # 새 위치 계산
        new_positions = {
            1: (min(current_pos.x() + 1, x_end), min(current_pos.y() + 1, y_end)),  # 우하
            2: (min(current_pos.x() + 1, x_end), max(current_pos.y() - 1, y_start)),  # 우상
            3: (max(current_pos.x() - 1, x_start), max(current_pos.y() - 1, y_start)),  # 좌상
            4: (max(current_pos.x() - 1, x_start), min(current_pos.y() + 1, y_end)),  # 좌하
            5: (max(current_pos.x() - 1, x_start), current_pos.y()),  # 왼쪽
            6: (min(current_pos.x() + 1, x_end), current_pos.y())  # 오른쪽
        }
        new_x, new_y = new_positions[self.random_num]

        # 유령라벨 새 포지션으로 옮기기
        self.ghost_label.move(new_x, new_y)
 def show_messagebox_easter_egg(self):
        """이스터에그 메세지 박스 보여주기 (질문하는 메세지박스 띄우기)"""
        self.reply_state = True
        # paper_img = QPixmap('구겨진_종이조각-removebg-preview.png')

        msg_box = QMessageBox()
        msg_box.setIconPixmap(QPixmap("./image/paper.png"))
        msg_box.setText("구겨진 종이조각을 유령이 주었습니다... 보시겠습니까?")
        msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        result = msg_box.exec_()

        if result == QMessageBox.Yes:
            self.show_second_messagebox()
        else:
            self.mark_label.hide()
            pass

        self.reply_state = False

 def show_second_messagebox(self):
        ranodm_num = random.randint(1, len(self.msg_sample_list.keys()))
        msg_box = QMessageBox()
        msg_box.setWindowFlags(Qt.FramelessWindowHint)
        msg_box.setStyleSheet('background-color: rgb(242, 238, 203)')
        if ranodm_num == 3:
            pass # 일단 패스 msg_box.setIconPixmap(QPixmap('./image/모야.jpg')) #호현 머리자르는 사진
        msg_box.setText(f"쪽지에 작성된 내용은...\n{self.msg_sample_list[ranodm_num]}")
        msg_box.exec_()
        self.mark_label.hide()
 def change_the_portal_location(self, index, num):
        """포탈 위치 랜덤 배정"""
        if index == 1:
            self.battle_cnt += 1
        if index == 2:
            self.battle_cnt_for_dungeon += 1

        if self.battle_cnt % num == 0 and index == 1: #노말필드일 경우
            self.Log_textEdit.append(f'전투가 {num}번 되었습니다. 포탈 위치를 변경합니다.')
            print(f"############################일반필드전투가 {num}번 되었습니다. 포탈 위치를 변경합니다.")
            self.portal_sample.move(random.randint(0, 1580), random.randint(0, 760))  # 포탈 위치 랜덤으로 배정

        if self.battle_cnt_for_dungeon % num == 0 and index == 2:# 던전필드인 경우
            self.Log_textEdit.append(f'전투가 {num}번 되었습니다. 포탈 위치를 변경합니다.')
            print(f"############################던전필드전투가 {num}번 되었습니다. 포탈 위치를 변경합니다.")
            random_x = random.randint(self.map_size[self.random_num_for_teleport][0],self.map_size[self.random_num_for_teleport][1])
            random_y = random.randint(self.map_size[self.random_num_for_teleport][2],self.map_size[self.random_num_for_teleport][3])
            self.entrance.move(random_x, random_y)

 

보스 만나면 층 오픈시켜주기 보스 사진도 바뀌게

7층 최종보스 만나면 엔딩 페이지 보여주게 하기

 

    def user_win_the_boss_stage(self, state):
        """보스와의 전투에서 이겼을 때 변하는 부분"""
        #TODO 여기에 에필로그 이동으로 이동하기 중요 중요 중요
        if state == True:
            self.dungeon_floor += 1
            print('던전층: ', self.dungeon_floor)
            self.show_messagebox("어디선가 문이 열리는 소리가 들립니다...")
            self.user_meet_boss = False
            self.entrance.setPixmap(QtGui.QPixmap('./image/downstair.png'))
            map_num = self.random_num_for_teleport
            self.boss_monster.move(random.randint(self.map_size[map_num][0], self.map_size[map_num][1]),
                                   random.randint(self.map_size[map_num][2], self.map_size[map_num][3]))
            # self.boss_monster.close()
            if self.dungeon_floor == 8:
                self.show_messagebox("당신은 게임을 클리어했습니다!")
                self.show_ending() #엔딩 크레딧 넣기
    def show_ending(self):
        """엔딩페이지 보여주는 곳"""
        self.StackWidget_Field.setCurrentIndex(0) #일반필드로 옮겨주고
        hide_list = [self.Character_QLabel_2, self.entrance, self.boss_monster,
                     self.portal_sample,self.Character_QLabel ]

        # 라벨리스트를 숨겨준다.
        for label in hide_list:
            label.hide()

        #영상의 경로를 불러온다
        self.movie_1 = QMovie('./video/boss_ending.gif', bytearray(), self)
        self.movie_2 = QMovie('./video/boki_endingcredits.gif', bytearray(), self)

        self.ending_timer = QTimer()
        self.ending_timer_2 = QTimer()

        self.ending_timer.timeout.connect(self.play_second_gif)
        self.ending_timer_2.timeout.connect(self.ending_message)
        self.play_first_gif()

    def play_first_gif(self):
        self.BackGround_Nomal.setMovie(self.movie_1)
        self.movie_1.start()
        self.ending_timer.start(130000)

    def play_second_gif(self):
        self.ending_timer.stop()
        self.BackGround_Nomal.setMovie(self.movie_2)
        self.movie_1.stop()
        self.movie_2.start()
        self.ending_timer_2.start(16000)
    def ending_message(self):
        self.close()
        self.show_messagebox("게임이 종료되었습니다.\n플레이 해 주셔서 감사합니다!")

Qtimer를 두번 사용하였다.


팀장님과 같이 한 공격 로직.

나는 일반공격 + 턴 넘기는 부분의 함수를 짜서 넘기고 - 팀장님은 스킬 부분과 추합하고 같이 디버깅을 잡았다.

팀장님이 고생을 많이 하심.

 

나의 접근방식(영어는 함수이름임)

User_Turn ->(go_to_normalfield)-> attack_function -> monster_got_damage -> monster_attack_users ->(go_to_normalfield) 하고

다시 user_turn 변수에 따라 User_Turn으로 돌아가는 재귀함수에 던전전투 / 보스전투를 넣어 재활용했다.

시간이 좀 더 있었다면 공격하는 부분도 할수 있었을 텐데 아쉽다.

 

 def User_Turn(self):
        """유저 턴이었을 때"""
        if self.battle_type == '일반전투':
            if self.go_to_normalfield(): #일반필드나가기
                return
            if self.user_turn >= 5:  # 만약 유저 턴이 5보다 크다면
                self.user_turn = 1  # 1로 만들어준다.
                print("여기서 오류가 나나요 여기는 유저턴임 몬스터가 유저 때리기 전임")
                self.monster_attack_users()  # 이거 여기다 넣으니까 (동시 다발적으로 캐릭터가 죽으면 턴이 넘어가도 몬스터가 공격을안함) 이 현상이 해결됨..

            else:
                self.user_turn += 1  # 그렇지 않다면 턴 더해주기
            print('현재 턴은', self.user_turn)  # 확인용


        ###################################################################
        if self.battle_type == '던전전투':
            if self.go_to_dungeonfield(): #던전필드로 나가기
                return

            if self.user_turn >= 5:  # 만약 유저 턴이 5보다 크다면
                self.user_turn = 1  # 1로 만들어준다.
                print("여기서 오류가 나나요 여기는 유저턴임 몬스터가 유저 때리기 전임")
                self.monster_attack_users()  # 이거 여기다 넣으니까 (동시 다발적으로 캐릭터가 죽으면 턴이 넘어가도 몬스터가 공격을안함) 이 현상이 해결됨..
            else:
                self.user_turn += 1  # 그렇지 않다면 턴 더해주기
            print('현재 턴은', self.user_turn)  # 확인용


        # 유저턴 hp 0 이상이면 활성화 / 아니면 다음 턴으로 넘어감
        selected_character_hp = self.class_hp_dict[self.user_turn]  # 선택된 캐릭터의 hp
        if selected_character_hp > 0:
            self.active_class_frame(self.user_turn)  # 해당 클래스 버튼들 활성화 및 다른 프레임 버튼들 비활성화

        else:
            self.User_Turn()  # 0보다 작으면 다시 User_Turn 돌아감 (재귀함수)

 

  def attack_function(self, num):
        """공격 함수(공격버튼 외 다른 버튼 비활성화, 몬스터 공격버튼 활성화)"""
        self.attackType = 0
        self.carit = num
        self.Log_textEdit.append(getattr(self, f"Status{num}_1_Name").text()+"이(가) 공격버튼을 선택했습니다.")
        self.name = [self.list_class[0][0].character_name, self.list_class[1][0].character_name,
                     self.list_class[2][0].character_name, self.list_class[3][0].character_name,
                     self.list_class[4][0].character_name, self.list_class[5][0].character_name]
        selection_class = self.name.index(getattr(self, f'Status{num}_1_Name').text())+1
        self.choice_btn = int(getattr(self, f'Class{selection_class}_DetailsStatus_AtkValue').text())
        print(self.name)
        print(selection_class)
        print(getattr(self, f'Status{num}_1_Name').text())
        print("클래스의 이름은?? : "+getattr(self, f'Class{selection_class}_DetailsStatus_Name').text())
        print("클래스의 공격력 : %d"%int(getattr(self, f'Class{selection_class}_DetailsStatus_AtkValue').text()))

        # fixfind
        # 공격 버튼 외에 다른 버튼 비활성화
        getattr(self, f'Status{num}_Action2_Skill').setEnabled(False)
        getattr(self, f'Status{num}_Action3_Item').setEnabled(False)
        getattr(self, f'Status{num}_Action4_Run').setEnabled(False)

        # 몬스터 공격 버튼 활성화
        self.monster_btn_active(True)
 def monster_got_damage(self, num):

        """몬스터 데미지 입는 함수"""
        self.atkup_reset(self.carit)
        if self.battle_type == '일반전투':
            monster_hp = self.monster_hp_dict
        elif self.battle_type == '던전전투':
            monster_hp = self.dungeon_random_monster_hp


        if self.attackType == 1:
            if self.target == 2:
                for i in range(1, len(self.monster_hp_dict.keys()) + 1):
                    monster_hp[i] -= self.choice_btn
                    self.Log_textEdit.append(
                        "%s에게 %d만큼의 데미지를 입혔습니다." % (getattr(self, f'Monster_{i}_Name').text(), self.choice_btn))
            elif self.target == 1:
                print("내가 선택한 스킬의 데미지%d"%self.choice_btn)
                self.Log_textEdit.append("%s에게 %d만큼의 데미지를 입혔습니다."%(getattr(self, f'Monster_{num}_Name').text(), self.choice_btn))
                monster_hp[num] -= self.choice_btn
            elif self.target == 3:
                self.provocation_skill_motion()

            self.Widget_Skill.close()
        elif self.attackType == 0:
            self.attack_effect(num-1)
            monster_hp[num] -= self.choice_btn  # 임시로 몬스터 체력에는 100씩 데미지 입힘


        print(f'{num}번 몬스터의 맞은 후 체력: {monster_hp[num]}')  # 확인용

        if self.battle_type == '일반전투':
            if self.go_to_normalfield():
                return
        if self.battle_type == '던전전투':
            if self.go_to_dungeonfield():
                return

        # 체력 0인 얘들은 안보여주기
        for m, n in monster_hp.items():
            if n < 0:
                print(f'{m}번 몬스터를 처치했습니다.')  # 콘솔 확인용

                self.Log_textEdit.append(f'{m}번 몬스터를 처치했습니다.')
                #132123132132132
                monster_hp[m] = 0

                # 죽은 몬스터 구성들은 숨겨주기
                getattr(self, f'Monster_{m}_Name').hide()
                getattr(self, f'Monster_{m}_QLabel').hide()
                getattr(self, f'Monster_{m}_QButton').hide()
                getattr(self, f'Monster_{m}_QProgressBar').hide()

        if self.battle_type == '일반전투':
            if self.go_to_normalfield():
                return
        if self.battle_type == '던전전투':
            if self.go_to_dungeonfield():
                return
        # if all(v == 0 for v in self.monster_hp_dict.values()):
        #     self.guardLevel += 1  # 적을 모두처치하면 레벨업 +1
        #     print("현재 레벨 %d" % self.guardLevel)
        #     self.TopUI_Level_Label.setText("%s의 수호대 Level : %d" % ("땅", self.guardLevel))
        #     print("몬스터 체력이 0입니다.")
        #     self.Log_textEdit.append('몬스터를 모두 처치했습니다....')
        #     self.StackWidget_Field.setCurrentIndex(0)  # 일반필드로 이동

        # 프로그래스바에 유저가 때린 몬스터 체력 넣어주기
        getattr(self, f'Monster_{num}_QProgressBar').setValue(monster_hp[num])  # 몬스터 체력

        # 몬스터 버튼 비활성화
        self.monster_btn_active(False)

        # 공격 버튼 비활성화
        getattr(self, f'Status{self.user_turn}_Action1_Attack').setEnabled(False)

        print(f'다음 턴으로 넘어가야됨=========================(지금 유저턴{self.user_turn})')
        # self.go_to_normalfield()

        if self.user_turn == 5:
            self.user_turn = 0  # 유저 턴 0으로 만들어주고 다른 버튼들 비활성화 시켜줌(나중에 단축시킬 것)
            self.set_actions_enabled(5, False)  # 비활성화 시켜주고 소연수정
            ### 몬스터 공격 함수로 넘어가야됨
            print("몬스터 데미지 입는 곳 가기 전임")
            self.monster_attack_users()

        else:  # 유저턴이 5 미만이면 다시 유저턴으로 돌아감
            ################################### 다음 턴으로 넘어가기 몬스터 턴에서 더해주기!!!!!!!!!!!! ########################################
            self.User_Turn()
 def go_to_normalfield(self):
        # 만약 모든 유저 hp가 0이면 일반필드로 나가게 함
        if all(h == 0 for h in self.class_hp_dict.values()):

            print("유저체력 부족해서 죽은 경우")
            self.Log_textEdit.append('유저 체력이 부족하여 후퇴합니다...한 발자국만 움직여 보자...')
            self.set_actions_enabled(5, False)  # 클래스들의 모든 버튼 비활성화 시켜줌 <= 지금 작동 안함 살려조ㅁ
            self.current_index = 0
            self.return_user_state() #유저들의 체력 초기화
            self.change_the_portal_location(1, 10) # 미궁 랜덤 스팟
            self.StackWidget_Field.setCurrentIndex(0)  # 일반필드로 이동
            self.portal_sample.show()
            if self.guardLevel < 50:
                self.item_list[-2].stack = self.item_list[-2].stack + 5
            else:
                self.item_list[-2].stack = self.item_list[-2].stack + 5
                self.item_list[-1].stack = self.item_list[-1].stack + 5
            self.consumable_reset()
            return True


        if all(v == 0 for v in self.monster_hp_dict.values()):
            self.guardLevel += 1

            print("현재 레벨 %d(몬스터 처치한 경우)" % self.guardLevel)
            self.TopUI_Level_Label.setText("%s의 수호대 Level : %d" % (self.guardname, self.guardLevel))
            print("몬스터 체력이 0입니다.")
            self.Log_textEdit.append('몬스터를 모두 처치했습니다....')
            # noraml_previous_position
            self.user_turn = 0
            self.set_actions_enabled(5, False) #클래스들의 모든 버튼 비활성화 시키기
            self.Character_QLabel.move(self.normal_previous_position.x(), self.normal_previous_position.y())
            self.change_the_portal_location(1, 10)  # 미궁 랜덤 스팟
            self.StackWidget_Field.setCurrentIndex(0)  # 일반필드로 이동
            print('몬스터 다 죽이고 나왔을 때 유저턴', self.user_turn)
            self.portal_sample.show()
            return True
        return False

    def go_to_dungeonfield(self):
        """던전에서 싸우고 다시 던전으로 돌아가는 함수"""

        if all(h == 0 for h in self.class_hp_dict.values()):

            print("유저체력 부족해서 죽은 경우")
            self.Log_textEdit.append('유저 체력이 부족하여 후퇴합니다...한 발자국만 움직여 보자...')
            self.set_actions_enabled(5, False)  # 클래스들의 모든 버튼 비활성화 시켜줌 <= 지금 작동 안함 살려조ㅁ
            self.change_the_portal_location(2, 7) # 전투 7번만다 미궁 랜덤 스팟
            self.return_user_state()  # 유저들의 체력 초기화
            self.StackWidget_Field.setCurrentIndex(1)  # 던전필드로 이동
            self.portal_hide(False) # 포탈, 캐릭터, 보스포탈 나오게 하기
            self.user_win_the_boss_stage(self.user_meet_boss)
            return True

        if all(v == 0 for v in self.dungeon_random_monster_hp.values()):
            self.guardLevel += 1
            print("현재 레벨 %d(몬스터 처치한 경우)" % self.guardLevel)
            self.TopUI_Level_Label.setText("%s의 수호대 Level : %d" % ("땅", self.guardLevel))
            print("몬스터 체력이 0입니다.")
            if self.guardLevel < 50:
                self.item_list[-2].stack = self.item_list[-2].stack + 5
            else:
                self.item_list[-2].stack = self.item_list[-2].stack + 5
                self.item_list[-1].stack = self.item_list[-1].stack + 5
            self.consumable_reset()
            self.Log_textEdit.append('몬스터를 모두 처치했습니다....')
            self.user_turn = 0
            self.set_actions_enabled(5, False)  # 클래스들의 모든 버튼 비활성화 시키기
            self.StackWidget_Field.setCurrentIndex(1)  # 던전필드로 이동
            print('몬스터 다 죽이고 나왔을 때 유저턴', self.user_turn)
            self.portal_hide(False)  # 포탈, 캐릭터, 보스포탈 나오게 하기
            self.change_the_portal_location(2, 7) # 전투 7번마다 랜덤 스팟되게 하기
            self.user_win_the_boss_stage(self.user_meet_boss)
            return True
        return False

 

 def monster_attack_users(self):
        """몬스터가 유저 랜덤으로 때리는 함수"""
        # 살아있는 몬스터가 돌아가면서 랜덤으로 유저 때림
        # 유저hp가 0이 되면 패스
        # 살아있는 몬스터 수 세기(죽으면 hide() 시켜줌)


        if self.battle_type == '일반전투':
            monster_hp = self.monster_hp_dict
        elif self.battle_type == '던전전투':
            monster_hp = self.dungeon_random_monster_hp

        self.alive_monster = []  # 살아있는 몬스터 리스트에 담아주기
        for i, j in monster_hp.items():  # 몬스터 체력 딕셔너리는 몬스터 호출 함수 Add_Monster_info 에 있음. 여기서 체력을 가져와줌
            print(i, j)  # 확인용
            if j > 0:  # 만약 몬스터 체력이 0 이상이면
                self.alive_monster.append(i)  # 빈 리스트에 더해준다.
                pass
            elif j <= 0:  # 만약 몬스터 체력이 0 이면
                pass

        print('살아있는 몬스터 리스트는', self.alive_monster)

        # 살아있는 클래스 수 세기
        self.alive_class = [key for key, value in self.class_hp_dict.items() if value > 0]


        # 어떤 클래스 때릴지 랜덤으로 리스트에 추가 - 몬스터 갯수만큼 세주기
        # 수정해서 미안하지만 리스트 6번을 공격 대상에서 빼야 했어서 어쩔 수 없었음
        attacked_class_list = []
        for i in range(1, len(self.alive_monster) + 1):
            attacked_class_list.append(random.choice(self.alive_class))

        print("attacked_class_list", attacked_class_list)

        # 클래스의 hp 깎아준다
        # 클래스 라벨들


        # 클래스 값 넣어줄 리스트
        class_hp_present_value_list = [
            self.Status1_2_HpValue,
            self.Status2_2_HpValue,
            self.Status3_2_HpValue,
            self.Status4_2_HpValue,
            self.Status5_2_HpValue,
        ]
        death_class = []

        if not self.user_meet_boss: #보스를 만나지 않은 경우(일반몬스터)

            for m in range(1, len(self.alive_monster) + 1):
                # self.Log_textEdit.append(f"{m}번째 몬스터가 {attacked_class_list[m - 1]}번 클래스를 100만큼 때립니다...")
                self.nomalfield_monster_skill = random.randrange(0,10)
                if self.nomalfield_monster_skill > 3:
                    self.Log_textEdit.append(f"{m}번째 몬스터가 스킬을 사용하여 %s에게 %d의 데미지를 입혔습니다"%(getattr(self, f"Status{attacked_class_list[m - 1]}_1_Name").text(),int(self.class_hp_dict[attacked_class_list[m - 1]]/10)))
                    self.nomalfield_atk = 0.3
                else:
                    self.Log_textEdit.append(f"{m}번째 몬스터가 일반 공격을 사용하여 %s에게 %d의 데미지를 입혔습니다"%(getattr(self, f"Status{attacked_class_list[m - 1]}_1_Name").text(),int(self.class_hp_dict[attacked_class_list[m - 1]]/10)))
                    self.nomalfield_atk = 0.1
                if (int(self.class_hp_dict[attacked_class_list[m - 1]] * self.nomalfield_atk) < int(getattr(self, f'Class{attacked_class_list[m - 1]}_DetailsStatus_ShieldValue').text())):
                    self.Log_textEdit.append("%s이(가) 방어력이 높아 적의 공격을 막았습니다"%(getattr(self, f"Status{attacked_class_list[m - 1]}_1_Name").text()))
                else:
                    self.class_hp_dict[attacked_class_list[m - 1]] = self.class_hp_dict[attacked_class_list[m - 1]] - (int(self.class_hp_dict[attacked_class_list[m - 1]]/10) - int(getattr(self, f'Class{attacked_class_list[m - 1]}_DetailsStatus_ShieldValue').text()))    # 임시로 100씩 때린다 <- 방어력을 넣어 공격력 감쇄 추가해봄
                print(self.class_hp_dict)  # 확인용

                for i in range(1, 6):
                    if self.class_hp_dict[i] <= 0:
                        if attacked_class_list[m - 1] not in death_class:
                            death_class.append(attacked_class_list[m - 1])
                            self.class_hp_dict[attacked_class_list[m - 1]] = 0
                            print('죽은 클래스는', death_class)
                            self.Log_textEdit.append(f"{attacked_class_list[m - 1]}번 클래스가 사망했습니다.")
                            print(f"{attacked_class_list[m - 1]}번 클래스가 사망했습니다.")
                        else:
                            self.class_hp_dict[attacked_class_list[m - 1]] = 0
        else:
            user_atk = random.randrange(5)
            self.boss_monster_skill = random.randrange(0, 10)
            if self.boss_monster_skill > 7:
                self.Log_textEdit.append("보스몬스터가 스킬을 사용하여 %s에게 %d의 데미지를 입혔습니다" % (
                getattr(self, f"Status{attacked_class_list[user_atk - 1]}_1_Name").text(),
                int(self.class_hp_dict[attacked_class_list[user_atk - 1]] / 50)))
                self.nomalfield_atk = 0.3
            else:
                self.Log_textEdit.append("보스몬스터가 스킬을 사용하여 %s에게 %d의 데미지를 입혔습니다" % (
                getattr(self, f"Status{attacked_class_list[user_atk - 1]}_1_Name").text(),
                int(self.class_hp_dict[attacked_class_list[user_atk - 1]] / 10)))
                self.nomalfield_atk = 0.1
            if (int(self.class_hp_dict[attacked_class_list[user_atk - 1]] * self.nomalfield_atk) < int(
                    getattr(self, f'Class{attacked_class_list[user_atk - 1]}_DetailsStatus_ShieldValue').text())):
                self.Log_textEdit.append("%s이(가) 방어력이 높아 적의 공격을 막았습니다" % (
                    getattr(self, f"Status{attacked_class_list[user_atk - 1]}_1_Name").text()))
def monster_btn_active(self, state):
        """몬스터 버튼 활성화 함수"""
        for i in range(1, 11):
            getattr(self, f'Monster_{i}_QButton').setEnabled(state)
        # Monster_1_QButton

    def active_class_frame(self, index):
        """특정 클래스 프레임 활성화 """
        print('가져온 인덱스는', index)
        for num in range(1, 6):
            if num == index:
                getattr(self, f'Status{num}_Action1_Attack').setEnabled(True)
                getattr(self, f'Status{num}_Action2_Skill').setEnabled(True)
                getattr(self, f'Status{num}_Action3_Item').setEnabled(True)
                getattr(self, f'Status{num}_Action4_Run').setEnabled(True)
            else:
                getattr(self, f'Status{num}_Action1_Attack').setEnabled(False)
                getattr(self, f'Status{num}_Action2_Skill').setEnabled(False)
                getattr(self, f'Status{num}_Action3_Item').setEnabled(False)
                getattr(self, f'Status{num}_Action4_Run').setEnabled(False)

    def set_actions_enabled(self, status_count, enabled):
        """클래스 프레임 활성화/비활성화 시키기"""
        for i in range(1, status_count + 1):
            getattr(self, f'Status{i}_Action1_Attack').setEnabled(enabled)
            getattr(self, f'Status{i}_Action2_Skill').setEnabled(enabled)
            getattr(self, f'Status{i}_Action3_Item').setEnabled(enabled)
            getattr(self, f'Status{i}_Action4_Run').setEnabled(enabled)
    def return_user_state(self):
        """유저턴 초기화 시켜주기"""
        self.user_turn = 0
        for i in range(1, 6):  # 서플로 돌려준 클래스유저들의 체력을 빈 딕셔너리에 1부터 5까지 다시 담아주고
            self.class_hp_dict[i] = self.list_class[i - 1][1]
            self.class_mp_dict[i] = self.list_class[i - 1][2]
        for i in range(1, 6):  #유저가 죽으면 체력회복
            self.class_hp_mp_present_value_list[i - 1][0].setText(
                f'{self.class_hp_dict[i]}/{self.Statusclass[i - 1].get_maxhp()}')  # hp판에 변경된 값 넣어주기
            self.class_hp_mp_present_value_list[i - 1][1].setText(
                f'{self.class_mp_dict[i]}/{self.Statusclass[i - 1].get_maxmp()}')  # mp판에 변경된 값 넣어주기

    def checkCollision(self, obj1, obj2):
        """겹치면 true반환"""
        x1, y1, w1, h1 = abs(obj1.x()), abs(obj1.y()), abs(obj1.width()), abs(obj1.height())
        x2, y2, w2, h2 = abs(obj2.x()), abs(obj2.y()), abs(obj2.width()), abs(obj2.height())
        if x1 < x2 + w2 and x1 + w1 > x2 and y1 < y2 + h2 and y1 + h1 > y2:
            return True
        return False
 def Add_Dungeon_monster_info(self):
        """던전 몬스터들을 나오게 함(일반몬스터와 로직 같음)"""

        self.dungeon_random_monster_hp = {}  # 던전 몬스터 체력 담기
        dungeon_monster_style = []  # 던전 몬스터 스타일 담기

        # 던전 전투 배경 담아주기
        dungeon_background_random = random.randint(1, 5)
        self.back_ground_label.setPixmap(
            QtGui.QPixmap(self.battlefield_background[dungeon_background_random - 1]).scaled(QSize(1580, 830),
                                                                                             aspectRatioMode=Qt.IgnoreAspectRatio))

        if self.user_meet_boss == True: #보스몬스터 나오게 하기

            # 보스몬스터는 무조건 1번에 들어가게 하기
            self.Monster_1_Name.setText(self.dugeonBossbox[self.dungeon_floor - 1].name)  # 보스 이름
            self.Monster_1_QLabel.setPixmap(QPixmap(self.dugeonBossbox[self.dungeon_floor - 1].image))  # 보스몬스터 이미지
            self.Monster_1_QProgressBar.setMaximum(self.dugeonBossbox[self.dungeon_floor - 1].hp)  # 보스몬스터 최대 hp 프로그래스바 1번에 담아주기
            self.Monster_1_QProgressBar.setValue(self.dugeonBossbox[self.dungeon_floor - 1].hp)  # 보스몬스터 현재 hp 프로그래스바 1번에 담아주기
            self.dungeon_random_monster_hp[1] = self.dugeonBossbox[
                self.dungeon_floor - 1].hp  # 보스몬스터와 몬스터들 hp딕셔너리 1번에 보스몬스터 hp 담아주기
            self.Monster_1_Name.show()  # 몬스터들 속성 보여주기 아래는 동일함
            self.Monster_1_QLabel.show()
            self.Monster_1_QButton.show()
            self.Monster_1_QProgressBar.show()

            #보스몬스터와 나오는 랜덤 몬스터 숫자
            dungeon_monster_num = random.randint(0, 6)
            print('보스몬스터와 함게 나오는 던전몬스터 등장 숫자',dungeon_monster_num)
            for i in range(1, dungeon_monster_num+1):
                dungeon_monster_style.append(random.randint(1, 12))

            for num in range(2, dungeon_monster_num + 2):
                monster = self.dugeonfieldbox[dungeon_monster_style[num-2]-1]
                getattr(self, f'Monster_{num}_Name').setText(monster.name)  # MonsterImage 이름
                getattr(self, f'Monster_{num}_QLabel').setPixmap(QPixmap(monster.image))  # MonsterImage 이미지
                getattr(self, f'Monster_{num}_QProgressBar').setMaximum(monster.hp)  # MonsterImage 체력
                self.dungeon_random_monster_hp[num] = monster.hp  # MonsterImage 체력 더하기
                getattr(self, f'Monster_{num}_QProgressBar').setValue(monster.hp)  # MonsterImage 체력
                getattr(self, f'Monster_{num}_QButton').setEnabled(False)
                getattr(self, f'Monster_{num}_Name').show()
                getattr(self, f'Monster_{num}_QLabel').show()
                getattr(self, f'Monster_{num}_QButton').show()
                getattr(self, f'Monster_{num}_QProgressBar').show()

            for num in range(dungeon_monster_num+2, 10 + 1):
                getattr(self, f'Monster_{num}_Name').hide()
                getattr(self, f'Monster_{num}_QLabel').hide()
                getattr(self, f'Monster_{num}_QButton').hide()
                getattr(self, f'Monster_{num}_QProgressBar').hide()

        else:
            dungeon_monster_random_num = random.randint(1, 10) #던전몬스터 숫자
            print('던전몬스터 등장 숫자: ',dungeon_monster_random_num)
            for i in range(1, dungeon_monster_random_num+1): #던전 몬스터 스타일 담기
                dungeon_monster_style.append(random.randint(1, 12))

            for num in range(1, dungeon_monster_random_num + 1):
                monster = self.dugeonfieldbox[dungeon_monster_style[num-1]-1]
                getattr(self, f'Monster_{num}_Name').setText(monster.name)  # MonsterImage 이름
                getattr(self, f'Monster_{num}_QLabel').setPixmap(QPixmap(monster.image))  # MonsterImage 이미지
                getattr(self, f'Monster_{num}_QProgressBar').setMaximum(monster.hp)  # MonsterImage 체력
                self.dungeon_random_monster_hp[num] = monster.hp  # MonsterImage 체력 더하기
                getattr(self, f'Monster_{num}_QProgressBar').setValue(monster.hp)  # MonsterImage 체력
                getattr(self, f'Monster_{num}_QButton').setEnabled(False)
                getattr(self, f'Monster_{num}_Name').show()
                getattr(self, f'Monster_{num}_QLabel').show()
                getattr(self, f'Monster_{num}_QButton').show()
                getattr(self, f'Monster_{num}_QProgressBar').show()

            for num in range(dungeon_monster_random_num+1, 10 + 1):
                getattr(self, f'Monster_{num}_Name').hide()
                getattr(self, f'Monster_{num}_QLabel').hide()
                getattr(self, f'Monster_{num}_QButton').hide()
                getattr(self, f'Monster_{num}_QProgressBar').hide()

        print('던전몬스터스타일', dungeon_monster_style)  # 확인용
        self.portal_hide(True)

    def portal_hide(self, state):
        """던전 입장할 때 없애줄 라벨들(보스몬스터, 포탈, 캐릭터 라벨)"""
        if state == True:
            self.boss_monster.hide()
            self.entrance.hide()
            self.Character_QLabel_2.hide()
        else:
            self.boss_monster.show()
            self.entrance.show()
            self.Character_QLabel_2.show()

getattar를 너무 많이 쓴 것 같다. 코드 로딩시간이 길어진다.

리스트와 딕셔너리를 사용하는 습관을 들이자.

디버깅을 더 했으면 좋았을 텐데 아쉬우면서도

잘 마무리되서 다행이다.

다음 프로젝트를 위해 공부를 더 해야겠다.

 

 

 

 

 

파일 github 링크

https://github.com/guaba98/legend_of_boki/tree/FINAL_GAME_FILE

 

GitHub - guaba98/legend_of_boki: 레전드오브보키(보키스토리)_낭만코더리보키팀

레전드오브보키(보키스토리)_낭만코더리보키팀. Contribute to guaba98/legend_of_boki development by creating an account on GitHub.

github.com

 

 

profile

소연의_개발일지

@ssoyxon

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!