중력가속도 점프 Jump

Unity3D 2020. 5. 27. 14:57
반응형

1. 게임 소개

 

이 게임은 올빼미가 나뭇가지를 밟고 점프해서 위로 높이 올라가는 것을 목적으로 하는 2D 게임입니다. 사용자는 좌우 이동키(모바일에서는 자이로 센서)로 올빼미를 좌우로 이동해서 옆에 있는 나뭇가지로 날아가야 합니다.

 

 

올빼미가 나뭇가지를 밟으면 위로 점프하며, 점프 후에는 중력에 의해 추락합니다. 따라서 올빼미가 추락하기 전에 옆의 나뭇가지를 밟아야 다시 점프할 수 있습니다.

 

 

 

 

 

완성된 게임은 아래 사이트에서 웹게임으로 테스트해 볼 수 있습니다.

 

 

Flying Owl : http://afterglow.co.kr/wordpress/wp-content/uploads/unity_games/Owl_Web/Owl_Web.html

 

 

 

2. 게임의 요구 사항

 

게임을 개발할 때에는 명확한 가이드라인을 정해두고 시작해야 나중에 중복과 혼란이 없습니다. 우리도 게임의 가이드라인을 개략적으로 정해둡시다.

 

 

 사용자는 올빼미를 좌우로만 이동할 수 있으며, 올빼미는 화면을 벗어날 수 없다.

 올빼미가 나뭇가지를 밟으면 위로 점프하며, 시간이 지나면 중력에 의해 추락한다.

   ③ 올빼미가 올라가는 높이에 따라 점수가 부여된다.

 랜덤하게 나타나는 선물을 획득하면 보너스 점수가 주어지며, 날아가는 참새와 충돌하면 감점이다

   ⑤ 화면 위에 득점, 올빼미의 높이, 획득한 보너스의 수를 표시한다.

 올빼미가 점프할 때 카메라가 함께 이동해서 올빼미가 화면 위로 사라지지 않도록 한다.

 참새는 화면 왼쪽에서 오른쪽으로 날아가며 올빼미와 충돌하면 아래로 추락한다.

 올빼미가 선물이나 참새와 충돌할 때 득점 및 감점을 1~2초간 표시한 후 사라진다.

 게임 실행 중에는 커서가 나타나지 않으며, 게임 오버가 되면 커서가 나타난다.

 이 게임은 PC, Web 및 모바일 단말기에서 각각 독립적으로 실행할 수 있도록 제작한다.

 PC  Web 게임은 키보드로 올빼미를 이동하고, 모바일 기기는 단말기를 좌우로 기울여서 이동한다(자이로 센서 사용). - 추후 버튼으로 이동하는 기능을 추가한다.

   ⑫ 게임의 배경화면은 오른쪽에서 왼쪽으로 천천히 스크롤된다.

 

 

요구사항이 많아 보이지만 올빼미에 대한 것만 요약하면 다음과 같이 정리할 수 있겠네요.

 

 

   ① 사용자는 올빼미를 좌우로만 이동할 수 있다.

   ② 올빼미의 점프와 추락은 자동으로 처리한다.

   ③ 올빼미가 나뭇가지를 밟았는지를 판정해야 한다.

   ④ 올빼미와 선물 및 참새와 충돌 판정이 필요하다.

 

 

 

 

3. 가속도와 중력

 

먼저 올빼미가 점프하는 것을 생각해 봅시다. 물체의 이동은 등속 운동과 가()속 운동으로 구분할 수 있습니다. 등속운동은 날아가는 총알처럼 일정한 속도로 이동하는 것이고, ()속 운동은 자동차 가속 페달을 밟을 때 ~’하고 속도가 빨라졌다 브레이크를 밟으면 끼익~’하고 천천히 멈추는 운동입니다.

 

 

등속운동은 거리=속도×시간으로 나타낼 수 있으므로 간단하게 처리할 수 있지만 가속도 운동은 좀 더 복잡해서 일반적으로 다음과 같은 공식을 사용합니다.

 

    

   

    S : 현재속도, v : 초속도, t : 시간, a : 가속도(토크, 중력, 저항 등)

 

 

올빼미가 점프하고 추락할 때 등속 운동을 하면 로봇과 같이 아주 기계적인 움직임이 되어 현실감이 떨어질 것입니다. 따라서 올빼미의 점프와 추락은 중력을 고려한 가속 운동을 구현해야 합니다. 근데, 이걸 어케 코딩하나... ~~

 

 

우선 포물선 운동을 하는 예를 들어보겠습니다. 대포에서 발사된 포탄은 포물선 궤도를 비행하는데, 포탄의 궤적은 다음과 같은 식으로 구할 수 있습니다.

 

 

 

    

     h : 포탄의 높이, v : 초속, t : 시간, θ : 발사각도, G : 중력가속도 상수 9.8

 

     

     d : 포탄의 비행 거리

 

 

, 포탄은 높이 방향으로는 가()속 운동을 하며, 거리 방향으로는 등속 운동을 합니다. 그러므로 우리 게임의 주인공 올빼미는 위의 포탄과 같이 포물선 궤도로 운동하도록 처리해야 할 것입니다.

 

 

 

 

4. 포탄의 궤적을 표시하는 프로젝트

 

포물선 운동의 원리를 이해하기 위해 위의 공식을 활용해서 포탄의 궤적을 표시하는 간단한 프로젝트를 만들어 보겠습니다. 수평선과 60°의 각도, 초속 50m의 속도로 발사한 포탄의 궤적을 0.1초 간격으로 화면에 표시하는 프로그램입니다.

 

 

 새로운 프로젝트 시작

     적당한 이름으로 새로운 프로젝트를 하나 만듭니다. 저는 프로젝트 이름을 Gravity로 했습니다.

 

 

 Game Object 설치

     Scene 뷰에 Sphere를 한 개 설치하고 Position (0, 0, 0)으로 설정합니다. Game 뷰가 조금 밝아지도록 

     Directional Light도 하나 추가하세요.

 

 

 Sphere를 프리팹으로 만들기

     Project 뷰에 폴더를 하나 만들고(이름을 Prefabs로 하였습니다) Scene 뷰의 Sphere Prefabs 폴더로 끌

     고 와 프리팹으로 만듭니다.

 

 

 

 

 카메라 설정

     공이 Game 뷰의 오른쪽 아래에 보이도록 카메라의 Position (110, 42, -100)으로 설정합니다.

 

 

 GameManager 설치

    [GameObjectCreate Empty] 메뉴를 이용해서 빈 오브젝트를 하나 만든 후 이름을 GameManager로 

     바꿉니(굳이 바꾸지 않아도 문제가 되지는 않습니다).

 

 

 스크립트 작성

    다음 스크립트를 작성한 후 Ball.cs로 저장합니다.

 

 

 

using UnityEngine; using System.Collections; public class Ball : MonoBehaviour { public GameObject ball; // 공 float v = 50; // 초속도 float th = 60; // 발사각도 float t = 0; // 시간 float g = 9.80665f; // 중력가속도 상수 float h = 0; // 높이 float d = 0; // 거리 // Update is called once per frame void Update () { if (h < 0) return; float r = th * Mathf.Deg2Rad; // 각도를 라디안으로 변환 h = v * t * Mathf.Sin(r) - 0.5f * g * t * t; d = v * t * Mathf.Cos(r); Vector3 pos = new Vector3(d, h, 0); Instantiate(ball, pos, Quaternion.identity); t += 0.1f; // 0.1초 단위로 계산 } }

 

 

 

 GameManager에 스크립트 연결

    GameManager에 앞에서 작성한 스크립트를 연결한 후 변수 ball 에서 프리팹으로 만들어 둔 Sphere

    를 설정합니다.

 

 

 

 

 

 

 게임 실행

    이제 게임을 실행하면 다음과 같은 포물선 궤적이 나타나는 것을 확인할 수 있을 것입니다.

    

 

 

 

5. 오브젝트에 중력 가속도 적용하기

 

 

위에서 사용한 수식은 삼각함수를 사용하므로 수학을 잘 모르는 경우에는 사용하기 곤란한 점이 있습니다. 게다가 위의 수식은 지구의 중력 가속도(9.8)에 특화되어 있으므로 우주인이 달표면에서 슬로우 모션으로 겅충겅충 뛰는 것과 같은 부드러운 동작을 표현하기에는 조금 부족합니다(물론 중력 가속도 상수를 작게 하면 가능할 것입니다).

 

 

그래서 수식을 조금 더 간단하게 만들도록 하죠. 먼저 맨 처음 사용한 가속도 운동 공식을 주목하시기 바랍니다.

 

 

    

    S : 현재속도, v : 초속, t : 시간, a : 가속도(토크, 중력, 저항 등)

 

 

위의 식에서 a가 가속도인데 이 값을 아예 절반으로 설정하는 것으로 하면 다음과 같은 식을 구할 수 있습니다.

 

   S = (v + at) t

 

 

게임에서의 가속도는 결국 캐릭터가 점프할 때 작용하는 중력이므로 가속도가 음수(-)가 되어 위의 식은

 

 

   S = (v - at) t

 

 가 될 것입니다. 시간 t는 유니티가 제공해주므로 결국 점프 속도 v와 중력 가속도 상수 a만 적절히 설정해 주면 부드럽게 점프하는 동작을 구현할 수 있습니다. 물론 좌우로 이동하는 동작은 키를 입력받아 처리합니다.

 

 

 

 

6. 오브젝트 움직이기

 

 

위의 식을 기초로 해서 앞에서 만들어 둔 공(Sphere)을 좌우로 이동하고 점프하는 프로그램을 만들어 보겠습니다. 앞에서 만들어 둔 프로젝트에 추가합니다.

 

 

 새로운 Scene 만들기

     현재의 씬을 저장(저는 Gravity1로 저장했습니다)한 후 새로운 씬을 만듭니다.

 

 

 Object 설치

     Scene 뷰에 프리팹으로 만들어 둔 Sphere Directional Light를 하나 설치합니다.

 

 

 Script 작성

    다음 스크립트를 작성한 후 Ball2로 저장하고  Sphere에 연결합니다.

  

 

using UnityEngine; using System.Collections; public class Ball2 : MonoBehaviour { int speedSide = 6; // 좌우 이동속도 int speedJump = 16; // 점프속도 int gravity = 30; // 중력 Vector3 dir = Vector3.zero; // 상하좌우 이동방향 // Update is called once per frame void Update () { // Jump if (Input.GetKeyDown(KeyCode.Space)) { // 점프 키를 누르면 dir.y = speedJump; // 점프속도 설정 } // 좌우 이동 방향과 속도 설정 dir.x = Input.GetAxis("Horizontal") * speedSide; // 점프 속도에 중력 적용 dir.y -= gravity * Time.deltaTime; // 점프속도를 중력*t 만큼 감소 // 오브젝트 이동 transform.Translate(dir * Time.smoothDeltaTime); // 화면 아래를 벗어나지 않도록 조치 Vector3 pos = transform.position; if (pos.y < -3) { pos.y = -3; transform.position = pos; } } }

 

 

 

위의 스크립트에서 눈여겨 볼 것은 speedJump(점프속도) gravity(중력)입니다. 점프속도가 작고 중력이 크면 폴짝거리면서 뛰는 동작이 되고, 반대로 점프속도가 크고 중력이 작으면 겅충겅충 뛰는 동작이 될 것입니다.

 

 

점프 동작을 자연스럽고 부드럽게 구현하려면 중력을 점프속도의 1.5~2 정도로 설정하면 되는데, 이것은 게임마다 달라질 것이므로 값을 바꿔가면서 테스트해서 가장 적당한 값을 찾아야 합니다.

 

 

결국 좌우 이동과 중력에 의한 추락을 구현하는 것은 다음의 3문장이므로 이것만 잘 알아두면 복잡한 삼각함수에서 해방될 수 있습니다.

   

 

dir.x = Input.GetAxis("Horizontal") * speedSide; dir.y -= gravity * Time.deltaTime;  

transform.Translate(dir * Time.smoothDeltaTime);

 

 게임 실행

이제 게임을 실행하면 [A][D] 키로 공을 좌우로 이동하고, [Space] 키로 공을 점프할 수 있습니다. 게임의 실행 화면을 동영상으로 만들어 두었으니 참고하시기 바랍니다.

 

 

  •  

 

2. Flying Owl_1 게임의 개요 및 중력가속도 처리

재생 수819

 

 

 

 

 

 

 

 

  

화질 선택 옵션480p

 

 

 

 

 

 

 

 

 

 

7. 오브젝트가 화면의 좌우를 벗어나지 않도록 처리

 

위의 프로젝트를 실행하고 좌우 이동키를 계속 누르고 있으면 공이 화면의 좌우를 빠져나가버립니다. 이젠 위의 스크립트에 공이 화면의 가장자리에 왔을 때는 키입력을 받지 않도록 하는 기능을 추가할 것입니다.

 

공이 화면의 가장자리에 있을 때에는 키입력을 받지 않도록 하면 되는데, 문제는 디바이스의 화면 크기가 서로 다르다는 점이 있습니다. 따라서 공의 절대 좌표(position)으로는 공이 화면 가장자리에 있는지를 판정할 수가 없습니다. 예를 들어 A 디바이스의 화면폭과 B 디바이스의 화면폭이 서로 다르다면 어느 디바이스를 기준으로 판정해야 되는 걸까요?

 

따라서 게임 화면의 World 좌표를 절대좌표인 Screen 좌표계로 변환하는 과정이 필요합니다. Screen 좌표계는 디바이스의 화면을 픽셀 단위로 표시하므로 스크린 좌표계를 사용하면 공이 화면의 가장자리에 가까워졌는지를 알아낼 수 있습니다. 유니티의 좌표계를 잘 모르시는 분은 다음 강좌를 참조하세요.

 

    유니티의 좌표계 http://blog.naver.com/foxmann/90179156609

 

 

위의 스크립트에 다음과 같이 화면의 가장자리를 판정하는 부분을 추가합니다.

    

 

// Update is called once per frame void Update () { // Jump if (Input.GetKeyDown(KeyCode.Space)) { // 점프 키를 누르면 dir.y = speedJump; // 점프 속도 설정 } // World 좌표를 Screen 좌표로 변환 Vector3 view = Camera.main.WorldToScreenPoint(transform.position); dir.x = 0; // 이동 방향 초기화 float key = Input.GetAxis("Horizontal"); // 키 압력 -1.0 ~ +1.0 // 키를 눌렀을 때 공이 화면의 가장자리가 아니면 이동 if ((key < 0 && view.x > 30) || (key > 0 && view.x < Screen.width - 30)) { dir.x = key * speedSide; } // 점프 속도에 중력 적용 dir.y -= gravity * Time.deltaTime; // 점프 속도를 중력*t 만큼 감소

......... 이하 변경없음 .............. } 

 

위의 스크립트에서 Camera.main 태그 MainCamera인 카메라를 의미하는 것으로 유니티가 기본으로 제공하는 Main Camera는 태그가 MainCamera로 되어 있습니다. 월드 좌표를 스크린 좌표로 바꾸는 것은 현재 오브젝트를 바라보고 있는 카메라의 시점이 기준이라는 것을 기억해 두시기 바랍니다. 

 

이제 게임을 실행하고 좌우 이동키로 공을 이동해 보면 화면의 해상도와 상관없이 화면을 벗어나지 않는 것을 알 수 있습니다. 

 

 

  •  

 

2. Flying Owl_1 게임의 개요 및 중력가속도 처리

재생 수373

 

 

 

 

 

 

 

 

  

화질 선택 옵션480p

 

 

 

 

 

 

 

 

이것으로 이번 강좌를 마치겠습니다. 캐릭터의 점프와 이동, 화면을 벗어나게 하지 않는 방법을 알았으므로 다음 강좌는 실제로 게임을 만들어 가는 과정에 대해 알아볼 것입니다.

 

모두들 유니티로 대박나는 게임을 만드는 그날까지 홧팅~

반응형
: