평타
간단히 컨텐츠를 준비하기 위해 평타를 구현해보자.
그렇다면 이것을 어디에 구현해야할지 또 고민이 된다. PlayerController에 넣는게 제일 좋은 생각이라는게 든다. 왜냐하면 모든 Creature가 공격을 하진 않을거기 때문이다.
Skill이 수백개 처럼 엄청 많으면 전문적으로 스크립트를 만들어서 관리하는게 낫겠지만 지금처럼 평타하나만 만드는경우 클래스를 계속 만드는것보다 만들다가 분리하는게 좋다.
또 스킬을 쓸 때, 쿨타임이 있고 후딜이 있게끔 구현해야하기 때문에 Coroutine을 이용할 것이다.
피격은 지금 처리하지 않고 나중에 처리할 것인데 일단 Log만 찍어보자
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Define;
public class PlayerController : CreatureController
{
Coroutine _coSkill;
protected override void Init()
{
base.Init();
}
protected override void UpdateController()
{
GetDirInput();
switch(State)
{
case CreatureState.Idle:
GetDirInput();
GetIdleInput();
break;
case CreatureState.Moving:
GetDirInput();
break;
}
base.UpdateController();
}
private void LateUpdate()
{
Camera.main.transform.position = new Vector3(transform.position.x, transform.position.y, -10);
}
// 키보드 방향 설정
void GetDirInput()
{
// 이동하겠다고 선언
if (Input.GetKey(KeyCode.W))
{
Dir = MoveDir.Up;
}
else if (Input.GetKey(KeyCode.S))
{
Dir = MoveDir.Down;
}
else if (Input.GetKey(KeyCode.A))
{
Dir = MoveDir.Left;
}
else if (Input.GetKey(KeyCode.D))
{
Dir = MoveDir.Right;
}
else
{
Dir = MoveDir.None;
}
}
private void GetIdleInput()
{
if (Input.GetKey(KeyCode.Space))
{
State = CreatureState.Skill;
_coSkill = StartCoroutine("CoStartPunch");
}
}
IEnumerator CoStartPunch()
{
// 피격 판정
GameObject go = Managers.Object.Find(GetFrontCellPos());
if(go != null)
{
Debug.Log(go.name);
}
yield return new WaitForSeconds(0.5f);
State = CreatureState.Idle;
_coSkill = null;
}
}
화살
이번에는 화살 공격을 만들어보자. 화살을 조금 더 어려운게 투사체가 있기 때문에 이를 고려해야하기 때문에 조금 더 어렵다.
그러면 화살은 Controller가 필요할까?? 움직이는 오브젝트이니까 당연하다. ArrowController를 만들고 관리해보자.
화살이 전진하는데 방해물이 있다면 그대로 사라지고 몬스터를 만났다면 아직 피격처리는 하지 않은 채 Log만 찍어보도록 하자.
물론 여기에 적는 코드나 이것만 변경사항이 있는건 아니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static Define;
public class ArrowController : CreatureController
{
protected override void Init()
{
switch (_lastDir)
{
case MoveDir.Up:
transform.rotation = Quaternion.Euler(0,0,0);
break;
case MoveDir.Down:
transform.rotation = Quaternion.Euler(0, 0, -180);
break;
case MoveDir.Left:
transform.rotation = Quaternion.Euler(0, 0, 90);
break;
case MoveDir.Right:
transform.rotation = Quaternion.Euler(0, 0, -90);
break;
}
base.Init();
}
protected override void UpdateAnimation()
{
}
protected override void UpdateIdle()
{
if (_dir != MoveDir.None)
{
Vector3Int destPos = CellPos;
switch (_dir)
{
case MoveDir.Up:
destPos += Vector3Int.up;
break;
case MoveDir.Down:
destPos += Vector3Int.down;
break;
case MoveDir.Left:
destPos += Vector3Int.left;
break;
case MoveDir.Right:
destPos += Vector3Int.right;
break;
}
State = CreatureState.Moving;
if (Managers.Map.CanGo(destPos))
{
GameObject go = Managers.Object.Find(destPos);
if (go == null)
{
CellPos = destPos;
}
else
{
Debug.Log(go.name);
Managers.Resource.Destroy(gameObject);
}
}
else
{
Managers.Resource.Destroy(gameObject);
}
}
}
}
소멸 이펙트
지금은 화살에 피격했을 때, 몬스터의 정보만 출력하게되어 있는데, 이제는 화살에 피격했을 때 사라지게 해보자. 물론 Hp나 데미지를 계산해서 죽어야하지만 이 역시 어차피 서버에서 관리할 값이니에 테스트 용도로만 만들어보자.
사라지는게 밋밋하면 재미 없으니까 이펙트를 추가할 것인데 이는 이펙트를 프리팹으로 만든 다음에 사라질때 보여주게 하면 될것 같다.
protected override void UpdateIdle()
{
if (_dir != MoveDir.None)
{
Vector3Int destPos = CellPos;
switch (_dir)
{
case MoveDir.Up:
destPos += Vector3Int.up;
break;
case MoveDir.Down:
destPos += Vector3Int.down;
break;
case MoveDir.Left:
destPos += Vector3Int.left;
break;
case MoveDir.Right:
destPos += Vector3Int.right;
break;
}
State = CreatureState.Moving;
if (Managers.Map.CanGo(destPos))
{
GameObject go = Managers.Object.Find(destPos);
if (go == null)
{
CellPos = destPos;
}
else
{
Debug.Log(go.name);
// 이펙트 틀기
GameObject effect = Managers.Resource.Instantiate("Effect/DieEffect");
effect.transform.position = go.transform.position;
effect.GetComponent<Animator>().Play("START");
GameObject.Destroy(effect, 0.5f);
Managers.Object.Remove(go);
Managers.Resource.Destroy(go);
Managers.Resource.Destroy(gameObject);
}
}
else
{
Managers.Resource.Destroy(gameObject);
}
}
}
ArrowController의 일부분인데 이펙트를 끄고 키는것 그리고 적들을 사라지게 하는건 어렵지 않다. 그런데 적들이 사라지는게 꼭 화살만 있는것은 아니다. 다양한 경로를 통해 몬스터가 죽을 수 있으니 이를 고려해야한다.
if (Managers.Map.CanGo(destPos))
{
GameObject go = Managers.Object.Find(destPos);
if (go == null)
{
CellPos = destPos;
}
else
{
Debug.Log(go.name);
// 이펙트 틀기
CreatureController cc = go.GetComponent<CreatureController>();
if (cc != null)
cc.OnDamaged();
Managers.Resource.Destroy(gameObject);
}
}
else
{
Managers.Resource.Destroy(gameObject);
}
크리처 컨트롤러에서 OnDamaged라는 가상 함수를 만들어서 그것을 상속받은 객체들에서 처리를 해주는게 올바른 방식이라는 생각이 든다.
public override void OnDamaged()
{
GameObject effect = Managers.Resource.Instantiate("Effect/DieEffect");
effect.transform.position = transform.position;
effect.GetComponent<Animator>().Play("START");
GameObject.Destroy(effect, 0.5f);
Managers.Object.Remove(gameObject);
Managers.Resource.Destroy(gameObject);
}
몬스터 컨트롤러에 이 부분을 추가해준다.
'Unity > 온라인 RPG' 카테고리의 다른 글
[Unity 2D] 서버 연동 - 멀티플레이 환경 및 게임 입장 (1) | 2024.03.07 |
---|---|
[Unity 2D] 컨텐츠 준비 - Monster AI(Patrol AI, Search AI, Skill AI) (0) | 2024.03.05 |
[Unity 2D] 컨텐츠 준비 - MapManager, Controller 정리, ObjectManager (0) | 2024.03.04 |
[Unity 2D] 컨텐츠 준비 - 세팅, MapTool, 플레이어 이동 (4) | 2024.02.28 |
[데이터베이스] SQL 튜닝 - 북마크 룩업, Join, Sorting (1) | 2024.02.23 |