반응형


화면과 같이 유니티 엔진으로 무한 점프 게임을 만들어 보겠습니다



제작게임 해보기 :  Google Play  





Game 씬 화면을 16:9 맞춤니다



Scene 폴더를 만들고 씬을 생성하여 이름을 MainGame이라 합니다



Texture 폴더를 만들고 그림 리소스를 드래그 하여 폴더 안에 넣습니다


  

Audio폴더를 만들고  드래그 하여 사운드 리소스를 넣습니다



MainCamera를 선택하여 그림과 같이 맞춤니다


Sky 텍스쳐를 선택하고 그림과 같이 속성을 바꿈니다


Hierarchy에 Quad를 생성 하여 이름을 Sky라 합니다



Materials폴더를 만들고 Material를 생성하여 Sky라 이름을 붙힙니다


Hierarchy에  Sky를 선택하고 만든 Material을 드래그 하여 붙히고 Shader -> Unlit -> Texture

를 선택합니다 



Select창에 sky Texture를 붙힙니다


Sky 오브젝트를 MainCamera자식으로 이동 합니다

그리고 그림과 같이 스케일과 포지션을 바꿉니다



Scripts폴더를 생성하고 SkyCtrl 스크립트를 생성하여 넣습니다


SkyCtrl 스크립트 작성

Sky를 배경으로 하여 배경 스크롤 하는 오브젝트를 짭니다



using System.Collections;

using System.Collections.Generic;

using UnityEngine;


public class SkyCtrl : MonoBehaviour {


    float speed = 0.03f;


    //------------------------------

    // 화면 스크롤

    //------------------------------

    void Update()

    {

        float ofsX = speed * Time.time;

        transform.GetComponent<Renderer>().material.mainTextureOffset = new Vector2(ofsX, 0);

    }

}




SkyCtrl 스크립트를 Sky 오브젝트에 드래그하여 붙힙니다



배경이 좌로 스크롤 되는 것을 확인합니다


Jump_tile 텍스쳐를 선택하여 그림과 같이 속성을 바꿉니다



Jump_tile 텍스쳐를 선택하여 Hierarchy창에 드래그하여 놓고 이름을 Tile 로 바꿉니다


Tile 오브젝트를 선택하여 Tag를 Tile을 생성하여 선택하고 Layer를 Tile를 만들어 선택합니다




TilCtrl 스크립트를 만들어 저장합니다


TilCtrl 스크립트 작성

그림과 같이 Camera 시선에 좌표를 만들어 화면에 벗어나면 삭제되는 스크립트를 작성합니다


using System.Collections;

using System.Collections.Generic;

using UnityEngine;


public class TilCtrl : MonoBehaviour {


    //-------------------

    // 화면 아래를 벗어나면 제거

    void Update()

    {

        // 월드 좌표를 스크린 좌표로 변환 

        Vector3 view = Camera.main.WorldToScreenPoint(transform.position);

        if (view.y < -50)

        {

            Destroy(gameObject);

        }

    }

}




Tile오브젝트에 Tile스크립틀 붙힙니다


Tile 오브젝트를 Prefabs폴더에 드래그하여 프리팹을 만듭니다



tile Sorting Layers tile 을 만들고 선택합니다 Sorting Layer는 아래로 선택할수록 텍스쳐가 위로 보이는 기능입니다 


Hierarchy 창에 Tile 오브젝트를 하나더 만들어서 포지션을 조금 높게 설정하여 저장합니다



rabbit_jump2 텍스쳐를 선택하여 드래그하여 Hierarchy창에 올리고 이름을 Player라 합니다

 

Sorting Layer를 Player를 만들어 선택합니다



 MainCamera를 선택하여 빈 오브젝트를 만들고 이름을 spPoint 라고 하고 포지션을 그림과 같이 합니다


Player를 선택하고 그림과 같이 자식으로 오브젝트를 만들어 StartPos 와 EndPos 이름을 붙힙니다  


그림과 같이 오브젝트포지션을 Player 발끝에 EndPos 를 놓고  바로 위에 StartPos를 놓습니다



Player를 선택하고 Audio Source를 붙힙니다


PlayerCtrl스크립트를 만들고 PlayerCtrl 스크립트를 작성합니다


PlayerCtrl 스크립트 작성




using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;


public class PlayerCtrl : MonoBehaviour {


    public Transform tile;

    public Transform startPos;

    public Transform endPos;


    public AudioClip sndJump;        // 효과음 및 배경음악 

    public AudioClip sndGift;

    public AudioClip sndBird;

    public AudioClip sndStage;

    public AudioClip sndOver;


    Transform spPoint;

    Transform newTile;

    float maxY = 0;


    int speedSide = 10;              // 좌우 이동 속도 

    int speedJump = 16;             // 점프 속도 

    int gravity = 25;                  // 추락 속도 


    Vector3 moveDir = Vector3.zero;


    bool isDead = false;

    Animator anim;

    public Button retryGame;



    void Start()

    {

        anim = GetComponent<Animator>();


        // 모바일 단말기 설정

        Screen.orientation = ScreenOrientation.LandscapeRight;

        Screen.sleepTimeout = SleepTimeout.NeverSleep;


        spPoint = GameObject.Find("spPoint").transform;


        // Tile 만들기 

        newTile = Instantiate(tile, spPoint.position, spPoint.rotation) as Transform;


        //Cursor.visible = false;     // 커서 감추기 

        retryGame.gameObject.SetActive(false);

    }


    //-------------------

    // 게임 루프

    //-------------------

    void Update()

    {

        if (isDead) return;

        JumpPlayer();          // Player 점프

        MovePlayer();          // Player 이동 

        MoveCamera();          // 카메라 이동 

      

    }



    //-------------------

    // Player 점프

    //-------------------

    void JumpPlayer()

    {

        RaycastHit2D hit;

        hit = Physics2D.Linecast(startPos.position, endPos.position, 1 << LayerMask.NameToLayer("Tile"));


        if (hit)

        {

            moveDir.y = speedJump;

            AudioSource.PlayClipAtPoint(sndJump, transform.position);

        }

    }


    //-------------------

    //  Player 이동

    //-------------------

    void MovePlayer()

    {

        Vector3 view = Camera.main.WorldToScreenPoint(transform.position);


        if (view.y < -50)

        {       // 화면 아래를 벗어나면  

            isDead = true;      // 게임 오버 

            GameOver();

            return;

        }


        moveDir.x = 0;      // Player의 좌우 이동 방향


        // Mobile 처리 

        if (Application.platform == RuntimePlatform.Android ||

            Application.platform == RuntimePlatform.IPhonePlayer)

        {

            // 중력 가속도 센서 읽기 

            float x = Input.acceleration.x;


            // 왼쪽으로 기울였나?

            if (x < -0.2f && view.x > 35)

            {

                moveDir.x = 2 * x * speedSide;

            }


            if (x > 0.2f && view.x < Screen.width - 35)

            {

                moveDir.x = 2 * x * speedSide;

            }


        }

        else

        {   // Keyboard 읽기 

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

            if ((key < 0 && view.x > 35) ||

                (key > 0 && view.x < Screen.width - 35))

            {

                moveDir.x = key * speedSide;

            }

        }


        // 매 프레임마다 점프 속도 감소

        moveDir.y -= gravity * Time.deltaTime;

        transform.Translate(moveDir * Time.smoothDeltaTime);



        //애니메이션 설정

        if (moveDir.y > 0)

        {

            anim.Play("PlayerJump");

        }

        else

        {

            anim.Play("PlayerIdle");

        }

    }


    void MoveCamera()

    {

        // Player 최대 높이 구하기 

        if (transform.position.y > maxY)

        {

            maxY = transform.position.y;


            // 카메라 위치 이동 

            Camera.main.transform.position = new Vector3(0, maxY - 2.5f, -10);

           // score = (int)maxY * 1000;

        }


        // 가장 최근의 Tile과 spPoint와의 거리 구하기

        if (spPoint.position.y - newTile.position.y >= 4)

        {

            float x = Random.Range(-10f, 10f) * 0.5f;

            Vector3 pos = new Vector3(x, spPoint.position.y, 0.3f);

            newTile = Instantiate(tile, pos, Quaternion.identity) as Transform;


            // 나뭇가지의 회전방향 설정 

            int mx = (Random.Range(0, 2) == 0) ? -1 : 1;

            int my = (Random.Range(0, 2) == 0) ? -1 : 1;

            newTile.GetComponent<SpriteRenderer>().material.mainTextureScale = new Vector2(mx, my);

        }

    }


    //게임 오버 설정

    void GameOver()

    {

         retryGame.gameObject.SetActive(true);

        if (GetComponent<AudioSource>().clip != sndOver)

        {

            GetComponent<AudioSource>().clip = sndOver;

            GetComponent<AudioSource>().loop = false;

            GetComponent<AudioSource>().Play();

        }

    }

    // 재시작 

    public void RetryGame()

    {


        Application.LoadLevel("MainGame");

    }


}





Player를 선택하고 Animation을 만든다


Create New Clip 으로 들어가 PlayerIdle 만들고 저장하고 그림과 같이 rabbit_jump2 텍스쳐를 드래그하여 애니메이션을 만든다



Create New Clip 으로 들어가 PlayerJump 이름을 만들고 저장하고 그림과 같이 rabbit_jump 텍스쳐를 드래그하여 애니메이션을 만든다


Main Camera 자식으로 한 Canvas 를 만들어 

Button 을 만듭니다



Canvas 의 설정을 그림과 같이 합니다


Button 밑에 있는  Text 도 그림과 같이 속성을 합니다



버튼 크기를 적당히 그림과 같이 배치하고 크기를 조절합니다


Player 오브젝트에 PlayerCtrl스크립트를 연결하고 그림과 같이 오브젝트들을 연결합니다



Tile은 프리팹으로 연결합니다 


게임을 실행합니다

영상과 같이 캐릭터가 올라가면 됩니다



bird 스프라이트 하나를 드래그 하여 Hierarchy 창에 올리고 이름을 Bird하 합니다


만든  Bird 오브젝트에 Animation 을 열고  BirdFly  애니메이션 이름을 만들고 bird_107*92*0 ~ 5 스프라이트를 드래그 하여 Animation창에 올려 놓습니다



Bird 오브젝트를 선택하여 Tag를 Bird 를 만들어 선택하고 Sorting Layer를 bird 를 만들어 선택합니다

그리고 Box Coillder2D를 붙힙니다


BirdCtrl 스크립트를 만들어 붙힙니다


BirdCtrl 스크립트 작성



using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;


public class BirdCtrl : MonoBehaviour {


    public Transform txtScore;  // 프리팹 

    int speed;                  // 이동 속도 

    bool isDrop = false; // Use this for initialization


    Animator anim;


    private void Awake()

    {

        anim = transform.GetComponent<Animator>();

    }


    void Update()

    {

        speed = Random.Range(3, 7);


        float amtMove = speed * Time.smoothDeltaTime;


        if (!isDrop)

        {

            AnimateBird();

            transform.Translate(Vector3.right * amtMove);

        }

        else

        {           // 아래로 이동 

            transform.Translate(Vector3.down * amtMove, Space.World);

        }


        // 화면을 벗어난 오브젝트 제거 

        Vector3 view = Camera.main.WorldToScreenPoint(transform.position);

        if (view.y < -50 || view.x > Screen.width + 50)

        {

            Destroy(gameObject);

        }


    }


    void AnimateBird()

    {

        anim.Play("BirdFly");

    }


    void DropBird()

    {

        isDrop = true;


        // 참새 회전 

        transform.eulerAngles = new Vector3(0, 0, 180);


        // 감점 표시 

        Transform obj = Instantiate(txtScore) as Transform;

        obj.GetComponent<Text>().text = "<color=red><size=22>-1000</size></color>";


        // World 좌표를 Viewport 좌표로 변환 

        var pos = Camera.main.WorldToViewportPoint(transform.position);

        obj.position = transform.position;

    }

    // Update is called once per frame

}




스크립트를 작성하고 Bird 프리팹을 만들어 저장합니다 Hierachy 창에 Bird는 삭제합니다


Canvas 자식으로 Text 를 만들고 이름을 TextCtrl이라 하고속성을 그림과 같이 합니다



TextCtrl 스크립트를 만들고 TextCtrl 오브젝트에 붙힙니다


TextCtrl 오브젝트를 Canvas 자식에서 빼냅니다



TextCtrl 오브젝트의 Scale을 변경 하지마시고 TextCtrl 오브젝트를 프리팹을 만들고 Hierarchy창에 있는 TextCtrl을 삭제합니다


Bird 오브젝트를 선택하고 TextCtrl 프리팹을 txtScore에 붙힙니다



gift1 스트라이트를 선택 드래그 하여 Item1오브젝트를 만듭니다


Item1오브젝트를 선택하여 Tag를 Item1 정하고 Sorting Layer를 Item을 만들어 선택합니다

그리고 BoxCoillder2D를 붙힙니다


ItemCtrl 스크립트 작성



using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;


public class ItemCtrl : MonoBehaviour {


    public Transform txtScore;      // 프리팹 


    //-------------------

    // 화면을 벗어난 Gift 제거

    //-------------------

    void Update()

    {

        // World 좌표를 Screen 좌표로 변환 

        Vector3 view = Camera.main.WorldToScreenPoint(transform.position);

        if (view.y < -50)

        {

            Destroy(gameObject);

        }

    }

    //-------------------

    // 점수 표시 - 외부 호출 

    //-------------------

    void DisplayScore(int n)

    {

       

        // 점수 표시용 UIText 만들기 

        Transform obj = Instantiate(txtScore, transform.position, Quaternion.identity) as Transform;

        obj.GetComponent<Text>().text = "+" + n * 500;


        // World 좌표를 Viewport 좌표로 변환 

        var pos = Camera.main.WorldToViewportPoint(transform.position);

        // obj.position = pos;


        // Gift 제거 

        Destroy(gameObject);

    }

}




작성한 스크립트를 Item1에 붙히고 TextCtrl 프리팹을 연결합니다


Item2를 만들어 그림과 같이 합니다



Item3를 만들어 그림과 같이 합니다


Canvas에 Text 3개를 만들어 이름을 그림과 같이 하고 속성을 그림과 같이 합니다



Scene 창에 그림과 같이 대략 적절한 크기와 위치 색깔로 맞춤니다 




PlayerCtrl 스크립트를 그립과 같이 수정합니다


PlayerCtrl 스크립트 수정



using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using UnityEngine.UI;


public class PlayerCtrl : MonoBehaviour

{

    public Text tScore;          //점수,높이 ,아이템갯수 

    public Text tHeight;

    public Text tItem;


    public Transform tile;        // 프리팹 

    public Transform[] item;

    public Transform bird;


  

    public Transform startPos;

    public Transform endPos;


    public AudioClip sndJump;       // 효과음 및 배경음악 

    public AudioClip sndGift;

    public AudioClip sndBird;

    public AudioClip sndStage;

    public AudioClip sndOver;


    Transform spPoint;

    Transform newTile;

    float maxY = 0;

    int giftCnt = 0;                // 획득한 선물 수 

    int score = 0;                // 득점 


    int speedSide = 10;             // 좌우 이동 속도 

    int speedJump = 16;             // 점프 속도 

    int gravity = 25;               // 추락 속도 


    Vector3 moveDir = Vector3.zero;

 

    bool isDead = false;

    Animator anim;

    public Button retryGame;



    void Start()

    {

        anim = GetComponent<Animator>();


        // 모바일 단말기 설정

        Screen.orientation = ScreenOrientation.LandscapeRight;

        Screen.sleepTimeout = SleepTimeout.NeverSleep;


        spPoint = GameObject.Find("spPoint").transform;


        // Tile 만들기 

        newTile = Instantiate(tile, spPoint.position, spPoint.rotation) as Transform;


        //Cursor.visible = false;     // 커서 감추기 

        retryGame.gameObject.SetActive(false);

    }


    //-------------------

    // 게임 루프

    //-------------------

    void Update()

    {

        if (isDead) return;

        JumpPlayer();          // Player 점프

        MovePlayer();          // Player 이동 

        MoveCamera();          // 카메라 이동 

        MakeItem();

        UIText();

    }



    //-------------------

    // Player 점프

    //-------------------

    void JumpPlayer()

    {

        RaycastHit2D hit;

        hit = Physics2D.Linecast(startPos.position, endPos.position, 1 << LayerMask.NameToLayer("Tile"));


        if (hit)

        {

            moveDir.y = speedJump;

            AudioSource.PlayClipAtPoint(sndJump, transform.position);

        }

    }


    //-------------------

    //  Player 이동

    //-------------------

    void MovePlayer()

    {

        Vector3 view = Camera.main.WorldToScreenPoint(transform.position);


        if (view.y < -50)

        {       // 화면 아래를 벗어나면  

            isDead = true;      // 게임 오버 

            GameOver();

            return;

        }


        moveDir.x = 0;      // Player의 좌우 이동 방향


        // Mobile 처리 

        if (Application.platform == RuntimePlatform.Android ||

            Application.platform == RuntimePlatform.IPhonePlayer)

        {

            // 중력 가속도 센서 읽기 

            float x = Input.acceleration.x;


            // 왼쪽으로 기울였나?

            if (x < -0.2f && view.x > 35)

            {

                moveDir.x = 2 * x * speedSide;

            }


            if (x > 0.2f && view.x < Screen.width - 35)

            {

                moveDir.x = 2 * x * speedSide;

            }


        }

        else

        {   // Keyboard 읽기 

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

            if ((key < 0 && view.x > 35) ||

                (key > 0 && view.x < Screen.width - 35))

            {

                moveDir.x = key * speedSide;

            }

        }


        // 매 프레임마다 점프 속도 감소

        moveDir.y -= gravity * Time.deltaTime;

        transform.Translate(moveDir * Time.smoothDeltaTime);



        //애니메이션 설정

        if (moveDir.y > 0)

        {

            anim.Play("PlayerJump");

        }

        else

        {

            anim.Play("PlayerIdle");

        }

    }


    void MoveCamera()

    {

        // Player 최대 높이 구하기 

        if (transform.position.y > maxY)

        {

            maxY = transform.position.y;


            // 카메라 위치 이동 

            Camera.main.transform.position = new Vector3(0, maxY - 2.5f, -10);

           // score = (int)maxY * 1000;

        }


        // 가장 최근의 Tile과 spPoint와의 거리 구하기

        if (spPoint.position.y - newTile.position.y >= 4)

        {

            float x = Random.Range(-10f, 10f) * 0.5f;

            Vector3 pos = new Vector3(x, spPoint.position.y, 0.3f);

            newTile = Instantiate(tile, pos, Quaternion.identity) as Transform;


            // 나뭇가지의 회전방향 설정 

            int mx = (Random.Range(0, 2) == 0) ? -1 : 1;

            int my = (Random.Range(0, 2) == 0) ? -1 : 1;

            newTile.GetComponent<SpriteRenderer>().material.mainTextureScale = new Vector2(mx, my);

        }

    }

    void MakeItem()

    {

        if (Random.Range(1, 1000) < 990) return;


        // 오브젝트 표시 위치 

        Vector3 pos = Vector3.zero;

        pos.y = maxY + Random.Range(4, 5.5f);


        if (Random.Range(0, 100) < 50)

        {

            // 참새 만들기 

            pos.x = -12f;

            Instantiate(bird, pos, Quaternion.identity);

        }

        else

        {

            for (int i = 1; i < item.Length; i++)

            {

                // 화면의 선물 수를 5개 이내로 제한 

                int n1 = GameObject.FindGameObjectsWithTag("Item1").Length;

                int n2 = GameObject.FindGameObjectsWithTag("Item2").Length;

                int n3 = GameObject.FindGameObjectsWithTag("Item3").Length;


                if (n1 + n2 + n3 >= 5) return;


                // Item 만들기 

                pos.x = Random.Range(-5f, 5f);


                int n = Random.Range(0, 3);

                Transform obj = Instantiate(item[n], pos, Quaternion.identity) as Transform;


            }

        }

    }


    void OnTriggerEnter2D(Collider2D coll)

    {

        switch (coll.transform.tag)

        {

            case "Item1":

                AudioSource.PlayClipAtPoint(sndGift, transform.position);

                // 득점 처리              

                score += 500;

                giftCnt++;


                // 선물 제거 

                coll.transform.SendMessage("DisplayScore", 1);

                break;


            case "Item2":

                AudioSource.PlayClipAtPoint(sndGift, transform.position);

                // 득점 처리 

                score += 1000;

                giftCnt++;


                // 선물 제거 

                coll.transform.SendMessage("DisplayScore", 2);

                break;


            case "Item3":

                AudioSource.PlayClipAtPoint(sndGift, transform.position);

                // 득점 처리 

                score += 1500;

                giftCnt++;


                // 선물 제거 

                coll.transform.SendMessage("DisplayScore", 3);

                break;


            case "Bird":

                if (coll.transform.eulerAngles.z != 0) return;


                AudioSource.PlayClipAtPoint(sndBird, transform.position);

                score -= 1000;


                // 참새 추락 처리 

                coll.transform.SendMessage("DropBird", SendMessageOptions.DontRequireReceiver);

                break;

        }

    }


    void UIText()

    {

        tScore.text = "Score :" + score;

        tHeight.text = "Height :" + (int)maxY;

        tItem.text = "Gift :" + giftCnt;

    }


    //게임 오버 설정

    void GameOver()

    {

         retryGame.gameObject.SetActive(true);

        if (GetComponent<AudioSource>().clip != sndOver)

        {

            GetComponent<AudioSource>().clip = sndOver;

            GetComponent<AudioSource>().loop = false;

            GetComponent<AudioSource>().Play();

        }

    }

    // 재시작 

    public void RetryGame()

    {


        Application.LoadLevel("MainGame");

    }


}





수정한 PlayerCtrl 스크립트에 그림과 같이 리소스를 연결합니다



제작게임 해보기  Google Play



게임을 실행하여 동영상과 같이 실행되는지 확인합니다


Audio_Texture.unitypackage


JumpRabbit.unitypackage



반응형

+ Recent posts