본문 바로가기

3D_FPS

08_04 (Enemy 생성, FSM 구현, Idle 구현)

 

목차

 


 

(참고) 어제 했던것  중 짚고 넘어갈 것 (RIgidBody 부분)

 

더보기

Rigidbody 는 원래 충돌하기 위해서 사용했었음

이걸 이용해서 물리를 어떻게 표현할까 생각했음

 

Velocity

Force

 

update()에서 

V =V0 + at  이걸 넣으면

총알은 그냥 앞으로 쭉 나갈거임. (포물선을 그리지도 않고)

벽에 맞아도 튕기지도 않음.

 

그래서 RigidBody 쓸려면 태어날때 한번 주거나 이렇게 하는게 좋음!

Update 에 넣고 계속 하는게 아니라

 

유니티에는 NVIDIA 물리엔진이 들어가있는데

여기에는 진짜 엄청 많은 물리엔진이 구현되어있음. 그래서 엄청 무거움

 

앵그리버드를 만든다면, 

날라가서 쾅 부딪히면, 다 부서지고 떨어지고 이런거 할때는 RIgidBody 가 붙어야 함

 

조인트
힌지 하나씩 달아서 조종

이런거할때 RIgidBody 같은거 들어감

 

[Player] 머리위에서 총 터지는 문제 해결 (Layer 이용)

 

문제 [바닥에다가 총 쏘면 머리위에서 터짐 ㅋㅋ ]

앞에 쏘는데 지금 머리에서 터지는 장면,,

 

자기한테 안맞게 하기위해 LayerMask를 써보자

플레이어한테 붙여줌

 

Player 에게 Layer 를 붙여준 모습

 

 

 

 

비트연산자로 밀어준 모습

 

 

여기에 컴마를 넣어주면 다른 형태 하나 더나옴 (오버로딩)

 

1000m 까지  레이에 걸리는 애를 확인하는것임

 

 

(참고) !와 ~ 의 차이

더보기

 

! 는 bool 연산자에서 쓰고

 

~ 는 비트연산자에서 쓰는거임

 

 

(참고) Layer 와 비트

더보기

 

Layer 는 32개가 있음

 

32와 관련있는것? (int)

 

 

0은 불을 꺼넣고, 1이면 불을 켜놓는다.

불들어온놈은 충돌체크~

안들어오면 충돌 안함~ 단순히 이렇게 되잇음

 

근데 코딩스타일 대로 하면

if( 레이어가 막 6인데 얘가 충돌을 가능하게 하면 or 7번이랑도 충돌 되고 막 ㅁㄴㅇㄻㄴㅇㄻ)

이렇게 쓸게 많다.

 

이렇게 코드상에서만 봐도 엄청난 차이이다.

 

레이어도, 신호들어오면 충돌체크 하고 이런식으로 하는것이다.

 

그럼 Player 는 6번째인데 6번째 불 어떻게 켜?

 

1번에 1 써놓고 << 로 옮기는거임!
6번 옮긴것!

근데 플레이어는 안맞고 나머지는 다 맞게 하고싶음

즉, 6번째만 0으로 하고 나머지를 1로 하고싶음 그러면 6번째를 1로 만들고, 

반전 기호

이렇게 다 반대로 해놓으면 됨!!

그래서 

 

 

 

이걸 코드로 구현한거임... Holy Shit..

---

 

옛날 게임들 중 키 조합해서 만드는것

 

 

 

아도겐 은 3,4,5 조합이면

 

3,4,5번에 비트가 찍힘

이렇게 되면 아도겐 스킬이 나감.

 

 

 

 

사용자가 누른 비트랑 && 해서 완전 똑같으면 아도겐이 나가게 함.

 

만약 다른걸 눌러서 && 를 하면? 3,4,5 번째가 1이 안되면 안나가게 함.

 

이렇게 비트가 획기적임!!

 

 

 

뭐 다른 스킬은 다른 순서 조합이고 이런 스킬들이 있으면

 

 

실무에서 그렇게 많이 쓰지는 않지만, 

그러면 2 를 1칸 옮기면 4 가 나옴!

여기까지 플레이어

------------------------------

(참고)오버로딩과 디폴트 인수

더보기
오버로딩에서 디폴트 인자를 넣은 모습

이렇게 하면 아무것도 안넣어도 디폴트 인자가 들어감

(참고) 사업이든 창업이든 입사하면 가져야 할 마인드

더보기

내가 이 회사를 먹여살린다.

어떻게하면 이 회사를 먹여 살릴 수 있을까

 

--------

[Enemy 만들기]

 

 

1. 빈게임오브젝트로 Enemy 를  만들자!

2. CharacterController 도 넣고

Capsule 콜라이더는 뺴주자!

3. Eye 도 넣고

 

 

 

(참고) FSM (유한 상태 머신) 

본문과 목차와 구분해서 만들기 위해 FSM 을 만드는거임!

 

F = Finite = 유한

S = State = 상태

M = Machine = 동작 (유기적인)

 

우리가 알고있는  FSM 은 자판기!

이런 유한한 상태와 흐름을 가지고 있음

저 일련의 과정들을 상태 다이어그램이라고도 함!

 

----

[Enemy Finite StateMachine]

 

 

처음 시작하는 단계는 '대기' 여야 함. 그걸 Default State 라고 하고, 

시작하는 단계라고 해서 Entry State 라고도 함

전체적인 설명 사진 , 화살표는 Transition 이라고 함.

 

AnyState 는 어떤 상태에서든! 이라는 말이다.

 

피격당한 후 죽는게 아니라, 어떤상태에서든 죽게..!

 

 

이제 뼈대 설계를 위해 

Enum 을 이용해 볼거임

  enum EnemyState
    { 
        Idle,
        Move,
        Attack,
        Damage,
        Die
    };

    EnemyState m_State = EnemyState.Idle;

Update () 에 뼈대를 작성해놓음

 

    void Update()
    {
        switch (m_State)
        {
            case EnemyState.Idle:
                Idle();
                    break;
            case EnemyState.Move:
                Move();
                    break;
            case EnemyState.Attack:
                Attack();
                    break;
            case EnemyState.Damage:
                Damage();
                    break;
            case EnemyState.Die:
                Die();
                    break;       
        }
       
    }

 

    private void Die()
    {
    }

    private void Damage()
    {
    }

    private void Attack()
    {
    }

    private void Move()
    {
    }

    private void Idle()
    {
    }

 

FSM 의 장점 이 있음!!

1.  가독성이 좋고

2. Debuging 을 하기 쉬움!

 

오류가 어디에서 났는지 알면 다 잡을 수 있음!

----

Idle 

 

 

 

 

(참고) 맨마지막 단계에서 공부 할 Try Catch

더보기

사용자 입장에서 플레이하는데 계속 꺼짐...

깰려고 했는데 꺼짐....

거기에서 버그생기고.. 그러면 안되는데 그럴때 많이 쓰게 되는게 Try Catch 임!

 

유니티, 언리얼 의 결정적인 차이점

 

Unity 는 엔진이 안꺼짐!!

근데 언리얼은 계속 꺼짐..

 

언리얼은 꺼져서 무조건 잡고 가게 하는데

유니티는 일단 계속 되게 함..

 

근데 유니티는 안되다가 껏다가 키면 되는 경우가 있음 이게 단점임.

 

 

[Enemy.cs]

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


// 적이 유한한 상태를 갖도록 하고 싶다.
// 필요속성 : 상태 정의

public class Enemy : MonoBehaviour
{
    //필요속성 : 상태정의

    enum EnemyState
    { 
        Idle,
        Move,
        Attack,
        Damage,
        Die
    };

    EnemyState m_State = EnemyState.Idle;


    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        print("State : " + m_State);


        switch (m_State)
        {
            case EnemyState.Idle:
                Idle();
                    break;
            case EnemyState.Move:
                Move();
                    break;
            case EnemyState.Attack:
                Attack();
                    break;
            case EnemyState.Damage:
                Damage();
                    break;
            case EnemyState.Die:
                Die();
                    break;       
        }
       
    }


    // 일정시간이 흐르면 상태를 이동으로 바꾸고 싶다.
    // 필요속성 : 대기시간, 경과시간
    public float idleDelayTime = 2;
    float currentTime = 0;

    private void Idle()
    {

        // 일정시간이 흐르면 상태를 이동으로 바꾸고 싶다.
        // 3. 시간이 흘렀으니까
        currentTime += Time.deltaTime;
        // 2. 시간이 됬으니까
        if (currentTime > idleDelayTime)
        {
            // 1. 상태를 이동으로 전환
            m_State = EnemyState.Move;
            currentTime = 0;
        }
        

    }



    private void Move()
    {

    }
    private void Attack()
    {

    }
    private void Damage()
    {

    }
    private void Die()
    {

    }






}