Unity_본캠프

[내일배움캠프 13일차] TextRPG-이번에는 팀플이다! 3

전기연(Unity_9기) 2025. 4. 23. 21:18

 

1. 오늘의 할 일

1. 레벨업 제작하기
2. 공격력 메서드를 각 캐릭터 스탯에 맞춰서 사용하도록 만들기
3. 스킬 적용하기

 

2. 작업 개시🛠️

1. 레벨업

여기서 사용할 레벨업은 사실 별로 안 어렵다. log함수 쓸 것도 아니니까!

10>35>65>100...순으로 올라가니, 경험치가 올라가는 규칙성을 찾는 게 어려울 뿐이다.

그리고 오랜만에 연립방정식을 풀었을 뿐....

 

 public void LevelUP()
 {
     if(EXP >= MaxEXP)
     {
         while (EXP >= MaxEXP)
         {
             EXP -= (int)MaxEXP; // 남은 경험치
             Level++;
             MaxHealth += 10; // 레벨업 시 체력 증가
             Attack += 0.5; // 레벨업 시 공격력 증가
             Defense += 1; // 레벨업 시 방어력 증가
             MaxMP += 5; // 레벨업 시 마나 증가
             MaxEXP = 2.5 * Level * Level + 17.5 + Level - 10; //MaxEXP 갱신
             //레벨업 시 클래스이름-랭크 증가(직급 상승)
             ClassName = Enum.GetName(typeof(Ranks), Level);
             Console.WriteLine($"{Name}이(가) {ClassName}(으)로 승진했습니다! 현재 레벨: {Level}");
         }
     }
 }

 

정상적으로 작동하는지는 Battle 메서드와 연결 후 확인해보아야 한다.

하지만 기본적으로는 잘 작동할 것이다. (만약 오류가 생긴다면, ( ) 안에 Character character를 집어 넣고 주르륵 수정하면 될 것이다.)

 

2. 공격-스탯에 따른 메서드 수정

바로 이전에 만든 공격 메서드는 가장 기본적인 가이드를 따른 공격방식이다.

하지만 바로 어제, 명중률, 회피율, 크리티컬 확률과 크리티컬 대미지(배수) 까지 구성했다.

DamageMargin (즉, 오차범위) 계산식에 오류가 있어 해당 부분도 수정해주었다.

 

 public static void AttackMethod(Character character, Monster monster)
 {
     //공격력이 11일때 나머지가 있으므로 오차범위 +1됨.
     int DamageMargin;
     //나누기 후 소수점(나머지)가 있을 경우 올림처리
     if ((int)character.Attack% 10 != 0)
     {
         DamageMargin = (int)character.Attack / 10 + 1;
     }
     else //없으면 그대로 오차범위 확정
     {
         DamageMargin = (int)character.Attack / 10;
     }

         //공격 시 대미지 범위 설정 (11일 경우 10-2부터 10+2까지) 중 랜덤으로 들어감
     int damage = new Random().Next((int)character.Attack - DamageMargin, (int)character.Attack + DamageMargin + 1);

     //공격 시 일정 확률로 크리티컬 혹은 miss 발생
     //크리티컬 공격
     Random probability = new Random();
     int Accuracy = probability.Next(1, 101); // 명중률에 따라 일반공격 적용
     int critical = probability.Next(1, 101); // 15% 확률로 크리티컬 공격 발생

     //최종 명중률 = 공격자 명중률 - 상대방 회피율

     //monster Attack을 이후 EVA 데이터가 만들어지면 교체할 것.
    
     if (Accuracy <= character.DEX - monster.Attack)
     {
         if(critical <= character.CRIT)
         {
             //크리티컬 공격
             //크리티컬 공격력 = 최종대미지*치명타 대미지 배수
             int critDamage = (int)(damage * character.CRITDMG);
             Console.WriteLine($"{character.Name}의 크리티컬 공격!");
             Console.WriteLine($"Lv.{monster.Level} {monster.Name}에게 {critDamage}의 피해를 입혔습니다.");

             //타겟 체력 감소- Monster 클래스의 Health를 사용
             monster.Health -= critDamage; // 몬스터의 체력 감소
         }
         else
         {
             //일반 공격
             Console.WriteLine($"{character.Name}의 공격!");
             Console.WriteLine($"Lv.{monster.Level} {monster.Name}에게 {damage}의 피해를 입혔습니다.");
             //타겟 체력 감소- Monster 클래스의 Health를 사용
             monster.Health -= damage; // 몬스터의 체력 감소
         }
     }
     else
     {
         //miss
         Console.WriteLine($"{character.Name}의 공격!");
         Console.WriteLine($"Lv.{monster.Level} {monster.Name}을(를) 공격했지만 아무일도 일어나지 않았습니다.");
     }


 }

 

먼저 DamageMargin으로 캐릭터 대미지의 오차범위를 정한다. (10이면 1, 11부터 20까지는 2)

캐릭터의 공격력의 10%인데, 소수점이 있을 경우 올림처리를 하므로,

(공격력)/10의 나머지가 0이라면 해당 값이 그대로 출력, 나머지가 남으면 0.n의 소수가 나오므로 올림처리(몫+1)

그리고 대미지는 공격력과 해당 오차범위 사이에서 결정되도록 만든다.

 

일반 공격 성공확률은 (명중률)-(상대방의 회피율)이며, 일반 공격이 성공했을 경우, 크리티컬 확률도 범위 내에 들어가면 치명타, 일그렇지 않으면 일반 공격이 수행된다.

일반 공격이 실패할 경우, 당연히 공격 실패 처리가 된다.

 

3. 스킬 적용하기

매번 공격만 하면 아쉬우니까, '스킬'을 구현해볼 것이다.

각 직업별로 스킬이 3개씩 있는데, 이 능력이 전부 달라서 기능을 어떻게 적용할 것인지 고민해봐야한다.

고민 결과: 나의 창의력으론 답이 없다. 튜터님께 다녀왔다.

해답: 추상클래스가 좋을 것 같아요

 

안그래도 이거 진짜 어떻게 쓰는 거예요 설명은 알겠는데 실 사용은 어케하는 건지 오늘 강의 들었는데도 감이 안왔는데.

이렇게 기회가 오다니.

 

 OK. 가보자고.

 

공통될 부분들을 넣기 시작했다.

지금 쓰다가 이게 맞나 싶은데

전부 re 0부터 쓰는 것보다는 나은 것 같긴 하다...

일단 만들고 리스트화를 생각해보기로 함.

 

사실 그러고도 밑에..abstract가 아닌 함수가 이만큼이나 들어가있다.

사유 : 스킬이 너무 너무 많다

더보기

//스킬의 쿨타임 감소
public void ReduceCooldown()
{
    if (cooldown > 0)
    {
        cooldown--;
    }
    if (effectDuration > 0)
    {
        effectDuration--;
    }
}

//부가효과 활성화 여부
public void isEffective(Character character)
{
    Console.WriteLine($"{skillName} 효과가 적용 중입니다.");
    return;
}

//효과 종료
public void EffectRemove(Character character)
{
    Console.WriteLine($"{skillName} 효과가 종료되었습니다.");
    isEffectActive = false; // 효과 비활성화
}

//쿨타임 중
public void coolTime()
{
    Console.WriteLine($"{skillName}은(는) 쿨타임 중입니다. 남은 쿨타임: {cooldown}턴");
}

//기본 스킬사용 로직
public void SkillUse(Character character, Monster monster)
{
    Console.WriteLine($"{character.Name}이(가) {monster.Name}에게 {skillName}을(를) 사용!");
    Console.WriteLine($"{character.Name}: {skillDescription}");
    character.MP -= costMP;
}

//스킬 사용 가능 확인 - 전투: 스킬사용에서 우선 검사하도록 함
public bool CanUseSkill(Character character, int costMP, int cooldown)
{
    if (cooldown > 0)
    {
        coolTime();
        return false;
    }

    if (character.MP < costMP)
    {
        Console.WriteLine("MP가 부족합니다.");
        return false;
    }
    return true;
}

왜 저만큼이나 필요한가요
A: 진짜 저걸 다 n회 반복해서 쓰고 싶지 않았어요

 

그래도 저렇게 해서 좋은 점이 있다.

실제로 사용하는 UseSkill 함수 내에는 저렇게 두줄이랑 쿨타임만 넣으면 된다.

와! 이래서 추상클래스 쓰는 구나!

 

3. 내일 할 일

일단 스킬을 해결한다

스킬을 해결한다

스킬.

정확히 말해주세요

: 1. 일단 스킬을 전부 빌딩한다. \n 2. 스킬cs와 캐릭터cs를 연결한다.(직업별 스킬이 캐릭터에게 뜨도록) \n 3. 스킬cs와 전투cs를 연결한다. (실제 전투에서 사용되고, 쿨타임이 적용되도록.)

 

if(시간 에바)

{

    Console.WriteLine("모든 스킬 대상을 단일로 변경하고 쿨타임을 제거한다.");

}