티스토리 뷰
오늘 한 작업
- 스킬 및 공격 모듈화
- ScriptableObject와 상속을 이용한 공격 요소의 모듈화
- 추가로 공격 변형 요소들을 체계화 및 수치화 시켜 간단하게 조정할 수 있도록 구성
- 스킬 사용 구문을 통합하여 추후 수정에도 용이하도록 변경
- 코루틴을 활용한 공격 요소의 방식 확장
- ScriptableObject와 상속을 이용한 공격 요소의 모듈화
※ 몬스터 관련 요소는 추후 몬스터 관련 몇 가지 수정사항을 수정하면서 함께 작업할 예정입니다.
※ 추후 공격 오브젝트 간의 상호작용을 추가할 예정입니다. 이에 대한 사전 작업 요소가 포함되어 있을 수 있습니다.
※ 라이프바 및 데미지 폰트는 아직 미작업 상태입니다.
결과물(영상)
※ 보스의 투사체 공격의 사거리가 심히 짧은 건 함수를 수정하면서 시간이 거리로 바뀐 것을 적용하지 않아서 그렇습니다.
코드(일부)
Active 부모 클래스
public class Active_Base : ScriptableObject
{
public GameObject Atk_Obj;
public int[] Damage = new int[5]; // 스킬의 기본 공격력.
public float Size;
public float Velocity;
public float Point_Time; // -1: 기본 공격
public int Point_Amount; // -1: 기본 공격
public bool is_On;
public int Max_Count;
public float Count_Term;
public float Rotate_Count;
public float Distance;
public float Angle_Term;
public int Branch; // 공격 개수. 정확히는 '원점(ex. 캐릭터) 기준으로 360도를 n등분하여 형성되는 공격의 개수'다.
public int Way; // 공격 개수. 정확히는 '부채꼴로 발사되는 공격의 갯수'다.
public int Refeat; // 공격 개수. 정확히는 '일렬로 순차 발사되는 공격의 갯수'다.
public int Line; // 공격 개수. 정확히는 '일렬로 나열되는 공격의 갯수'이다. 투사체는 속도 변화로 제작된다.
public virtual void Create_Obj(Vector3 _Position, float _rotation, bool _Friendly, float _Atk_Mul)
{
}
}
투사체 Active
[CreateAssetMenu(menuName = "Scriptables/Act/Projectile")]
public class Act_Proj : Active_Base
{
public float Dist_Max;
public int Pierce;
public List<int> Fork_List;
public override void Create_Obj(Vector3 _Position, float _rotation, bool _Friendly, float _Atk_Mul)
{
GameObject temp = Instantiate(Atk_Obj, _Position + (Quaternion.Euler(0.0f, 0.0f, _rotation) * Vector3.right * Distance), Quaternion.identity);
temp.SetActive(false);
Projectile temp_Script = temp.GetComponent<Projectile>();
temp_Script.is_friendly = _Friendly;
temp_Script.rotate = _rotation;
temp_Script.Size = new Vector3(Size, Size, 1.0f);
for (int i = 0; i < Damage.Length; i++)
temp_Script.Damage[i] = (int)((float)Damage[i] * _Atk_Mul);
temp_Script.velocity = Velocity;
temp_Script.Dist_Max = Dist_Max;
temp_Script.Fork = Fork_List.ToList();
temp_Script.Pierce_Max = Pierce;
temp.SetActive(true);
}
}
파동 Active
[CreateAssetMenu(menuName = "Scriptables/Act/Pulse")]
public class Act_Pulse : Active_Base
{
public override void Create_Obj(Vector3 _Position, float _rotation, bool _Friendly, float _Atk_Mul)
{
GameObject temp = Instantiate(Atk_Obj, _Position + (Quaternion.Euler(0.0f, 0.0f, _rotation) * Vector3.right * Distance), Quaternion.identity);
temp.SetActive(false);
Pulse temp_Script = temp.GetComponent<Pulse>();
temp_Script.is_friendly = _Friendly;
for (int i = 0; i < Damage.Length; i++)
temp_Script.Damage[i] = (int)((float)Damage[i] * _Atk_Mul);
temp_Script.Size = new Vector3(Size, Size, 1.0f);
temp_Script.speed = Velocity;
temp.SetActive(true);
}
}
구체 Active
[CreateAssetMenu(menuName = "Scriptables/Act/Orb")]
public class Act_Orb : Active_Base
{
public float Time_Max;
public float Time_Term;
public override void Create_Obj(Vector3 _Position, float _rotation, bool _Friendly, float _Atk_Mul)
{
GameObject temp = Instantiate(Atk_Obj, _Position + (Quaternion.Euler(0.0f, 0.0f, _rotation) * Vector3.right * Distance), Quaternion.identity);
temp.SetActive(false);
Orb temp_Script = temp.GetComponent<Orb>();
temp_Script.is_friendly = _Friendly;
for (int i = 0; i < Damage.Length; i++)
temp_Script.Damage[i] = (int)((float)Damage[i] * _Atk_Mul);
temp_Script.Size = new Vector3(Size, Size, 1.0f);
temp_Script.Time_Max = Time_Max;
temp_Script.TIme_Term = Time_Term;
temp_Script.Direction = _rotation;
temp_Script.velocity = Velocity;
temp.SetActive(true);
}
}
Active 발동 부분(실제로는 없어도 되지 싶습니다.)
[Serializable]
public class Active_Cell
{
public Active_Base Active;
public bool is_On = false;
public int Count_Cur = 0;
public float Count_Term = 0.0f;
public virtual void Use_Active(Vector3 _Position, float _rotation, bool _Friendly, float _Atk_Mul)
{
is_On = Active.is_On;
if (is_On)
{
Count_Cur = Active.Max_Count;
Count_Term = 0.0f;
}
for (int i = 0; i < Active.Branch; i++)
{
for (int j = 0; j < Active.Line; j++)
{
for (int k = 0; k < Active.Way; k++)
{
float Skill_Rotation = _rotation + (Active.Angle_Term * (((Active.Way - 1) / 2) - k)) + (360 / Active.Branch * i);
Vector3 Skill_Position = _Position + (Quaternion.Euler(0.0f, 0.0f, Skill_Rotation) * Vector3.right * j * Active.Size);
Active.Create_Obj(Skill_Position, Skill_Rotation, _Friendly, _Atk_Mul);
}
}
}
}
}
※ 추후 추가할 요소가 있어서 몇 가지 사전 작업을 해 놓았습니다.
플레이어 사용 파트(일부)
조작 인식 - 발동
if (Input.GetMouseButtonDown(0))
{
Attack.Use_Active(transform.position, Angle_Mouse, true, Scarf.Base_Att[0] * Scarf.Atk / 10000);
}
if(Input.GetMouseButtonDown(1) && Point_Cur >= Active_List[Cur_Active].Active.Point_Amount)
{
Point_Use(Active_List[Cur_Active].Active.Point_Time, Active_List[Cur_Active].Active.Point_Amount);
StartCoroutine(Active_Use(Cur_Active, Active_List[Cur_Active].Active.Refeat));
}
float Input_Wheel = Input.GetAxis("Mouse ScrollWheel");
if (Input_Wheel > 0)
{
Cur_Active++;
if (Cur_Active > 2)
Cur_Active = 0;
}
else if (Input_Wheel < 0)
{
Cur_Active--;
if (Cur_Active < 0)
Cur_Active = 2;
}
반복용 코루틴 함수
IEnumerator Active_Use(int Skill_Num, int Use_Num)
{
for (int i = 0; i < Use_Num; i++)
{
Active_List[Skill_Num].Use_Active(transform.position, Angle_Mouse, true, Scarf.Base_Att[0] * Scarf.Atk / 10000);
yield return new WaitForSeconds(0.1f);
}
}
새로운 내용 정리
코루틴
- 특정 요소에 대해서 독립적인 반복작업을 구성해야 하는 경우 유용하게 쓸 수 있는 기법.
- Invoke와 유사하며, 일반적으로는 Invoke 보다는 코루틴을 쓰는 것이 좋다.
┗ Invoke는 인수 전달은 할 수 없지만, 코루틴으로는 인수 전달이 가능하다.
┗ 작동 방식이 달라서 Invoke 보다 처리 속도가 빠르다.
정리하며
이번에도 부모 클래스와 자식 클래스의 구성을 어떻게 할지, 이걸 기동부 클래스와 어떻게 연계해야 할지 고민하는 시간이 길었습니다. 결과적으로는 자식클래스에 죄다 때려박은 감이 있긴 합니다만, 전체적으로는 원하던 구성이 완성된 거 같습니다.
추후 공격 오브젝트 간의 상호작용을 추가할 예정이며, 동시에 공격용 클래스가 다른 공격 클래스를 품어서 동시 발동되는 구성도 고려하고 있습니다.
다만, 일단 테스트 플레이는 가능하도록 만드는 것이 우선인 것 같아서 바로 작업하지는 않고, 필드 범위 제한이랑 적 몬스터 수정요소 적용(+ 체력바 & 데미지 폰트 추가), 타이틀 화면 추가 및 게임오버 추가를 한 뒤에 작업할 예정입니다.
이후 장비 시스템(+ 스킬 세팅 시스템)을 추가하고 시스템 세팅 UI와 캐릭터 세팅 UI를 추가하면 1차적으로는 완성했다고 봐도 될 것 같습니다.
물론, 캐릭터가 모두 도형이라던지, 스킬 종류가 적다던지 하는 문제가 있어서 최종 완성까지 가려면 아직 멀었지만요.
'스파르타 내일배움캠프 > Today I Learned' 카테고리의 다른 글
(사전 캠프) Day 18 [실전 제작: 멍뭉이! 멍멍뭉!] (0) | 2024.09.05 |
---|---|
(사전 캠프) Day 17 - 멍뭉이! 멍멍뭉! ~ 귀신 잡는 개멍대! (0) | 2024.09.04 |
(사전캠프) Day 15 - 멍뭉이! 멍멍뭉! ~ 귀신 잡는 개멍대! (0) | 2024.09.02 |
(사전 캠프) Day 14 - 멍뭉이! 멍멍뭉! ~ 귀신 잡는 개멍대! (0) | 2024.08.30 |
(사전 캠프) Day 13 - 간단한 역 기획 발표하기 (0) | 2024.08.29 |