목차
- Move() 상태 구현하기
- Attack() 상태 구현하기
- OnDamageProcess 이벤트 구현하기 (피격당했을 시)
- Die() 상태 구현하기
- 넉백 구현
- Lerp와 관련된 이야기
(참고) 고스톱에서 유용하게 쓰이는 FSM
Move() 상태 구현하기
=> 타겟쪽으로 이동하기
//타겟쪽으로 이동하고싶다 => 타겟은 Player
//타겟쪽으로 이동하고 싶다.
// 필요속성 : 이동속도, 타겟, CharactoerController
public float speed = 5;
public Transform target;
CharacterController cc;
변수 선언
private void Move()
{
//타겟쪽으로 이동하고싶다.
//1. 방향이 필요
// -> Target - me
Vector3 dir = target.position - transform.position;
dir.Normalize();
// 2. 이동하고싶다
cc.Move(dir * speed * Time.deltaTime);
}
Move() 함수에 들어가는 코드
(참고) 가독성 좋게 코드를 정리할 수 있는 Unity 의 기능!!
변수선언 (속성) 을 그냥 함수위에다가 놔도 상관은 없음!
근데 속성을 관리차원에서 위에 쭉 나열 하는것임!
근데 속성이 많아지면,,?
관리 차원에서 Unity 에서 제공하는 기능이 있음
![](https://blog.kakaocdn.net/dn/V4C08/btrIWNKLyDq/VPG09MxnjkIO7oHpQ9efnK/img.png)
![](https://blog.kakaocdn.net/dn/bqY5ps/btrIWM6aFzo/E78HwCW1ydUjKTAOTLfbu0/img.png)
Enemy.cs 에 CharacterController 속성추가
그렇다면
Enemy 가 Player 를 보면서 움직이려면??
즉, Player 쪽으로 가는 방향 dir 이 앞방향으로 하게 하려면??
나의 forward 가 dir 방향이 되면 됨!
근데 이렇게 되면? 플레이어쪽으로 뒤돌아볼 때, 너무 확확 뒤돌아봄!
확! 뒤돌아봄!
이걸 좀 고치고싶어서,, 부드럽게 해보고 싶다!
부드럽게 진행 해보기
Lerp 사용!
Lerp( from , to , % )
Vector3. Lerp ( 이 벡터부터 , 이 벡터까지 , % )
이제는 뒤돌아 볼 때, 부드럽게 돌아본다!
그런데 여기서 문제,
z값이 같으면 ( 즉, player 와 나란히 서있으면) 덤블링해서 Enemy 가 옴...!?
이것도 멋있긴 하지만,, 우리의 계획과는 좀 다르다..!
이건 EulerAngle 의 오류 때문임!
(참고)EulerAngle 의 오류
순서에 따라 결과 값이 달라지기 때문임!
Ex)
1. X 축으로 90도 회전 => Z축으로 90도 회전
2. Z 축으로 90도 회전 => X축으로 90도 회전
이건 언뜻보면 같을것 같지만 돌려보면 결과 값이 다르다!
이런 문제를 해결하기 위해
우리는 축하나만 꽂아놓고 돌리는 Quaternion (사원수) 로 써보자!
//타겟쪽으로 회전하고 싶다.
transform.rotation = Quaternion.Lerp( transform.rotation, Quaternion.LookRotation(dir), 5 * Time.deltaTime);
Quaternion.Lerp( 지금 방향, (쿼터니언으로)바라볼 방향 , t )
(참고) 왜 transform.rotation ?
여기서 또 문제.
Enemy 가 떠오르면 날아서 옴,,?
우리는 중력을 넣어줘야 한다!
여기서,
cc 기능중에 SimpleMove 라고 있음. 이걸 쓰면 중력을 받는모습을 볼 수 잇음!
(참고) SimpleMove 의 한계
근데 여기서 또 문제..
Enemy 가 앞을 보는게 아니라, Player 를 우러러본다..ㅋㅋ
이걸 해결해 보자.
문제는, Enemy 의 방향이다. Enemy 의 dir 의 Y방향만 그냥 고정시켜주면 되지 않을까!!
앞을 보는 방향 == y 값이 0 이라고 볼 수 있다!
여기까지의 Move() 코드
private void Move()
{
//타겟쪽으로 이동하고싶다.
//1. 방향이 필요
// -> Target - me
Vector3 dir = target.position - transform.position;
// y 부분은 회전하지 않게 하고싶다.
dir.y = 0;
dir.Normalize();
//타겟쪽으로 회전하고 싶다.
transform.rotation = Quaternion.Lerp( transform.rotation, Quaternion.LookRotation(dir), 5 * Time.deltaTime);
// 2. 이동하고싶다
//cc.Move(dir * speed * Time.deltaTime);
cc.SimpleMove(dir * speed); // SimpleMove 의 중력값을 조정을 못하니까, 다이나믹한건 못함
}
이제는, 공격범위에 타겟이 들어오면 상태를 공격으로 전환하고 싶다.
크기가 1이 되면 안되니까 normalize 되기 전에 써야 함!
참고)
기획자가 distance 가 2 라고 는 했는데 거리를 잘 모를 수 있다
잘 가늠이 안될 때 가시적으로 나타내는 방법!!
OnDrawGizmos() 를 사용하면 됨!
빨간색으로, 구를 그리게 됨!
Attack() 상태 구현
일정시간에 한번씩 공격하게 하고싶다!
// 일정시간에 한번씩 공격하고 싶다.
// 필요속성 : 공격대기시간
public float attackDelayTime = 2;
private void Attack()
{
currentTime += Time.deltaTime;
if (currentTime > attackDelayTime)
{
currentTime = 0;
print("attack!!");
}
}
이제 Attack 했다가 타겟이 공격범위를 벗어난다면? 상태를 '이동' 으로 전환하자!
(참고)인스펙터 멀티로 사용하는 법
어떤 상태에서든 당하는 피격!!
피격을 당해야 데미지 상태를 줄 수 있음!!
부딪힌 이벤트 발생이 먼저 이기 때문에
이건 어디서 당할까? Player 가 총쏴서 맞을때임!!
그러면 Player.cs 로 가보자!
쐈는데 안경맞으면 안죽네유.. ㅋㅋ
안경 콜라이더 빼자!
조준점(Cross Hair) 만들기!
(참고) world Space
OnDamageProcess 이벤트 구현 ( 피격당했을 시 )
HP 깎아 주기
// 3대 맞으면 죽도록 처리해보자!
위에서 public int hp = 3; 선언 해줌
(참고) 게임잼을 대하는 태도
피격상태 구현하기!
(피격당하면 일정시간 기다렸다가 상태를 Idle 로 전환하고 싶다.)
(참고)FPS 에서 맞은 위치에 따라서 피가 닳는게 다르게 하는것
부위별로 콜라이더를 넣어줘서, 다른 함수가 나오게 하는것임!
Ray 를 머리에 쐈는데, transform 이라고 하면 머리가 아니라, 그냥enemy 라고 나올 수도 있음!
그러니까 transform 이라고 하지말고 collider 라고 넣어야 함!
Die() 상태 구현하기
죽게 되면, 아래로 쭉 내려가게 되면서
밑에 다 내려가면 Destroy 시킬 예정
private void Die()
{
//아래로 사라지도록 하자.
transform.position += Vector3.down * dieSpeed * Time.deltaTime;
// 완전히 사라지면 제거
if (transform.position.y < -3)
{
Destroy(gameObject);
}
}
만약,
private void Attack()
{
currentTime += Time.deltaTime;
if (currentTime > attackDelayTime)
{
currentTime = 0;
print("attack!!");
}
//타겟이 공격범위를 벗어나면 상태를 이동으로 전환하고 싶다.
float distance = Vector3.Distance(target.position, transform.position);
if(distance > attackRange)
{
m_State = EnemyState.Move;
}
}
이 Attack() 코드에서 currentTime 이 한 1.9 초 정도 흘러서 실행되기 직전이었음.
근데 이때 피격당해서 Damage() 로 옮겨졌음
그러면
private void Damage()
{
//여기서는 Update 로 돌아감!
// 넉백 포지션
transform.position = Vector3.Lerp(transform.position, knockBackpos, 10 * Time.deltaTime);
currentTime += Time.deltaTime;
if (currentTime > damageDelayTime)
{
currentTime = 0;
m_State = EnemyState.Idle;
}
}
여기서 , 0.1 초만에 Idle 로 가야하게 됨...
그러니까 피격 당했을 때, currentTime 을 0 으로 초기화 시켜주자!
죽었는데 계속 맞게 하면 안되니까, 충돌체를 꺼버리자.
넉백 구현( 1. 그냥 위치이동, 2. Lerp 로 자연스럽게 이동 )
1. 그냥 위치이동
shootDirection 까지 설정해서 OnDamageProcess 에서 불러준 부분 (PlayerFire.cs 에 Shoot Ray() 부분 )
// Ray 를 발사해서 만약 부딪혔다면
if (Physics.Raycast(ray, out hitInfo,1000, ~layer ))
{
// 부딛힌 지점에 파편 튀게 하고싶다.
//1. 부딪힌 지점으로 이동시키기
bulletImpact.position = hitInfo.point;
// 2. 파편효과 재생하기
//파편이 튀는 방향을 부딪힌 지점이 향하는 방향과 일치시켜주자.
bulletImpact.forward = hitInfo.normal;
// 재생할 수도 있으니까 Stop 해주고
bulletPS.Stop();
// Play 해주자
bulletPS.Play();
// 부딪힌 녀석이 Enemy 라면 피격 이벤트 호출하자
// Layer, tag 이런것도 되지만
//컴포넌트 갖고있는지 체크해도 됨!
Enemy enemy = hitInfo.transform.GetComponent<Enemy>();
if (enemy != null)
{
enemy.OnDamageProcess(ray.direction);
}
}
Enemy.cs 에서 transform.position 설정
2. Lerp로 구현하기
우선 넉벡 포스를 설정해둔다
이 부분에 Time.deltaTime 이 들어가지 않는 이유 = update() 가 아니라서 딱 한프레임 만 들어가기 때문.
땅 밑으로 내려가기 때문에, shootDirection 의 y값을 0으로 만들자!
이제는 땅으로 내려가지 않음!
Lerp에 관련된 이야기
Linear Interpolation
선형보간 이라고 함
보간 한다는것
근데 여기서 재밌는게 우리가 정한 시간동안(2초라고 치자)
0 에서 1까지 가게 처리를 할 수가 있음
이렇게 하면, 2초가 걸리게 할 수 있음!!! currentTime /2 => 1 이되면 100% 가 되는 거임!
itween 이라고 함 이걸
Lerp 의 식 =>
1a*T + ( 1- a )*S
'3D_FPS' 카테고리의 다른 글
08_09 (주석처리 설정, 공격 이벤트,피격,Die 애니메이션 구현 ) (0) | 2022.08.09 |
---|---|
08_08 Enemy_Animation (Idle, Move, Attack) (0) | 2022.08.08 |
08_04 (Enemy 생성, FSM 구현, Idle 구현) (0) | 2022.08.04 |
(08_03) (0) | 2022.08.03 |
08-02 (3D_FPS) CamRotate.cs, PlayerMove.cs 생성 (0) | 2022.08.02 |