[Unity 강의] 뱀서라이크 강의 - 스킬 맵(무한맵) 개선
카테고리: Class VamSurLike
태그: C#, Unity, VamSurLike
IsSubclassOf
1. 개선 코드
PlayerController(평타 추가)
✔ Init - StartEgoSword() 추가
✔ StartEgoSword() EgoSword 스폰, 위치 설정, 코루틴 시작
✔ CollectEnv - Grid를 사용해서 체크
PlayerController
public class PlayerController : CreatureController
{
public override bool Init()
{
if (base.Init() == false)
return false;
_speed = 5.0f;
Managers.Game.OnMoveDirChanged += HandleOnMoveDirChanged;
StartProjectile();
StartEgoSword();
return true;
}
void CollectEnv()
{
float sqrCollectDis = EnvCollectDist * EnvCollectDist;
var findGems = GameObject.Find("@Grid").GetComponent<GridController>().GatherObjects(transform.position, EnvCollectDist + 0.4f);
foreach (var go in findGems)
{
GemController gem = go.GetComponent<GemController>();
Vector3 dir = gem.transform.position - transform.position;
if (dir.sqrMagnitude <= EnvCollectDist)
{
Managers.Game.Gem += 1;
Managers.Object.Despawn(gem);
}
}
}
#region EgoSword
EgoSwordController _egoSword;
void StartEgoSword()
{
if (_egoSword.IsValid())
return;
_egoSword = Managers.Object.Spawn<EgoSwordController>(_indicator.position, SkillID.EGO_SWORD_ID);
_egoSword.transform.SetParent(_indicator);
_egoSword.ActivateSkill();
}
#endregion
}
몬스터 스폰 개선
몬스터 스폰 플레이어 기준으로 Min~Max의 랜덤원 범위에서 스폰
✔ SpawningPool - TrySpawn()에서 스폰 Position 설정
✔ Utils.GenerateMonsterSpawnPosition - 랜덤 위치 계산, 반환
PlayerController
public class SpawningPool : MonoBehaviour
{
private void TrySpawn()
{
int monsterCount = Managers.Object.Monster.Count;
if (monsterCount > _maxMonsterCount)
return;
Vector3 randPos = Utils.GenerateMonsterSpawnPosition(Managers.Game.Player.transform.position,10,15);
MonsterController mc = Managers.Object.Spawn<MonsterController>(randPos,Random.Range(0, 2));
}
}
public class Utils
{
public static Vector2 GenerateMonsterSpawnPosition(Vector2 characterPosition, float minDistance = 10.0f, float maxDistance = 20.0f)
{
float angle = Random.Range(0, 360) * Mathf.Deg2Rad;
float distance = Random.Range(minDistance, maxDistance);
float xDist = MathF.Cos(angle) * distance;
float yDist = MathF.Sin(angle) * distance;
Vector2 spawnPosition = characterPosition + new Vector2(xDist, yDist);
return spawnPosition;
}
}
2. 스킬 추가 (EgoSwordController)
✔ EgoSword(평타) 추가
✔ SkillData.xml 스킬 데이터 추가
🔹 EgoSwordController
✅ Init() - 물리 적용, 1 ~ 4 타 Owner, Damage Set
✅ SetParticles() - 평타 각도 체크
✅ TurnOnPhysics - 물리 적용 On
🔹 EgoSwordChild
✅ 1 ~ 4 타 SET
✅ OnTriggerEnter2D 몬스터 충돌 시 체크, 데미지
SkillData.xml
<?xml version="1.0" encoding="utf-8"?>
<SkillDatas>
<SkillData templateID="1" name="화염구" type="Projectile" prefab="FireProjectile.prefab" damage="1000" speed="2" >
</SkillData>
<SkillData templateID="10" name="평타" type="Melee" prefab="EgoSword.prefab" damage="1000">
</SkillData>
</SkillDatas>
EgoSwordController
public class EgoSwordController : SkillController
{
[SerializeField]
ParticleSystem[] _swingParticles;
protected enum SwingType
{
First,
Second,
Third,
Fourth
}
//✅ Init() - 물리 적용, 1~4타 Owner, Damage Set
public override bool Init()
{
base.Init();
// Active 되기 전까지 콜라이더 물리 적용 x
for (int i = 0; i < _swingParticles.Length; i++)
_swingParticles[i].GetComponent<Rigidbody2D>().simulated = false;
for (int i = 0; i < _swingParticles.Length; i++)
_swingParticles[i].gameObject.GetOrAddComponent<EgoSwordChild>().SetInfo(Managers.Object.Player, 100);
return true;
}
public void ActivateSkill()
{
StartCoroutine(CoSwingSword());
}
float CoolTime = 2.0f;
IEnumerator CoSwingSword()
{
while (true)
{
yield return new WaitForSeconds(CoolTime);
SetParticles(SwingType.First); // 스킬 각도 세팅
_swingParticles[(int)SwingType.First].Play(); // 파티클 플레이
TurnOnPhysics(SwingType.First, true); // 물리 적용
yield return new WaitForSeconds(_swingParticles[(int)SwingType.First].main.duration); //파티클 실행 시간
TurnOnPhysics(SwingType.First, false);
SetParticles(SwingType.Second);
_swingParticles[(int)SwingType.Second].Play();
TurnOnPhysics(SwingType.Second, true);
yield return new WaitForSeconds(_swingParticles[(int)SwingType.Second].main.duration);
TurnOnPhysics(SwingType.Second, false);
SetParticles(SwingType.Third);
_swingParticles[(int)SwingType.Third].Play();
TurnOnPhysics(SwingType.Third, true);
yield return new WaitForSeconds(_swingParticles[(int)SwingType.Third].main.duration);
TurnOnPhysics(SwingType.Third, false);
SetParticles(SwingType.Fourth);
_swingParticles[(int)SwingType.Fourth].Play();
TurnOnPhysics(SwingType.Fourth, true);
yield return new WaitForSeconds(_swingParticles[(int)SwingType.Fourth].main.duration);
TurnOnPhysics(SwingType.Fourth, false);
}
}
private void SetParticles(SwingType swingtype) // 각도 틀어주기
{
float z = transform.parent.transform.eulerAngles.z;
float radian = (Mathf.PI / 180) * z * -1;
var main = _swingParticles[(int)swingtype].main;
main.startRotation = radian;
}
private void TurnOnPhysics(SwingType swingtype, bool simulated) //물리적용
{
for (int i = 0; i < _swingParticles.Length; i++)
_swingParticles[i].GetComponent<Rigidbody2D>().simulated = false;
_swingParticles[(int)swingtype].GetComponent<Rigidbody2D>().simulated = simulated;
}
}
EgoSwordChild
public class EgoSwordChild : MonoBehaviour
{
BaseController _owner;
int _damage;
public void SetInfo(BaseController owner, int damage) // 스킬 요소 세팅
{
_owner = owner;
_damage = damage;
}
private void OnTriggerEnter2D(Collider2D collision)
{
MonsterController mc = collision.transform.GetComponent<MonsterController>();
if (mc.IsValid() == false)
return;
mc.OnDamaged(_owner,_damage);
}
}
ObjectManager - Spawn (IsSubclassOf)
typeof(T).IsSubclassOf(typeof(SkillController))
T가 SkillController를 상속했는지 체크하는 코드
ObjectManager
public class ObjectManager
{
public T Spawn<T>(Vector3 position, int templateID =0) where T : BaseController
{
System.Type type = typeof(T);
else if (typeof(T).IsSubclassOf(typeof(SkillController)))
{
if (Managers.Data.SkillDic.TryGetValue(templateID,out Data.SkillData skillData)==false)
{
Debug.LogError($"ObjectManager Spawn Skill Failed{templateID}");
return null;
}
GameObject go = Managers.Resource.Instantiate(SkillPrefabsName.EgoSword, pooling: true);
go.transform.position = position;
T t = go.GetComponent<T>();
t.Init();
return t;
}
return null;
}
}
3. 맵 개선 - 무한 맵 (MapTileController)
✔ X(4) 개의 map을 플레이어 위치에 따라 위치 변경해서 무한처럼 만든다. (방법은 다양)
✔ Camera에 Collider2D 배치, 현재 위치 체크, OnTriggerExit2D를 사용해 맵 재사용
MapTileController
public class MapTileController : MonoBehaviour
{
private void OnTriggerExit2D(Collider2D collision)
{
Camera camera = collision.gameObject.GetComponent<Camera>();
if (camera == null)
return;
Vector3 dir = camera.transform.position - transform.position;
float dirX = dir.x < 0 ? -1 : 1;
float dirY = dir.y < 0 ? -1 : 1;
if (Mathf.Abs(dir.x) > Mathf.Abs(dir.y))
transform.Translate(Vector3.right * dirX * 200);
else
transform.Translate(Vector3.up * dirY * 200);
}
}
이것저것 메모
무적구현
상대에게 무적 버프? -> 복잡
상대에게 충돌 범위를 없애면 무적이 될 수 있다.
잡담, 일기?
코드, 어드레서블, 프리팹 등 규칙을 만들고 구조를 만든 후 작업을 하는 게 이해되는 느낌이다.
좀 더 편하고 뭔가를 해야 할 때 어디를 건드리면 되는지 알 거 같다.
다음 강의 UI
UI - Sprite, Prefab 옮겨놓기.
UI 팝업인지 유지되는지, 떠 있는 상태에서 실시간으로 변하는지 확인하고 설계
댓글남기기