ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • FPS 연습 02. Player 총 발사 구현
    연습 프로젝트/FPS 연습

    안녕하세요

    오늘은 Player의 총 을 쏘는 구현과 Zombie를 제작해 맞는 모션까지 제작하려고 합니다.

     

    우선 이렇게 제작을 해야 하는데.

     

    먼저 해야 할 것들이 생각났습니다.

     

    첫 번째는 Ground야 아직 작업 단계니 추 후로 미뤄둔다고 해도

     

    배경은 있어줘야 그림이 경계선도 뚜렷해지고 괜찮아질 것 같다고 생각했습니다.

     

     

    두 번째는 조준점이 있어야겠다고 생각했어요.

     

    우선 이 두 가지부터 작업을 완성 후 

     

    player의 총 쏘는 동작 구현과 zombie를 제작해 보겠습니다.

    SkyBox

    음. 이 부분은 책을 봤을 때를 얻은 지식으로 그때가 생각나 SkyBox를 적용해봤는데

    제가 적용한 방식을 설명? 하려고 하니 말을 잘 못하겠습니다.

     

    우선 책의 힘을 살짝 빌려와서 ㅎㅎ..

    하늘을 표현하는 대표적인 방식으론 SkyBox와 SkyDome이 있다고 합니다.

    SkyBox

    SkyBox는 left, front, right, back, top, bottom의 이미지를 Cube 형태로 배치하여 표현한 것이고

    SkyDome 은 Dome 형태의 메시에 하늘의 이미지를 텍스처로 입혀 구현한 것이라고 합니다.


    큼큼.. 

     

    이후 화면의 조준점을 그려주어

     

    발싸되는 지점이 어딘지 시각적으로 확인해 보겠습니다.

     

    간단히 UI항목의 Image를 이용해 구현했습니다.

     

     

    Canvas의 Render Mode는 우선 Screen Space로 사용했습니다.

     

    Screen Space : 가장 기본이 되는 모드.

    스크린의 크기가 조절되거나 해성도가 변경되면 캔버스는 여기에 맞춰 자동으로 크기를 변경함.

     

    Screen Space : 위의 Screen Space와 유사하지만,

    이 렌더 모드에서는 캔버스가 씬의 특정 Camera에서 주어진 거리만큼 앞쪽에 위치한다

    즉 카메라 설정이 ui모습에 영향을 준다.

     

    World Space : 이 렌더 모드는 캔버스가 씬에 있는 다른 오브젝트처럼 동작한다.

    예를 들어 체력바 라던가 닉네임 이라던가 등등..

     


     

    이제 기본 구색은 갖춘 것 같으니 Player가 총을 발사하는 부분을 구현해 보겠습니다.

    변수 선언 부분과 Start 함수입니다.

     

    bulletEffect : 총알이 맞은 자리를 시각화를 해 주기 위한 Effect입니다.

    ps : 받아온 bulletEffect의 ParticleSystem을 실행시켜 주기 위하 변수입니다.

     

    ps = bulletEffect의 GetComponent로 ParticleSystem을 받아왔습니다.

     

    먼저 업데이트 함수부터 보겠습니다.

    Input.GetMouseButton(0)으로 조건문을 걸어주었습니다.

    GetMouseButton ( 매 누르고 있을 시 )

    GetMouseButtonDown ( 눌러졌을 시 )

    GetMouseButtonUp ( 떼어졌을 시)

     

    0번으로 선택하여 마우스 왼쪽 버튼을 클릭하면 총을 발사하게 해 놨고

    (1번은 마우스 오른쪽, 2번은 휠)

     

    GetMouseButton으로 연사가 가능하게 해 놨습니다.

     

    매 프레임마다 실행되는 Update 함수에서 GetMouseButton는 상당한 슈퍼 연사를 실행하기에..

     

    isFals라는 불 변수로 총을 쏘고 있는 상태인지 판단하게 했고

    그 조건이 false 일 시 StartCorutine 함수로 Fire() 함수를 실행하게 했습니다.

    Fire 코 루틴 함수입니다.

     

    처음 작업을 할 땐

    간단한 Sphere를 만들어서 

     

    총알로 구현을 했었습니다.

    10개를 미리 생성해 두어 오브젝트 풀 관리 방식으로 사용하여

    활성화 / 비활성화를 해줬었지만

    문제 아닌 문제가 있었습니다.

    단 발 (한발)씩 쏠 때는 딱히 이상 현상이 안 보였는데

    연사(여러 발)를 쏘게 되니깐

    시각적으로 보이는 현상은 탁월하긴 하지만, 캐주얼? 식의 느낌이 없지 않아 느껴졌고

    제가 원하는 방식이 아녔습니다!

     

    그래서, Ray를 이용한 방식을 택했고 

     

    코 루틴 함수인 Fire 함수를 다시 보겠습니다.

    우선 업데이트에서 isFire가 false 였으면 실행될 조건이었던 isFire를 true로 바꿔주어

    바로 중복이 불가능하게 만들었습니다.

     

    Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward)

    레이를 만들어 주는 모습입니다.

     

    Ray는 Vector3 orinzin과 Vector3 forward를 받습니다.

    즉 원점과 방향이라 생각하면 쉬운데

     

    new Ray의 첫 번째 인자인 Camera.main.transform.position : 메인 카메라의 포지션으로 

    카메가 보는 방향에 , Camera.main.transform.forward로 앞 방향으로 해 줍니다.

     

    카메라가 보는 시점에, 카메라의 앞 방향

     

    이후 이 생성한 레이를 쏠 경우 맞은 녀석을 담아줄 RaycastHit hit입니다.

     

    이후 Manager.instance.managerSe.audio.PlayOneShot(Manager.instance.managerSe.player_Rifle, 0.5f)를 이용해

    사운드를 재생하는 코드입니다. PlayOneShot과 같은 Play함수도 있지만. 

    Play함수는 소리가 중첩되면 마지막 소리만 나타내어집니다.

     

    이제 단순 생성만 해놓은 ray를 쏴 보겠습니다.

     

    ray는 단순하게 생각해서 눈에 보이지 않는 광선을 쏜다고 생각하시면 됩니다.

    Ray ray로 광선을 만들고, 위치와 방향을 결정해주어

    Physics.Raycast으로 만든 레이를 발사해주며 맞은 

    맞은 오브젝트의 정보를 RaycastHit로 선언한 구조체 변수 hit에 담아 줍니다

     

    ray를 쏠 때는 Physics를 이용합니다.

     

    Physics는 물리학이라는 뜻이 있는데요.

    물리와 관련됐다고 생각하시면 쉽습니다.

    이후. Raycast를 이용해 만들었던 레이를 쏴 줍니다.

     

    들어가는 인자로 ray(생성한 ray)와 hit 충돌된 부분이 들어가는데요

    (ray, out hit)로 넣어줬습니다.

     

    여기서 hit 앞에 out키워드를 붙어야 한다고 학습을 했어서 out을 붙였는데

    정확히 왜 붙여야 하는가? 를 제가 모르고 있더라고요.

    그래서 검색을 해서 찾아보았습니다.

     

    c#에서는 out키워드를 직접 매개변수의 값을 바꿀 수 있는 매개변수 한정자로 사용한다고 합니다.

     

    제가 다시 볼 때 기억을 하기 위해서 예시 2가지를 남기겠습니다.

     

    int number;

    number = Keyword(number);

    Console.WriteLin(number);

     

    void Keyword(out int result)

    {                                    

    result= 1;

    return result;

    }                                   

    // 출력 : 1


    int number;

    Keyword(out number);

    Console.WriteLin(number);

     

    void Keyword(out int result)

    {                                    

    result= 1;

    }                                   

    // 출력 : 1


    위 예제처럼 이렇게 매개 변수의 값을 바꾸려면 return 키워드를 사용해서 직접 할당을 해 주어야 하지만,

    아래 예제처럼 out키워드를 사용해서 변수에 직접 할당을 하지 않아도 값이 반환되는 예제입니다.

     

    이렇게 봤을 때 out hit의 out키워드는 직접 할당을 하지 않아도 RaycastHit 변수 hit에 담아준다는 뜻인데

     

    어느 정도 이해는 가지만, 작동 원리? 부분이 제대로 이해가 가질 않습니다.

    공부를 많이 해야 할 것 같습니다..


    bulletEffect.transform.position = hit.point;

    bulletEffect.transform.forward = hit.normal;

    ps.Play();

     

    우선 많이 봤던 코드부터 보겠습니다.

    bulletEffect.transform.position : 받아온 bulletEffect의 트랜스폼 포지션입니다.

    bulletEffect.transform.forward : 받아온 bulletEffect의 트랜스폼 포워드(앞 방향)입니다.

     

    ps.Play() 

    ps : 받아온 bulletEffect의 ParticleSystem입니다.

    이 ParticleSystem을 Play 함수를 이용해 재생시켜 줍니다.

     

    hit.point

    hit.normal

     

    hit는 RaycastHit로 선언한 변수로 ray에 충돌된 오브젝트를 담고 있었죠?

    여기서 point는 충돌 지점을 뜻합니다.

     

    여기서 hit.transform.position을 사용하면 안 되나? 하고 써봤는데

    어딘진 모르겠지만 발생은 되더군요. 찾는데 10분은 걸린 듯합니다 허허...

    이렇게 사용한 걸 풀어 보면 hit(충돌된 오브젝트 의) transform(트랜스폼 의) position (위치)가 됩니다.

    이렇게 해서 총을 발사하면 맞은 오브젝트의 원점이 되는 것이죠

    이렇게 차근차근 풀어보면 말이 안 되는 걸 알 수 있지만, 사람 습관이란 게 ㅎㅎ....

     

    그리고 hit.normal입니다.

    이 normal은 법선 벡터라고도 불립니다.

     

    이게 설명을 어떻게 해야 할지 감이 잘 안 잡히는데..

    면과 수직인 벡터를 법선 벡터 (Normal Vector)라고 합니다.

    보통 법선 벡터는 빛의 반사 방향을 계산하거나 입사각에 대한 반사각을 계산할때 필요로 한다고 하는데요

     

    즉 풀어서 보자면 피격 이펙트의 forward 방향을 레이가 부딪힌 지점의 법선 벡터와 일치시킨다고 보시면 됩니다.

     

    yield return new WaitForSeconds(0.2f)를 이용해서 0.2초의 대기시간을 주었으며
            isFire = false 대기시간이 끝나면 isFire를 false로 바꿔주어 다시 if(Input.GetMouseButton(0)) 기능이

    가능하게 만들어 줍니다.

    즉 총이 발사되는 대기시간이 0.2f초가 된 셈입니다.


    긴 코드는 아니지만, 확실하게 기억하고 넘어가야 하는 부분인 것 같습니다.

    특히나 ray를 활용한 방법은 정말 많이 다양하게 연출이 가능할 것 같고 

     

    많은 영상과 학습을 통해서 퀄리티 높은 연출과 기법들을 사용해서 

    보다 멋진 영상으로 빠르진 않더라도 꾸준히 발전하는 모습 보여드리겠습니다.

     

    마지막으로 영상을 보며 오늘은 마무리하겠습니다.

    감사합니다.

     

    우선 영상을 보시기 전에, 총사운드가 갑자기 들려서 놀라실 수 있으십니다. 

    먼저 소리를 작게 하고 보신 다음 소리를 키우시는 것이 좋을 듯합니다.

     

     

    00 : 20초

     

    -추가 : 제가 설명 안 한 부분이 있는데, Ray를 사용할 때 충돌 여부를 감지하려면

    오브젝트에 Collider가 꼭 붙어있어야 합니다.

     현재 맵 제작 중인데 Collider를 안 붙이고.. 혼자 이상한 짓을 하고 있었습니다. ㅋㅋ

    댓글

김효겸 / Tel. 010-7735-0580 / E-mail. dollzzang2@hanmail.net