Unity 내일배움캠프 TIL 0829 | 스킬, 치명타, 회피 기능

cheeseonrose·2023년 8월 29일
0

Unity 내일배움캠프

목록 보기
22/89
post-thumbnail

어제 말썽이었던 gitignore 문제는 다행히도 팀장님이 해결해주셨다!!! 와!!!!
팀장님 최고~٩( ᐛ )و

그래서 무난하게 작업 시작~~

팀 프로젝트

스킬 기능

  • 전투 부분 구현이 드디어 머지 되어서 스킬 기능을 추가했다
  • UsePlayerSkill
    • 선택 값을 받아와서 1이면 알파 공격, 2면 더블 공격으로 Player에게 충분한 MP 값이 있는지 확인
    • 마나 공격이 가능한 상태라면 알파 공격은 Info를 다시 한 번 출력해서 플레이어에게 몬스터 번호를 고르도록 함 -> 선택하면 알파 공격 함수 실행
    • 더블 공격은 바로 더블 공격 함수 실행
// 스킬을 사용한 공격
void UsePlayerSkill()
{
	while (true)
    {
    	Console.Clear();
        
        // 공격할 몬스터가 없으면 break;
        if (monsters.All(x => x.IsDead)) break;
        
        string str = "1. 알파 스트라이크 - MP 10\n   공격력 * 2 로 하나의 적을 공격합니다.\n\n" +
        			"2. 더블 스트라이크 - MP 15\n   공격력 * 1.5 로 2명의 적을 랜덤으로 공격합니다.\n\n0. 취소";
        
        InfoScreen(false, str);
        
        int input = Extension.GetInput(0, 2);
        
        if (input == 1)
        {
        	if (player.CurrentMP < (int)Player.MPAttackType.ALPHA)
            {
            	Console.WriteLine("MP가 부족합니다!");
            	Thread.Sleep(1000);
            }
            else
            {
            	Console.Clear();
                InfoScreen(true, "");
                int monsterIdx = Extension.GetInput(1, monsters.Count) - 1;
                if (monsters[monsterIdx].IsDead)
                {
                	Console.WriteLine($"{monsters[monsterIdx].Name} 은(는) 이미 죽었습니다.");
                    Thread.Sleep(1000);
                }
                else AlphaStrikeAttack(monsterIdx);
            }
        }
        else if (input == 2)
        {
        	if (player.CurrentMP < (int)Player.MPAttackType.DOUBLE)
            {
            	Console.WriteLine("MP가 부족합니다!");
                Thread.Sleep(1000);
            }
            else
            {
            	DoubleStrikeAttack();
            }
        }
        else break;
    }
}
  • AlphaStrikeAttack
    • 몬스터의 TakeDamage 함수에 플레이어 공격력 * 2 값을 전달
    • player 객체에게 알파 공격 함수를 실행하도록 요청
    • 결과를 출력한 뒤 리턴
// 스킬 - 알파 스트라이크
private void AlphaStrikeAttack(int monsterIdx)
{
	Console.Clear();
    
    Extension.TypeWriting("Battle!!\n");
    Extension.TypeWriting($"{player.Name}의 알파 스트라이크 공격!");
    Console.WriteLine();
    
    Monster curMonster = (Monster)monsters[monsterIdx];
    int monsterPrevHP = curMonster.CurrentHealth;
    
    curMonster.TakeDamage(player.Attack * 2);  // 공격력 * 2 로 하나의 적 공격
    player.AttackWithMP(Player.MPAttackType.ALPHA);
    
    // 알파 스트라이크 결과 출력
    Console.WriteLine($"Lv.{curMonster.Level} {curMonster.Name}");
    Console.WriteLine($"HP {monsterPrevHP} -> {curMonster.CurrentHealth}\n");
    Console.WriteLine("0.다음");
    
    int input = Extension.GetInput(0, 0);
}
  • DoubleStrikeAttack
    • 살아있는 몬스터 수를 계산 -> 2마리 미만이면 1마리의 몬스터만 공격, 2마리 이상이면 2마리 공격
    • 랜덤한 몬스터 idx 값을 2개 뽑음
    • 공격 당하기 전 몬스터의 체력 값을 저장
    • player 객체에게 더블 공격 함수를 실행하도록 요청
    • 더블 공격 결과에 따른 몬스터들의 체력 변화를 출력하고 리턴
// 스킬 - 더블 스트라이크
private void DoubleStrikeAttack()
{
	Console.Clear();
    
    Extension.TypeWriting("Battle!!\n");
    Extension.TypeWriting($"{player.Name}의 더블 스트라이크 공격!");
    Console.WriteLine();
    
    // 살아있는 몬스터의 수
    int aliveMonster = monsters.Where(m => !m.IsDead).Count();
    
    // 살아있는 몬스터가 2마리 미만이면 1마리만 공격, 2마리 이상이면 2마리 공격
    int num = (aliveMonster < 2) ? 1 : 2;
    List<int> randomIdx = GetRandomIdx(num, 0, monsters.Count);
    
    // 공격 당하기 전 몬스터 체력을 저장해놓을 배열
    List<int> monsterPrevHPList = new List<int>();
    
    foreach (int idx in randomIdx)
    {
    	if (monsters[idx].IsDead) continue;
        monsterPrevHPList.Add(monsters[idx].CurrentHealth); // 공격 당하기 전 몬스터 체력 저장
        monsters[idx].TakeDamage((int)(player.Attack * 1.5));   // 공격력 * 1.5 로 2명의 적을 랜덤 공격
    }
    player.AttackWithMP(Player.MPAttackType.DOUBLE);
    
    Console.WriteLine();
    
    // 더블 스트라이크 결과 출력
    int prevHPidx = 0;
    foreach (int idx in randomIdx)
    {
    	Console.WriteLine($"Lv.{monsters[idx].Level} {monsters[idx].Name}");
        Console.WriteLine($"HP {monsterPrevHPList[prevHPidx++]} -> {monsters[idx].CurrentHealth}\n");
    }
    
    Console.WriteLine("0.다음");
    
    int input = Extension.GetInput(0, 0);
}
  • Player.AttackWithMP
    • 플레이어가 마나를 사용한 스킬 공격을 할 때 공격의 타입(알파/더블)을 받아와서 MP 값 조정
    • 필요한 마나의 양은 enum 클래스에 할당하여 계산
// Player가 스킬을 사용할 때 실행
public void AttackWithMP(MPAttackType type)
{
	if (type == MPAttackType.ALPHA) CurrentMP -= (int)MPAttackType.ALPHA;
    else CurrentMP -= (int)MPAttackType.DOUBLE;
}

public enum MPAttackType
{
	ALPHA = 10,
	DOUBLE = 15
}

치명타, 회피 기능

  • 어제 구현해놨던 IsOccur 함수를 이용해 이벤트가 특정 확률로 발생하는지 확인
  • 치명타 공격 성공시 damage 값을 1.6배 하고 추가 문구 출력
// 10% 의 확률로 플레이어의 공격을 회피
if (IsOccur(10)) monster.Avoid();
else
{
	Console.Write($"Lv.{monster.Level} {monster.Name} 을(를) 맞췄습니다.");
    // 15% 의 확률로 치명타 공격
    if (IsOccur(15))
    {
    	damage = (int)(damage * 1.6);
        Console.WriteLine($" [ 데미지 : {damage} ] - 치명타 공격!!");
    }
    else Console.WriteLine($" [ 데미지 : {damage} ]");
    Console.WriteLine();
    
    monster.TakeDamage(damage);
    Console.WriteLine();
    Console.WriteLine($"Lv.{monster.Level} {monster.Name}");
    Console.WriteLine($"HP {previousHP} -> {monster.CurrentHealth}\n");
}
  • Monster.Avoid
    • 몬스터가 공격을 회피하면 아무 일도 일어나지 않았다는 문구 출력
public void Avoid()
{
	Console.WriteLine($"Lv.{Level} {Name} 을(를) 공격했지만 아무 일도 일어나지 않았습니다.");
}

보상 제공 기능

  • Stage.GiveRewards
    • rewards 리스트의 반을 기준으로 앞쪽에는 consumable한 아이템을, 뒤쪽에는 equipable 아이템이 담겨져 있다.
    • 앞쪽에서 랜덤한 아이템 1개를 뽑고 뒤쪽에서 랜덤한 아이템 1개를 뽑아서 보상으로 제공
    • 해당 아이템은 Player가 들고 있는 Inventory 객체에게 넘겨준다. -> 추가 예정
private void GiveRewards()
{
	// 보상 아이템
    // 소모 가능한 보상 아이템
    int consumableItemIdx = GetRandomIdx(1, 0, rewards.Count / 2)[0];
    IItem consumableItemReward = rewards[consumableItemIdx];
    rewards.Remove(consumableItemReward);
    
    // 착용 가능한 보상 아이템
    int equipableItemIdx = GetRandomIdx(1, rewards.Count / 2, rewards.Count)[0];
    IItem equipableItemReward = rewards[equipableItemIdx];
    rewards.Remove(equipableItemReward);
    
    Console.WriteLine("[ 획득 아이템 ]");
    Console.WriteLine($"{consumableItemReward.Name} - 1");
    Console.WriteLine($"{equipableItemReward.Name} - 1");
    Console.WriteLine();
}
  • GameManager.GetStageRewards
    • 게임 매니저에서는 stage에 따라 적절한 아이템을 리스트에 담아서 Stage 객체에 넘겨준다.
    • 각각 ConsumableItemList와 EquipableItemList에서 스테이지에 해당하는 아이템 객체를 뽑음
    • 예를 들어 ConsumableItemList에서 0~1에는 stage1의 아이템을, 2~3에는 stage2의 아이템을, 4~5에는 stage3 아이템을 담아놓고, stage 값에 따라 아이템 2개를 가져오는 형태
private List<IItem> GetStageRewards(int curStageNum)
{
	// 각 스테이지의 보상 아이템들
    List<IItem> stageRewards = new List<IItem>();
    // 리스트 앞부분 절반에는 소모 가능한 아이템, 뒷부분 절반에는 착용 가능한 아이템을 담음
    for (int i = 0; i < 2; i++) stageRewards.Add(ConsumableItemList[i * curStageNum]);
    for (int i = 0; i < 2; i++) stageRewards.Add(EquipableItemList[i * curStageNum]);
    return stageRewards;
}



TODO

  1. 스테이지 클리어 후 보상 아이템을 Inventory 객체에 반영
    • Player 객체가 Inventory 객체를 갖도록 수정
  2. Player의 더블 스트라이크 공격 로직 수정
  3. 전투 시작 -> 도망가기 로직 추가
  4. 저장하기 기능 시도해보기



오늘은 여기까지!!! 스우파 봐야 되니까 일찍 퇴근 히히
끗~.~

0개의 댓글