이번에 자동 공격 파트를 맡게 되면서 아이템을 습득 할때 공격 특징이 바뀌고, 이것들이 조합되는 특징을 가질 수 있도록 공격 변경에 확장성을 띌 수 있도록 코드를 작성해야 했습니다.
이를 위해서 Module 형식으로 공격 특성을 붙일 수 있도록 코드를 작성해보았습니다.
아이템은 각각 모듈 리스트를 가지고 있으면서 필요 할때 해당 리스트를 반환해 현재 적용되고 있는 모듈을 알려줍니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "Item/Item Data")]
public class ItemData : ScriptableObject
{
public string ItemName;
public Sprite Icon;
public List<ProjectileModuleData> ProjectileModules;
public List<FireModuleData> FireModules;
public List<StatModuleData> StatModules;
}
투사체에 직접 붙은 모듈로써, 관통, 유도등의 투사체에 반영되는 모듈입니다.
public interface IProjectileModule
{
void OnFire(Projectile projectile);
void OnUpdate(Projectile projectile);
}
using UnityEngine;
[CreateAssetMenu(menuName ="Projectile/Module data")]
public class ProjectileModuleData : ScriptableObject
{
public string ModuleName;
public GameObject ModulePrefab;// 반드시 IProjectileModule이 붙어야함
}
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
public class HomingModule : MonoBehaviour, IProjectileModule
{
private Transform _target;
public void OnFire(Projectile projectile)
{
_target = projectile.Target;
}
public void OnUpdate(Projectile projectile)
{
if (_target == null) return;
Vector3 dir = (_target.position - projectile.transform.position).normalized;
Quaternion rotate = Quaternion.LookRotation(Vector3.forward, dir);
projectile.transform.rotation = Quaternion.Lerp(
projectile.transform.rotation, rotate, Time.deltaTime * projectile.Speed);
}
}
FireModule은 발사시에 반영되는 모듈로써, 투사체를 3갈래로 발사한다던가, 커다란 투사체를 발사하는 등의 투사체에 변경을 주게 됩니다.
using UnityEngine;
public abstract class FireModuleData : ScriptableObject
{
public abstract IFireModule CreateInstance();
}
using UnityEngine;
public interface IFireModule
{
void OnFire(AttackController attack, Transform enemy);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "FireModules/Spread Shot")]
public class SpreadShotData : FireModuleData
{
public float Angle = 15f;
public int ProjCount;
public override IFireModule CreateInstance()
{
return new SpreadShotModule(this);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpreadShotModule : MonoBehaviour, IFireModule
{
private SpreadShotData _spreadShotData;
public SpreadShotModule(SpreadShotData data)
{
_spreadShotData = data;
}
public void OnFire(AttackController attack, Transform enemy)
{
int middle = _spreadShotData.ProjCount / 2;
// 중심 발사 방향 계산 (타겟을 향한 방향)
Vector2 dir = (enemy.position - attack.AttackPivot.transform.position).normalized;
float baseAngle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90f; // Z축 기준
for (int i = 0; i < _spreadShotData.ProjCount; i++)
{
float offset = (i - middle) * _spreadShotData.Angle;
Quaternion rotation = Quaternion.Euler(0, 0, baseAngle + offset);
GameObject go = GameObject.Instantiate(
attack.ProjectilePrefab,
attack.AttackPivot.transform.position,
rotation
);
var proj = go.GetComponent<Projectile>();
proj.Init(attack.StatHandler, enemy, attack.ItemEffectManager.GetProjModules());
}
}
}
처음 생각했을 때는 이렇게 특징이 붙어져 나오는 탄환들을 모두 Bool 로 관리해야 하나 했지만 이렇게 Module 형식으로 코드를 작성하여 붙였더니 통합해서 하나의 화살 모양을 보여주는 것이 매우 쉬워졌습니다.