몬스터 추적 기능을 만들었으니 몬스터가 플레이어를 때리는 기본 공격을 먼저 만들려고 하는 도중 ‘플레이어 기본 공격이 우선 아닌가?’싶은 생각이 나서 플레이어 기본 근접 공격을 만들기 시작했다.
- 근접 공격의 범위는 원뿔형
- 공격 범위, 속도, 타격수(한 번 휘두를 때 2번 때리는 것같은?)는 제어 가능하게
- 2타 ~ 3타 공격이 이어짐
- 플레이어가 마지막으로 움직였던 방향이 공격 방향
위 조건들이 기획자님이 요구했던 사항들이다. 위 사항들중에 개발 기간이 오래 걸릴 것 같은 요소는 우선 제외하고 만들어도 된다고 하셨다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Weapon_1 : MonoBehaviour
{
public float viewAngle;
public float distance;
private float maxDistance;
public float damage;
public float maxDamage;
public LayerMask targetMask;
public LayerMask obstacleMask;
public MonsterStat monsterStat;
private void Start() {
maxDistance = 10.0f;
maxDamage = 100.0f;
}
private void Update() {
DrawView();
if(Input.GetKeyDown(KeyCode.K))
FindVisibleTargets();
}
public Vector3 DirFromAngle(float angleInDegrees) {
if(GameManager.GetInstance().playerDirection == new Vector3(-1.14f, 0, 1.14f))
angleInDegrees += GameManager.GetInstance().attackAngle;
if(GameManager.GetInstance().playerDirection == new Vector3(0, 0, 2.0f))
angleInDegrees += GameManager.GetInstance().attackAngle;
if(GameManager.GetInstance().playerDirection == new Vector3(1.14f, 0, 1.14f))
angleInDegrees += GameManager.GetInstance().attackAngle;
if(GameManager.GetInstance().playerDirection == new Vector3(-2.0f, 0, 0))
angleInDegrees += GameManager.GetInstance().attackAngle;
if(GameManager.GetInstance().playerDirection == new Vector3(2.0f, 0, 0))
angleInDegrees += GameManager.GetInstance().attackAngle;
if(GameManager.GetInstance().playerDirection == new Vector3(-1.14f, 0, -1.14f))
angleInDegrees += GameManager.GetInstance().attackAngle;
if(GameManager.GetInstance().playerDirection == new Vector3(0, 0, -2.0f))
angleInDegrees += GameManager.GetInstance().attackAngle;
if(GameManager.GetInstance().playerDirection == new Vector3(1.14f, 0, -1.14f))
angleInDegrees += GameManager.GetInstance().attackAngle;
return new Vector3(Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), 0, Mathf.Cos(angleInDegrees * Mathf.Deg2Rad));
}
public void DrawView() {
Vector3 leftBoundary = DirFromAngle(-viewAngle / 2);
Vector3 rightBoundary = DirFromAngle(viewAngle / 2);
Debug.DrawLine(transform.position, transform.position + leftBoundary * distance, Color.blue);
Debug.DrawLine(transform.position, transform.position + rightBoundary * distance, Color.blue);
}
public void FindVisibleTargets() {
Collider[] targets = Physics.OverlapSphere(transform.position, distance, targetMask);
for(int i = 0; i < targets.Length; ++i)
{
Transform target = targets[i].transform;
Vector3 dirToTarget = (target.position - transform.position).normalized;
if(Vector3.Dot(/*플레이어 앞방향 단위벡터*/, dirToTarget) > Mathf.Cos((viewAngle / 2) * Mathf.Deg2Rad))
{
float distToTarget = Vector3.Distance(transform.position, target.position);
if(!Physics.Raycast(transform.position, dirToTarget, distToTarget, obstacleMask))
{
Debug.DrawLine(transform.position, target.position, Color.red);
}
}
//공격기능
monsterStat = targets[i].GetComponent<MonsterStat>();
monsterStat.health -= damage;
Debug.Log("기본 공격! 남은 적 체력 : " + monsterStat.health);
}
}
}
원뿔형 공격 범위가 가장 큰 난제였다. 어떻게 제작할까 고민하다가 도통 좋은 방법이 안떠올라 검색을 해보니 벡터 내적을 활용하면 가능하다는 글을 보았다.
솔직히 벡터 내적에 관한 내용은 아직 이해가 잘 안되서 좀 더 공부해보고 유니티 카테고리에 정리해야겠다.

플레이어의 시야각 변수를 만들고 플레이어가 바라보는 방향의 단위벡터, target 위치에서 플레이어 위치 뺄샘의 단위벡터간의 내적이 cos(시야각/2)보다 커야 시야 내에 존재한다. 라는 걸 유니티 코드로 바꾸면 된다.
위 조건에 부합하는 코드를 제작하여 범위안에 존재하는 컬라이더를 받아오면 원뿔형 기본 공격을 만들 수 있다. 컬라이더를 OverlapSphere로 받아오고 범위의 길이를 담당하는 변수를 OverlapSphere 길이로 지정하면 원뿔형이 된다.
공격속도와 타격수는 개발이 오래 걸릴 것 같아서 보류하였다.
플레이어가 마지막으로 바라보는 방향을 공격 방향으로 정해야 하는데 이건 GameManager를 통해 쉽게 구현하였다. 플레이어가 움직이던 방향을 게임매니저가 매순간 받아오기만 하면 된다.
2타 ~ 3타 공격이 이어지는 건 아무래도 애니메이션으로 구현을 하는 게 좋을 것 같다. 적절한 애니메이션과 공격마다 텀을 주는 시간을 의미하는 변수들을 활용하면 만들 수 있을 것이다. 그리고 아직 공격 애니메이션에 사용될 스프라이트도 아직이다.