개발/하스스톤+전장

하스+전장) #2

kimchangmin02 2025. 12. 30. 17:44

적 핸드/동전/턴/마나수정 추가함 

 


덱은 잇지만 랜덤하려면, 랜덤 함수이요하면도니깐

[  ]스스로 덱짜게 하려면 어케 해야할지 

 

 

상대방 손패도 만들려면, 

카드 뒷면 <일단 로그로는 찍히도록 

 

 

3)손패도 안움직이도록

4)동전은 항상 처음 손패의 젤 오른쪽에 

 

6)주문은 드래그 해서 내면 발동하도록 ?[  ]발동조건이 뭐지

[  ]덱도없는데 어떻게 카드를 생성하고잇는거지 

initial()함수에서 

 

 


1)랜덤으로 누가 먼저인지 정해지도록, 

2)후턴은 동전 손에 추가

 

5) 주문 프리팹

=<동전주문 발동함 

 

 

 

 

 


 

1. 왜 저렇게 공간(영역)을 나누었나요?

지금까지 PlayerHand, PlayerField 등을 나눈 이유는 "자동 정렬(Layout Group)" 때문입니다.

  • 카드는 여러 장이 들어오기 때문에, 이 카드들을 한 줄로 예쁘게 세워주는 **바구니(Container)**가 필요했던 것입니다.
  • 바구니(Horizontal Layout Group)에 카드를 던져넣기만 하면 알아서 줄을 서니까요.

2. 마나 표시도 공간을 따로 나눠야 하나요?

아니요, 마나는 카트처럼 여러 개가 줄을 서서 움직이는 물체가 아니므로 "공간"을 나눌 필요가 없습니다.

마나는 화면상의 특정 위치에 고정된 정보일 뿐입니다. 따라서 다음 두 가지만 있으면 충분합니다.

  1. 배경 이미지: 마나 숫자가 잘 보이게 해주는 판때기.
  2. 텍스트(TMP): 현재 마나 / 최대 마나를 보여주는 숫자.

3. 마나 UI, 어떻게 만들면 될까요? (추천 방식)

공간을 또 쪼개지 마시고, 그냥 Canvas의 자식으로 마나용 오브젝트 하나만 만드세요.

  1. Hierarchy: Canvas 우클릭 -> Create Empty (이름: ManaContainer)
  2. 위치: 이 녀석을 마우스로 잡아서 '내 턴 종료 버튼' 근처'손패(분홍색)' 오른쪽 구석에 둡니다.
  3. 자식 추가:
    • ManaContainer 우클릭 -> UI > Image: (마나 수정 배경이나 바 이미지)
    • ManaContainer 우클릭 -> UI > Text - TextMeshPro: (이름: ManaText, 내용: "1 / 1")
  4. 상대방 마나: 똑같이 복사해서 상대방 영역 근처에 하나 더 두면 됩니다.

4. 마나 시스템 구현을 위한 "논리적" 준비 (코드 전 단계)

마나를 구현하려면 이제 **TurnManager.cs**가 버튼만 바꾸는 게 아니라, 실제 **'돈'**을 관리하는 은행원이 되어야 합니다.

앞으로 일어날 일 (이론):

  1. 게임 시작: 플레이어 최대 마나 = 1, 현재 마나 = 1.
  2. 카드 플레이 시:
    • 카드를 드롭하면 CardDatacost를 확인합니다.
    • 현재 마나가 충분하면 통과! 현재 마나 = 현재 마나 - 카드 코스트.
    • 부족하면? 카드를 다시 손패로 튕겨냅니다.
  3. 턴 종료 후 다시 내 턴이 올 때:
    • 최대 마나를 +1 합니다 (최대 10).
    • 현재 마나를 최대 마나만큼 다시 꽉 채웁니다.

 

 

 

 

 

 

 

 

 

 

가려짐, 

마나 이미지가 

 

해결 방법: 드래그해서 순서 바꾸기

  1. Hierarchy 창을 보세요.
  2. 아까 만드신 ManaContainer(또는 마나 관련 오브젝트)를 마우스로 꾹 잡습니다.
  3. 그것을 PlayerField EnemyField보다 더 아래쪽으로 끌어다 놓으세요. (Canvas 목록의 맨 아래쪽이 명당입니다.)

Hierarchy의 이상적인 순서:

  • Canvas
    • EnemyField (상대 필드)
    • PlayerField (내 필드)
    • PlayerHand (내 손패)
    • EndTurnButton (턴 종료 버튼)
    • ManaContainer (마나 UI - 가장 아래에 두면 무조건 맨 앞에 보임)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

유니티에서 연결하기

  1. TurnManager 오브젝트 클릭:
    • 인스펙터 창의 Player Mana Text 칸에, Hierarchy에 만드신 **PlayerManaContainer 안의 Text(TMP)**를 드래그해서 넣으세요.
    • Max Mana 1, Current Mana 1로 설정하세요.
  2. CardDraggable (프리팹) 확인:
    • 코드만 수정하면 자동으로 적용됩니다.
  3. Hierarchy 이름 확인:
    • CardDraggable 코드에서 GameObject.Find("PlayerHand")를 사용하므로, 손패 영역의 이름이 정확히 **PlayerHand**여야 합니다. (다르면 코드를 수정하거나 이름을 맞추세요.)

4. 실행(Play) 시 테스트 로그 확인

  1. 시작: 마나 UI가 1 / 1로 바뀌어야 합니다.
  2. 플레이 시도 (코스트 4 카드): 1마나인데 4코스트 카드를 내보세요.
    • 로그: [Mana] 마나가 부족합니다! (필요:4 / 현재:1)
    • 카드가 필드에 안 붙고 다시 손으로 튕겨 돌아와야 합니다.
  3. 턴 종료 -> 다시 내 턴: 턴 종료 버튼을 두 번 눌러서 내 턴으로 만드세요.
    • 로그: [Turn] 내 턴 시작! 마나 충전: 2/2
    • UI가 2 / 2로 바뀝니다.
  4. 플레이 성공: 1코스트 하수인을 내보세요.
    • 로그: [Mana] ... 플레이! 마나 1 소모.
    • UI가 1 / 2로 바뀝니다.

이렇게 하면 "돈 없으면 하수인을 못 내는" 하스스톤의 기본 경제 시스템

 

 

 

 

 

[  ]

마나 부족한데 카드 내지는 현상 


로그를 보면 
parentToReturnTo = placeholderParent; 

🚩 원인 분석

  1. 마우스가 필드 위에 있을 때 카드를 놓으면, DropZone에 의해 placeholderParent는 이미 **'PlayerField'**가 되어 있습니다.
  2. 마나가 부족해서 실패했을 때 코드가 "원래 부모로 돌아가!"라며 placeholderParent를 대입하는데, 이때 이미 그 값이 'PlayerField'이기 때문에 결국 필드에 남게 되는 것입니다.
  3. 또한 RectTransform 관련 경고는 GameObject 생성 시의 순서 때문에 발생합니다.

이를 해결하려면 드래그를 시작할 때의 진짜 손패(Hand) 위치를 따로 저장해두었다가, 실패 시 그곳으로 보내야 합니다.

 

 

 

 

 

 

하수인과 주문의 로직이 다르기 때문에 **"코드 내에서 if(타입 == 주문)으로 분기 처리"**를 하는 것입니다. 프리팹을 하나로 쓰는 이유는 유니티의 Horizontal Layout Group(손패 정렬) 시스템에서 같은 규격의 오브젝트를 다루는 것이 레이아웃이 깨지지 않고 관리하기 편하기 때문입니다. (물론 나중에 디자인이 완전히 달라지면 프리팹을 분리해도 됩니다.)

가장 중요한 **"주문의 각기 다른 효과"**를 처리하는 방법은 **[카드 고유 ID]**를 활용하여 SpellManager라는 전용 클래스에서 관리하는 것이 가장 깔끔합니다.

 

 

 

 

 

 

 

 

 

 

 


효과를 가진 주문과 하수인 만들기 

 

 

  • Card (레시피/봉투): "동전 한 잎"이라는 카드 그 자체입니다. 이름은 뭐고, 마나는 얼마고, 어떤 효과들을 가지고 있는지 정보를 담는 '틀'입니다.
  • Effects (재료/내용물): "마나를 1 늘린다"라는 구체적인 기능입니다.

(스크립트를 카드와 연결시키는방법 )

 

 

 


효과를 위한 새로운 폴더 

 

 

폴더가 다르면 이름이 같아도 유니티 시스템상 문제는 없습니다.
예를 들어 Cards/동전.asset Effects/동전.asset이 공존할 수 있습니다.

하지만 실제 작업할 때는 이름을 다르게 하는 것이 훨씬 좋습니다. 그 이유는 다음과 같습니다.

  • 검색 편의성: 유니티 상단 검색창에서 "동전"을 검색했을 때, 어느 게 카드고 어느 게 효과인지 아이콘만 보고 구분해야 해서 헷갈릴 수 있습니다.
  • 인스펙터 연결: 카드 데이터에서 효과를 연결하려고 선택창을 띄웠을 때 똑같은 이름이 두 개 나오면 실수할 확률이 높습니다.

 

 

 

 

 

 

 

 

재 카드 생성 구조를 핵심 단계별로 설명해 드리겠습니다.

  1. 데이터 준비: 프로젝트 창에 파일(ScriptableObject) 형태로 저장된 카드 정보들이 있습니다. 이 정보들을 HandManager 스크립트의 Deck 리스트에 직접 드래그해서 담아두었습니다.
  2. 생성 명령: 게임이 시작되면 GameManager가 선공/후공 결과에 따라 "카드를 몇 장 생성해라"라고 HandManager에게 숫자를 넘겨주며 명령을 내립니다.
  3. 복제(Instantiate): 명령을 받은 HandManager는 리스트의 0번부터 순서대로 데이터를 꺼냅니다. 그리고 미리 등록해둔 **카드 프리팹(Card_Template)**을 그 데이터 개수만큼 복제하여 화면에 만듭니다.
  4. 부모 설정: 복제된 카드들은 하이어라키(Hierarchy) 창에서 PlayerHand 오브젝트의 자식으로 들어갑니다. PlayerHand에는 카드를 가로로 정렬해주는 컴포넌트(Horizontal Layout Group)가 붙어 있어 자동으로 나란히 배치됩니다.
  5. 내용 채우기: 생성된 각 프리팹은 내부에 있는 CardDisplay 스크립트를 통해, 리스트에서 전달받은 데이터(이름, 비용, 공격력, 이미지 등)를 텍스트와 이미지 컴포넌트에 실시간으로 입혀서 우리 눈에 보이게 합니다.
  6. 특수 생성(동전): 후공일 경우, GameManager가 리스트에 없는 별도의 동전 카드 데이터를 직접 지목하여 HandManager에게 "이거 하나 더 만들어"라고 명령하여 손패 끝에 추가합니다.

결국 [데이터 리스트] -> [프리팹 복제] -> [부모 위치에 배치] -> [데이터 입히기] 순서로 작동하고 있는 것입니다.

 

 

랜덤이 아니고 여기서 가져온다네 

 

 

 

 

 

상대방(적)도 손패를 가지려면 EnemyHandManager를 만들어야 하나요?

네, 맞습니다! 똑같은 관리자가 한 명 더 필요합니다.

  • 역할 분담: 플레이어 쪽 관리자(PlayerHandManager)는 화면 아래쪽 내 손패 자리에 카드를 만들고 관리합니다. 마찬가지로 적 쪽 관리자(EnemyHandManager)는 화면 위쪽 적 손패 자리에 카드를 만들어야 합니다.
  • 차이점 처리: 나중에 적의 카드는 우리에게 뒷면만 보이게 하거나, 적이 카드를 낼 때는 내가 드래그하는 방식과는 다른 로직이 필요하기 때문에 별도의 관리자로 나누는 것이 가장 깔끔하고 나중에 수정하기 쉽습니다.
  • 구조적 이점: 플레이어에게 썼던 HandManager 스크립트를 그대로 복사해서 적 오브젝트에 붙인 뒤, "카드가 생성될 부모 위치"만 EnemyHand로 바꿔주기만 해도 기본적인 기능은 똑같이 작동하게 됩니다.

 

 

 

적의 카드 뒷면 

프리팹 새로만들지말고 

Card_Template 프리팹 내부에 뒷면 이미지를 하나 추가하고, 코드로 그것을 끄고 켜는 방식입니다

 

 

 

 

  1. 프리팹(Card_Template) 상태에서는 어떤 카드가 될지 모르기 때문에 None으로 비워두는 것이 맞습니다.
  2. 게임을 실행하면, 매니저가 덱에서 "게으른 투사"나 "동전" 데이터를 가져와서 실시간으로 저 빈칸에 배달해 줍니다.

 

 

 

 

🛠 유니티 작업 마무리 가이드

  1. 프리팹 수정:
    • Card_Template 프리팹을 엽니다.
    • 자식으로 Image를 하나 만들고 이름을 **CardBack**으로 짓습니다.
    • 카드 전체를 덮도록 크기를 맞추고 뒷면 이미지를 넣습니다. (기본적으로 꺼두지 않아도 코드가 제어합니다.)
    • CardDisplay 컴포넌트의 Card Back Object 칸에 이 CardBack 이미지를 드래그해서 연결합니다.
  2. EnemyHandManager 설정:
    • Hierarchy의 EnemyHand 오브젝트에 EnemyHandManager 스크립트를 붙입니다.
    • Card Prefab 칸에 Card_Template을 넣고, Hand Parent 칸에 자기 자신을 넣습니다.
    • Deck 리스트에 테스트용 카드들을 채웁니다.
  3. GameManager 연결:
    • GameManager 인스펙터에 새로 생긴 Enemy Hand Manager 슬롯에 EnemyHand 오브젝트를 드래그해서 연결합니다.

이제 실행하면 적의 손패는 뒷면으로 보이고, 내 손패는 앞면으로 보이며, 콘솔창에는 적이 가진 카드가 무엇인지 빨간색 로그로 뜰 것입니다! 드래그 방지 로직 덕분에 적의 카드를 건드릴 수도 없습니다.

 

 

 

 

[  ]적의 카드가 잘려서 보이는 문제 

이거 피봇 다르게 해야하나, 다른 프리팹으로 해야하나 

 

1) 플레이어 관리자(HandManager)에서 뒷면을 끄라는 명령이 없었고,

2) 적의 손패 영역에 정렬 컴포넌트(Horizontal Layout Group)가 없어서 카드가 겹쳐 보이기 때문입니다.