캐릭터 점프구현


이번에도 역시나 Roll a Ball을 활용한다.


캐릭터 점프는 실제 위치값을 움직이는 Translate보다는 

물리적 힘을 위로 주어서 튀어 오르는듯한 느낌을 주는 AddForce를 이용하는게 좋아보인다.


먼저 소스코드를 살펴보자


void Start( )

{       

        rb = GetComponent<Rigidbody>();

        jumpCount = 1; //점프 가능횟수

        isGround = true; //땅에 있을때

}

jumpCount는 1로 초기화 해준다.

isGround는 true로 땅에 있을때 캐릭터가 점프를 할 수 있는 환경이라고 판단하기 위해 선언 한 것이다.


void FixedUpdate ()

{        

        if (isGround) 

        {

            jumpCount = 1;

            if (Input.GetKeyDown("space")) //점프

           { 

                if (jumpCount==1){             

                    rb.AddForce(0, 300f, 0); //점프

                    isGround = false;

                    jumpCount = 0;

                }

           }

        }

    }

update문에서는 우선 플에이어가 있는 위치가 땅바닥인지 체크를 해준다.

땅바닥이라면 jumpCount값을 1로 만들어준다.

그리고 스페이스바가 눌리면 다시 jumpCount가 1인지 체크를 한다. 

두 if문이 모두 맞다면 플레이어의 rigidbody에 y값에 힘을 주어 캐릭터가 위로 튀어 오르게 만들어준다.

점프를 하고 있는 중에는

플레이어의 위치가 땅바닥이 아니기 때문에 isGround는 false로 설정하고

점프를 한번 했기 때문에 다시 jumCount는 0으로 만들어준다.(다시 점프를 할수 없게)

    private void OnCollisionEnter(Collision col)

    {

        if (col.gameObject.tag == "ground")

        {

            isGround = true;    //Ground에 닿으면 isGround는 true

            jumpCount = 1;          //Ground에 닿으면 점프횟수가 1로 초기화됨

        }

    }

OnCollision물체가 플레이어에게 닿으면 아래 코드들이 활성화된다.

플레이어에게 Collision(여기서는 땅바닥)이 닿게 되면 

jumCount를 1로 만들어준다. 


여기서 알아야 할 것은 

JumCount와 플레이의 위치 isGround를 체크 하지 않고 스페이스바를 여러번 누르게 되면 

계속해서 하늘로 치솟아 무한 점프가 될것이다 

그것을 방지하기 위해 체크한다. (캐릭터가 땅에 도착해야 다시 점프를 할 수 있게)

그리고 OnTrigger이 아닌 OnCllision을 사용했다는 점도 파악해야한다.


OnTrigger , OnCollision 비교하기

 

Collider

유니티에서 충돌체크를 하기 위한

필요한 컴포넌트이다.

 

3D오브젝트를 생성하면 Collider가 자동적으로

추가 되어있다.

 

먼저 Trigger에 대해 살펴보자

1) void OnTriggerEnter(Collider other) : Trigger에 들어갔을 때

2) void OnTriggerStay(Collider other) : Trigger안에 있을때

3) void OnTriggerExit(Collider other) : Trigger를 벗어 날때

 

 

1) OnTriggerEnter


    void OnTriggerEnter(Collider other) 

{

if (other.gameObject.CompareTag ("Pick Up"))

{

other.gameObject.SetActive (false);

 

count = count + 1;

           

            SetCountText ();

            Debug.Log(count);

}

코드는 Roll a Ball 플레이 스크립트

Collider가 닿게 되면 아래 코드가 실행된다.

 

 

흰색 볼에 스크립트를 추가 하였다. 그리고 노란색 Cube에 닿을때 마다

왼쪽 상단에 Count 값이 증가되고 있는것을 볼수 있다.

 

 

2) OnTriggerStay

우선 // other.gameObject.SetActive (false); 

위 코드면 큐브가 사라진다.

Collider가 닿은 상태를 유지 하는 동안을 보기위해

주석 처리하고 실행했다.

 

Count가 닿는 동안 계속 증가하는것을 볼 수 있다.

그렇다면 Exit도 충분히 예상 가능하다.

 

 

3) OnTriggerExit

 

노란색 큐브를 닿는 순간에는 아무일이 일어나지 않지만

큐브를 지나쳐가는(벗어나는) 순간 Count가 올라간다.

 

OnTrigger를 알아봤는데 꼭 설정해 줘야하는것들이 있다.

노란색큐브와 흰색공에는 반드시 충동체크를 할수 있는 Collider가 있어야한다.

 

그리고 두 오브젝트중 하나는 Collider에 is Trigget에 체크가 되어있어야한다.

위 게임같은 경우에는 큐브에 체크가 되어있다. 흰색공에 체크 되어있지 않는 

이유는 is Trigger 가 체크가 되면 흰공에는 Rigidbody에 무게 값을 갖고있기 때문에

땅을 통과해 밑으로 사라져버린다.

 

 (하지만 여기서는 Cube에도 Rigidbody에 UseGravity에 체크되어있는데 땅으로 떨어지지 않고있다. Is Kinematic를 체크 하고있기 때문)

 

 

 

OnCollsion

void OnCollisionEnter(Collision other) : Collision에 들어 갔을 때

void OnCollisionStay(Collision other) : Collision과 충돌하고 있는 중

void OnCollisionExit(Collision other) : Collision과 충동에서 벗어 났을 때

 

 

Trigger와 함수의 기능은 똑같다

OnTrigger : 물리 연산 안함, 관통 가능, Collision 보다 연산이 적어서 효율적

OnCollision : 물리 연산을 통해 충돌 처리, 관통 X, 많이 사용하면 부하?.


여기서 주의할 점은 충돌 할 오브젝트들이 Rigidbody를 갖고 있다면오브젝트 모두 isTrigger가 언체크 되어있어야 하고 또,둘중 한 오브젝트는 Is Kinematic가 언체크 되어 있어야 한다.

 

 

UI기초 : 버튼사용하기


버튼A를 누를때 마다 왼쪽 위 캐릭터모양 ON&OFF하기




1) UI -> Canvas를 만든다. Rect Transform을 사용하기 위해

Rect Transform은 유니티 전체 좌표가 아니다

canvas안에서 기준을 표시한다.(canvas아래 자식 오브젝트들은 부모인 canvas에 로컬좌표에 따라서 설정된다.)


2) UI -> Canvas아래 자식 오브젝트로 Button을 생성한다.


3) 버튼을 클릭 했을때 변화를 주기 위한 스크립트 작성

   public void BtnOnOff()

   {

       bool isview = !gameObject.activeSelf;  //엑티브 상태를 반환한다.(켜져있는지 없는지)

       gameObject.SetActive(isview);

   }

4) UI -> Image 생성 : 변화 될 이미지

5) 작성한 스크립트를 이미지에 추가한다.(버튼이 아닌 이미지에 추가)

6) 버튼 OnClick 컴포넌트

OnClick은 버튼을 클릭 했을때 발동된다.

생성한 Image를 넣어주고 알맞는(BtnOnOff) 함수를 찾아서 설정한다.


완료!

Roll a Ball



Materials 적용하기

Asset에서 빈Materials을 생성한다.

그리고, Texture파일을 빈Materials에 Albedo에 끌어다 놓는다. 


Physic Material

Materials 에 반동을 주거나 마찰력을 주기 위한 Materials 

Component -> Physic Material 생성한다.



Physic Material 인스펙터창을 살펴보자

Dynamic Friction : 이미 이동중일 때 마찰

Static Friction : 정지시 마찰

Bounciness : 반동방식


나는 벽에다 Physic Material를 추가 하고 Bounciness값을 0.5주었다.



그랬더니 ~

볼을 벽에 부딪히면 전과 다르게 튕겨 나온다.

(캐릭터 움직임에는 translate으로 위치값을 변경해주는 방법과

rigdbody를 통해 물리적힘을 줘서 물체를 움직이는 방법이있는데

이 게임은 rb.AddForce (movement * speed); 로 물체에 힘을 줘서 움직이게 하고있다.)





코드분석






코드분석 : PlayerControllers

public으로 변수를 할당하면 유니티 인스펙터창에서 보인다. 변경가능 (값 적용 우선순위 : 인스펙터 > 소스코드창)

speed : 스피드 값

Text CountText; 현재 점수를 불러올 UI 텍스트

Win Text : 승리시 띄울 UI텍스트


void Start ()

{

rb = GetComponent<Rigidbody>();


count = 0;

SetCountText ();

winText.text = "";

}

주요코드

rb = GetComponent<Rigidbody>();

컴포넌트 Rigidbody를 가져와 변수 rb로 정한다.


void FixedUpdate ()

{

float moveHorizontal = Input.GetAxis ("Horizontal");

float moveVertical = Input.GetAxis ("Vertical");


Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);


rb.AddForce (movement * speed);

}

주요코드

rb.AddForce (movement * speed);

Rigidbody를 물리적 힘을 가해 플레이어를 이동시킨다.



void OnTriggerEnter(Collider other)

{

if (other.gameObject.CompareTag ("Pick Up"))

{

other.gameObject.SetActive (false);


count = count + 1;


SetCountText ();

}

}

주요 키워드

CompareTag : 해당하는 태그를 찾는다.

SetActive : 컴포넌트에 토글? 켜고,끄기

OnTriggerEnter: Collider가 다른 트리거 이벤트에 침입했을 때 호출

(지금 위 코드에서는 pick up 태그가 붙은 오브젝트(노란상자)에 Collider가 닿으면 count를 1증가한다.)




Quaternion


쿼터니언이은 회전을 표현하기 위해 사용된다.

복잡한 수를 기반하고 있어 직관적으로 이해하기 쉽지 않다.
그래서 대부분 기존의 회전축을 취하고(즉, Transform으로 부터) 새 회전을 생성하기 위해 사용한다.



  •  Quaternion.LookRotation : 지정된 upwards와 upwards 방향들과 함께 rotation을 생성합니다.

  •  Quaternion.Angle :두개의 roation b와 b 사이의 각도를 반환합니다.

  •  Quaternion.Euler : z축 주위로 z, x축 주위로 x, y축 주위로 y 각도만큼 회전한(순서대로) Rotation을 반환합니다.

  •  Quaternion.Slerp : /from/과 /to/사이를 /t/로 구형보간 합니다

  •  Quaternion.FromToRotation:/fromDirection/에서 /toDirection/으로 회전한 rotation을 생성합니다.

  • Quaternion.identity.: 쿼터니언은 "회전 없음"을 의미합니다. 오브젝트는 완벽하게 월드 좌표 축 또는 부모의 축으로 정렬



쉽게 정리하면 transform.rotation에 대입하기 위한 변수 타입이라고 생각하면 쉽다.

Quaternion.Euler(x: float , y: float, z: float) :오일러는 절대각도를 의미.


ex)

현재 transform.Rotate 값이 (0,10,0) 이다


1) transform.Rotate(0,30,0) (더하기 개념)

=>Rotation에 x,y,z가 0,40,0 //현재 상태에서 증가


2) (transform.rotation=Quaternion.Eular(0,30,0))

=> Rotation에 x,y,z가 0,30,0


Eular는 파라미터로 들어온 벡터의 오일러 값을 쿼터니언으로 바꿔주는 함수이다.







열겨형 Enum 사용법




const 대신 사용하는데 유니티에서 보통 오브젝트의 상태를 구분하여

열거형 타입의 변수를 선언및 할당하여 그 값의 맞는 액션을 취하 도록 한다.


scriptA

public enum eMove_Type { eMove_None, eMove_Normal, eMove_Dash }

public class MoveObj : MonoBehaviour {


   Vector3 vDestPos = new Vector3(7.0f, 1.5f, 1.0f);

   Vector3 vDir;


   public float mfSpeed = 1.5f;

   eMove_Type memove_Type = eMove_Type.eMove_None;



scriptB

eMove_Type mpreType = eMove_Type.eMove_Normal;





캐릭터 회전시키기 :

마우스 이동 시 큐브가 좌우로 움직임


public class PlayerMove : MonoBehaviour {

     

       float rotSpeed = 1.0f; //ADD

// Update is called once per frame

void Update () {

      


       // 마우스 입력

       float MouseX = Input.GetAxis("Mouse X");


       transform.Rotate(Vector3.up * rotSpeed * MouseX);

}

}

transform.Rotate(회전할 기준 좌표 축 * Time.deltaTime * 회전 속도 * 변위 값)

출처:http://itmining.tistory.com/48





위 그림처럼 큐브가  키보드 입력을 받으면 앞,뒤,왼쪽,오른쪽으로 이동하게 만들기




public float speed = 5.0f

    //캐릭터가 움직일 스피드설정 public으로 함으로써 유니티 인스펙터 창에 설정이 가능해짐


void Update () { // 매프레임 반복되기때문에 Update에 써준다.


if(Input.GetKey(KeyCode.UpArrow)) //키보드 위쪽 화살표가 눌릴경우  

{ this.transform.Translate(Vector3.forward * speed * Time.deltaTime); } 

// this(이스크립트를 가지고있는).transform(컴포넌트).Translate(움직을 주는)값을

// Vector3(3D 방항).forward(앞).*speed(속도).*Time.deltaTime(1초당)

if(Input.GetKey(KeyCode.DownArrow))

{ this.transform.Translate(Vector3.back * speed * Time.deltaTime); }

if(Input.GetKey(KeyCode.RightArrow))

{ this.transform.Translate(Vector3.right * speed * Time.deltaTime); }

if(Input.GetKey(KeyCode.LeftArrow))

{ this.transform.Translate(Vector3.left * speed * Time.deltaTime);}



*Delta Time 이전 프레임의 시작 시간과 현재 프레임의 시작 시간의 차이



월드 좌표

-오브젝트의 위치를 나타내는 좌표계로, 화면의 중심을 원점(0,0,0)으로 하는 3차원 상대좌표계 월드 좌표계는 게임 화면을 투영하는 카메라의 위치와 회전 상태에 따라 달라지므로 화면의 중심이 원점이 되는것은 아니다.

쉽게 얘기하면

월드를 기준으로 태양이 우주를 중심으로 0.0.0에 위치라고 하면 내위치를 말하는 것이 월드 좌표다. 


로컬 좌표

자신의 위치를 중심으로 생각하고 각각의 그 오브젝트의 위치에서 어디있는지 계산하는것이다.

만약 부모 객체가 있다면 부모객체의 좌표와의 거리를 나타낸다. 상대좌표라고도 한다.


스크린 좌표

-단말기의 화면 좌표계로, 화면의 왼쪽 아래를 원점으로 하는 평면 절대좌표계 마우스 클릭이나 터치는 스크린 좌표계를 이용해서 처리한다. 카메라의 위치나 각도와 상관없이 일정


뷰 포트 좌표

  • 화면에 글자나 2D이미지를 표시하기 위한 좌표계로, 화면의 왼쪽 아래를 (0,0)오른쪽 위를(1,1)로 하는 평면 상대 좌표계이다.


출처 :​ http://hyunity3d.tistory.com/m/post/368

break 키워드


조건문 또는 반복문을 벗어날 때에 사용하는 키워드입니다.


ex)


while (true)

{

Console.writeLine("무한반복문");

}


위 예같은 경우 계속 while문 안에있는 문장을 반복해서 출력하겠죠??


ex)

while (true)

{

Console.WriteLine("숫자를 입력해주세요(홀수를 입력하면 종료):");

int input = int.Parse(Console.ReadLine());


if (input % 2 == 1)

{

break;

}

}


이 예제는 어때요??

짝수를 입력하면 계속 실행하고

홀수를 입력하면 if문을 통해 break키워드가 실행되면서 바로 종료가 됩니다.




continue 키워드


반복문 내부에서 현재 반복을 멈추고 다음 반복을 진행하는 키워드입니다.


ex)

for(int i=1; i<=10; i++)

{

if(i%2==0)

{

continue; //짝수이면 다음 반복문으로 넘어갑니다. 아래코드 실행X

}

Console.WriteLine(i);

}


break문과 continue문을 활용하여 반복,조건문을 잘 활용 하시면 되겠습니다~

하지만 너무많은 사용은 코드의 가독성과 유지보수가 좋지 않기 때문에

남용은 좋지 않다고 하네요~





여러분들 PRG게임 좋아하시나요??


RPG게임이란



Role Playing Game

유저가 게임 속 캐릭터들을 연기하며 즐기는 역할 수행게임! 

(네이버지식백과)



게임속 자신의 캐릭터를 육성하는 게임이죠!



RPG중에서도

여전히 사랑받는 게임


로그라이크(Rogue - like) 형식

게임을 제작중입니다.


로그라이크를 잘모르시는 분들이 있으시겠죠??

저도 제작하기 전까지는 몰랐습니다 .ㅎ.ㅎ


간단히 설명 드리자면


1980년대에 캘리포니아에서 대학을 다니던 세 학생이

한 게임을 개발합니다. 이름하여 Rogue

세련미는 떨어지는 다소 투박한 게임이지만

신선한! 게임플레이를 선보이며 당시 큰 반응을 일으켰답니다.


큰 특징으로는,

1. 하나로 연결된 방대한 던전세계

2. 죽으면 처음으로 시작하는 무자비한 시스템

3. 무작위로 생성되는 시스템


여러 게이머의 도전 정신을 자극하게 되는데요


이 게임 인기를 끌다보니 당연히 파생된

게임들이 나오기 시작했답니다. 

(itunes.apple.com참조)



그리하여  Rogue를 닮았다고 해서 

'로그라이크' 입니다.

+ Recent posts