본문 바로가기

유니티 스파르타 캠프 3주차

25-04-23 팀프로젝트 3일차

🔴 오늘의 내용  .

  1. 튜터 님의 강의(클래스와 객체)  .
  2. 기획한 내용 기반으로 내가 작성한 코드  .
  3. 후기 및 내일 일정  .

1. 튜터 님의 강의(클래스와 객체)

  • 절차지향 vs 객체지향
  • 상속

1)-1. 절차지향 vs 객체지향

 

절차지향 객체지향

개념

프로그램을 기능 단위(함수 중심)로 나누어 순서대로 실행하는 방식 데이터를 중심으로 그 데이터와 관련된 기능을 묶어서 객체 단위로 처리하는 방식

예시

절차지향: main()에서 순차적으로 기능 호출 (C)
객체지향: Car 객체를 만들고, Drive() 메서드를 호출 (C#, Java 등)

목적

간단하고 빠른 개발 (초기 개발에 유리) 재사용성, 확장성, 유지보수에 유리

1)-2. 상속 (Inheritance)

부모 클래스의 속성과 기능을 자식 클래스가 물려받는다.

  • 코드 재사용성
  • 공통 기능은 상위 클래스에, 구체 기능은 하위 클래스에

 

2. 기획한 내용 기반으로 내가 작성한 코드

  • GameLogic(SceneStart)
  • JobSelect
  • SceneStatus 
  • SceneRest
  • Quest
  • Skill

 

클래스 명을 적어보니 생각보다 많이 한 느낌이 없어서 약간 허무한 느낌이 있다. 하지만 팀 프로젝트였기에 개인으로 할 때와는 확연히 시간을 쓰는 부위가 많다는 것을 느꼈다. 

GameLogic(SceneStart) 중 일부

SceneStatus sceneStatus = new SceneStatus();
SceneBattle sceneBattle = new SceneBattle();
private SceneShop sceneShop = new SceneShop();
private SceneInventory sceneInventory = new SceneInventory();
private Inventory inventory = new Inventory();
List<Skill> skills = new List<Skill>();

switch (result)
{
    case 1:
        sceneStatus.Start(player);
        break;
    case 2:
        sceneBattle.StartBattle(player);
        break;
    case 3:
        sceneInventory.Start(inventory);
        break;
    case 4:
        sceneShop.Start(player, inventory);
        break;
    case 5:
        sceneRest.Start(player);
        break;
}

위와 같이 코드에서 맵(어떤 구성)을 하나씩 다 연결하여 이동하는 것을 구현했습니다. 모두가 Start, Input 메소드를 쓰기로 하여 스크립트명.Start를 활용하면 그 창을 열 수 있어서 편리합니다. 

JobSelect 중

sb.AppendFormat($"{(i + 1)}. 직업: {job[i].name}" + ("체력 :").PadLeft(8) + $"{job[i].hp, -4} 공격력 : {job[i].atk, -4} 방어력 : {job[i].def, -4} ").Append("\n");

직업 선택에서 PadLeft, PadRight 등에 Padding을 활용하여 문자열을 정리하는 코드를 사용했습니다.

 

SceneStatus 

public void Start(Player player)
{
	Console.Clear();
	Console.ForegroundColor = ConsoleColor.Green;
	Console.WriteLine("상태 보기");
	Console.ResetColor();
	sb.Append("캐릭터의 정보가 표시됩니다").Append("\n");
	sb.AppendLine("");
	sb.Append($"이  름	:{player.name}").Append("\n");
	sb.Append($"Lv.	: {player.level}").Append("\n");
	sb.Append($"직업	: {player.job}").Append("\n");
	sb.Append($"체  력	: {player.hp}").Append("\n"); 
	sb.Append($"공격력	: {player.atk}").Append("\n"); 
	sb.Append($"방어력	: {player.def}").Append("\n"); 
	sb.Append($"돈	: {player.gold}").Append("\n");
	sb.Append("\n");
	sb.Append("0. 나가기").Append("\n\n");
	sb.Append("원하시는 행동을 입력해주세요.").Append("\n");
	sb.Append(">> ");
	Console.Write(sb.ToString());
	sb.Clear();

	Input();
}

public void Input()
{
	while (true)
	{
		try
		{
			int input = int.Parse(Console.ReadLine());
			switch (input)
			{
				case 0:
					return;
				default:
					Console.WriteLine("다시 입력해주십시오");
					continue;
			}
		}
		catch (Exception)
		{
			Console.WriteLine("다시 입력해주십시오");
			continue;
		}
		
	}
}

플레이어의 능력치가 보이는 스크립트는 재사용성이 높아서 함수로 정의할 예정이지만, 가장 먼저 제작한 코드였고 재사용을 위해서는 다른 스크립트에 있는 것이 나아 현재는 그냥 코드에 넣어놨습니다. ShowStatus로 뺀다면 편한 코드가 될 듯합니다.

SceneRest 중 일부

Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("당신은 치유의 요람에서 즐겁게 놀았습니다.");
Thread.Sleep(500);
Console.WriteLine("...");
Thread.Sleep(500);
Console.ResetColor();
Console.WriteLine();
Console.WriteLine("요람의 신비한 힘이 당신을 회복시켰습니다.");
player.hp += (int)(player.hp * 0.3f);
player.gold -= 30;
Thread.Sleep(500);
Console.WriteLine();
Console.WriteLine($"현재 체력 : {player.hp} / 현재 골드 : {player.gold}");
Console.ReadLine();

SceneRest의 경우, 스테이터스와 같지만 휴식하고 그 내용에 대해 출력하는 것에 Thread.Sleep을 넣어 애니메이션의 느낌을 주었습니다. 단조롭게 바로 결과가 뜨는 것보다 훨씬 "진행된다"는 느낌이 강해 좋았습니다.

Quest 중 일부

public void PlayEvent(Quest quest, string name)
{
	switch (quest.eventType)
	{
		case EventType.EquipItem:
			EventEquipItem(quest, name);
			break;

	}
}

public void PlayEvent(Quest quest, int value)
{
	switch (quest.eventType)
	{
		case EventType.HitDamage:
			EventHit(quest, value);
			break;

		case EventType.UseGold:
			EventUseGold(quest, value);
			break;

	}
}

public void PlayEvent(Quest quest, int value, string name)
{
	switch (quest.eventType)
	{
		case EventType.KillOther:
			EventKill(quest, value, name);
			break;
	}
}

public void EventHit(Quest quest, int damage)
{
	curProgress += damage;
}

public void EventKill(Quest quest, int kill, string name)
{
	if (quest.pickName == null)
	{
		quest.curProgress += kill;
	}
	if (name.Contains(quest.pickName))
	{
		quest.curProgress += kill;
	}
}

public void EventUseGold(Quest quest, int gold)
{
	curProgress = gold;
}

public void EventEquipItem(Quest quest, string name)
{
	if (quest.pickName == null)
	{
		quest.curProgress++;
	}
	if (name.Contains(quest.pickName))
	{
		quest.curProgress++;
	}
}

Quest와 같은 경우는 처음으로 다뤄보았고 또 어떻게 해야할지 감을 잡기 어려웠습니다. 그래서 비효율적인 방법이긴 하지만 이벤트의 종류를 enum값으로 넣어 switch문을 활용하였고 그 활용을 상세하고 필요한 값을 나누기 위해 오버라이딩을 활용했습니다.

Skill 중 일부

enum DamageType
{
	Hp = 1,
	Def = 2,
	Atk = 4,
	Mp = 8
}

enum ValueType
{
	Mp = 1,
	Gold = 2,
	Hp = 4
}

public int UseSkillDamage(Player player, Skill skill)
{
	int type = skill.damageType;
	int damage = 0;
	if (type >= (int)DamageType.Mp)
	{
		damage += (int)(skill.damage[0] * 0.01f * player.mp);
		type -= (int)DamageType.Mp;
	}

	if (type >= (int)DamageType.Atk)
	{
		damage += (int)(skill.damage[1] * 0.01f * player.atk);
		type -= (int)DamageType.Atk;
	}

	if (type >= (int)DamageType.Def)
	{
		damage += (int)(skill.damage[2] * 0.01f * player.def);
		type -= (int)DamageType.Def;
	}

	if (type >= (int)DamageType.Hp)
	{
		damage += (int)(skill.damage[3] * 0.01f * player.hp);
		type -= (int)DamageType.Hp;
	}

	return damage;
}

public string UseSkillValue(Player player, Skill skill)
{
	string typeName = "";
	int type = skill.valueType;
	if (type >= (int)ValueType.Mp)
	{
		player.mp -= skill.value;
		type -= (int)ValueType.Mp;
		typeName += "마나";
	}

	if (type >= (int)ValueType.Gold)
	{
		player.gold -= (int)skill.value;
		type -= (int)ValueType.Gold;
		typeName += "골드";
	}

	if (type >= (int)ValueType.Hp)
	{
		player.hp -= (int)skill.value;
		type -= (int)ValueType.Hp;
		typeName += "체력";
	}
	return typeName;
}

위에 코드는 1/2 + 1/2 + 1/2 ... 는 1이 될 수 없다는 제논의 역설에 근거하여 데미지와 스킬의 사용값이 여러 개일 경우, 그 값을 처리하기 위해 작성한 코드입니다. 더 효율적인 방법이 있는지는 현재로썬 알 수 없지만 문제는 없기에 이대로 작성했습니다.

 

3. 후기 및 내일 일정

오늘 코드 프로토타입 마무리를 하려 했으나, 생각보다도 합치는 과정에서 시간이 걸렸다. 내일까지도 프로토타입 코드를 작성할 거 같고, 내일도 마무리가 되지 않는다면 시간이 없어서 프로토타입 완성하고 PPT를 작성하는 것도 각오해야 될 거 같다.

내일은 코드도 열심히 작성해야하지만, 시험도 있는 날이다. 솔직히 시험 문제를 조금 공부해봐야되나 싶지만, 그것보다도 당장하고 있는 프로젝트를 좀 더 완벽하게 꾸미는데에 초점을 두는 것이 맞을 것으로 보인다.