본문 바로가기

Programming/유니티

유니티 무한의 발판 만들기 (Unity - Infinity Vertical Jump Platform)

목표 (Subject)

무한으로 생성되는 점프 플렛폼을 만들어보자. (Creating an infinitely generated jumping platform)

Platform 

발판의 스크립트를 아래와 같이 작성하자

Platform.cs

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

public class Platform : MonoBehaviour
{
    int platformIndex = 0;

    public void SetPlatformIndex (int _index)
    {
        platformIndex = _index;
    }
    public int GetPlatformIndex { get { return platformIndex; } }
}

----

----

발판에 사용될 발판의 클래스를 만들어준다.

1. 'Hierachy'에서 'Create Empty'를 눌러서 'GameObject'를 만들어주고

2. 이름을 'PlatformNormal'로 변경 후

3. 'Add Component' 로 'Platform' 스크립트를 추가하고

4. 'Sprite Renderer' 컴포넌트를 넣어준다.

platform.png
0.01MB

 위의 이미지를 다운받아서 'Project'의 'Assets' 영역에 'DragAndDrop' 해준다.

다운받은 발판이미지를 선택하여 발판의 'Pivot'을 변경하여 중앙이 'TopCenter'가 되도록 수정해주자

이렇게 해야 발판위에 타겟이 착지 할 수 있다.

'Sprite Renderer' 의 이미지를 변경해준다.

만들어진 'PlatformNormal' 오브젝트를 'Prefab'으로 사용하기위해

'Resources' 폴더를 만들어 'PlatformNormal'을 'DragAndDrop'해준다.



PlatformManager

발판 관리자로 발판을 생성하고 타겟의 위치에 따라서 발판의 위치를 변경해주자

'PlatformManager'라는 오브젝트를 만들고 아래와 같은 스크립트작성하여 붙여주자

PlatformManager.cs

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

public class PlatformManager : MonoBehaviour
{
    List<Platform> platforms = new List<Platform>();

    float platformStartPosition;
    float platformDistance;

    int curPlatformIndex = -1;

    int preloadUpCount = 0;     
    int preloadDownCount = 5;   //5개 정도가 적당할것같다.

    int preloadCount = 5;

    public void MakePlatforms(float _startPos, float _distance)
    {
        //카메라 영역의 크기를 가져온다 
        var _orthoSize = Camera.main.orthographicSize;

        //발판이 시작되는 위치부터 화면의 영역에 들어갈 발판의 갯수를 구한다
        var _screenHeight = (_orthoSize * 2) - _startPos;
        var _divideCount = (int)(_screenHeight / _distance);

        //화면에 보여질 발판외에 상단에 미리 생성해 놓을 발판의 갯수를 추가하여
        //캐릭터 기준으로 위로 몇개의 발판이 놓일지 정한다.
        preloadUpCount = _divideCount + preloadCount;

        //발판이 시작될 위치를 계산한다
        platformStartPosition = -_orthoSize + _startPos;
        //발판 사이의 거리를 지정한다
        platformDistance = _distance;

        Debug.Log("PreloadCount " + preloadUpCount);

        transform.position = Vector3.up * -_orthoSize;

        //만들어질 발판의 갯수를 정한다
        var _loopCount = preloadUpCount + preloadDownCount;
        var _platFormStartPos = _startPos - (_distance * preloadCount);

        Debug.Log("_loopCount : " + _loopCount);

        var _prefab = Resources.Load("PlatformNormal");
        for (int i = 0; i < _loopCount; i++)
        {
            var go = Instantiate(_prefab, transform) as GameObject;
            var _platform = go.GetComponent<Platform>();
            var _ypos = _platFormStartPos + (_distance * i);
            go.transform.localPosition =  Vector3.up * _ypos;

            //발판의 순서를 정해준다
            _platform.SetPlatformIndex(i);

            platforms.Add(_platform);
        }

        //아래로 다섯개가 생기기 때문에 현재 위치는 5번째가 된다.
        curPlatformIndex = preloadDownCount;
    }

    //외부에서 타겟의 높이를 가져와서 현재 발판의 중심 위치를 갱신해준다
    public void UpdatePlatform(float _targetYposition)
    {
        var _diff = _targetYposition - platformStartPosition;
        var _index = (int)(_diff / platformDistance);

        //타겟의 위치에 밑에 배치되는 발판의 수를 더해서 배열상의 발판위치를 만들어준다
        _index += preloadDownCount;

        //Debug.Log("UpdateScroll : " + _diff);

        if (curPlatformIndex != _index)
        {
            bool _isUp = true;
            if (_index < curPlatformIndex)
            {
                _isUp = false;
            }
            curPlatformIndex = _index;

            SetPlatform(_isUp);
        }
    }

    //타겟의 이동방향에 따라서 발판을 재배치한다
    void SetPlatform(bool _isUp)
    {
        Debug.Log("SetPlatform : " + curPlatformIndex);

        int _moveCount = 0;
        if (_isUp == true)
        {
            var _diff = curPlatformIndex + (preloadUpCount-1);
            Debug.Log("SetPlatform 1 : " + _diff);
            _moveCount = _diff - platforms[platforms.Count-1].GetPlatformIndex;
            Debug.Log("SetPlatform 2 : " + _moveCount + " / " + platforms[platforms.Count - 1].GetPlatformIndex);
        } else
        {
            var _diff = curPlatformIndex - (preloadDownCount-1);
            if (_diff <= 0) return;

            Debug.Log("down : " + _diff);
            _moveCount = platforms[0].GetPlatformIndex - _diff;
            Debug.Log("down _moveCount : " + _moveCount);
        }

        if (_isUp)
        {
            for (int i = 0; i < _moveCount; i++)
            {
                var _go = platforms[0];
                platforms.RemoveAt(0);
                var _endGo = platforms[platforms.Count - 1];
                platforms.Add(_go);
                //새로 배치된 위치 값으로 다시 지정 
                _go.SetPlatformIndex(_endGo.GetPlatformIndex + 1);
                _go.transform.localPosition = new Vector3(0, _endGo.transform.localPosition.y + platformDistance, 0);
            }
        } else
        {
            for (int i = 0; i < _moveCount; i++)
            {
                var _go = platforms[platforms.Count - 1];
                platforms.RemoveAt(platforms.Count - 1);
                var _startGo = platforms[0];
                platforms.Insert(0, _go);
                //새로 배치된 위치 값으로 다시 지정
                _go.SetPlatformIndex(_startGo.GetPlatformIndex - 1);
                _go.transform.localPosition = new Vector3(0, _startGo.transform.localPosition.y - platformDistance, 0);
            }
        }
    }
}

'MakePlatforms' 은 외부에서 발판의 시작 위치(Platform Start Y Position)와

발판 사이의 간격(Platform Space)을 넘겨주어 발판이 생성되도록 한다.

'UpdateScroll' 은 외부에서 타겟의 현재위치(Current Target Y Position)를 전달해 주어

타겟의 위치가 변경되었다면 SetPlatform 함수를 호출 해준다.

'SetPlatform' 은 타겟의 이동 방향(Target Move Direction)에 따라서

발판이 어느쪽으로 재배치 되는지 확인하여 재배(Platform Repositioning)치한다.

위의 스크립트에서는 타겟의 위치를 기준으로 아래로 5개의 예비 발판을 배치하였고

위로는 화면을 채울 발판과 예비 발판을 5개 추가하여 주었다.

이제 테스트에 사용될 'Unit'을 추가해서 점프를 해보며 기능이 동작하는지 확인해보자

----

----

Unit.cs

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


public class Unit : MonoBehaviour
{
    UNIT_STATE state = UNIT_STATE.IDLE;

    Rigidbody2D rigid;
    Collider2D collid;
    
    float yDir = 0;

    private void Start()
    {
        rigid = GetComponent<Rigidbody2D>();
        collid = GetComponent<Collider2D>();

        yDir = transform.position.y;
    }

    private void Update()
    {
        if (state == UNIT_STATE.JUMP)
        {
            var y = transform.position.y;
            if (y < yDir)
            {
                collid.enabled = true;
            }
            yDir = y;
        }
    }

    public void Jump(float _jumpHeight)
    {
        Debug.Log("jump");

        if (rigid == null || collid == null) return;

        state = UNIT_STATE.JUMP;
        collid.enabled = false;
        yDir = transform.position.y;

        var g = Physics.gravity.magnitude;  // get the gravity value
        var vSpeed = Mathf.Sqrt(2 * g * _jumpHeight); // calculate the vertical speed
        rigid.velocity = new Vector2(0, vSpeed); // launch the projectile!
    }

    public void SetUnitState (UNIT_STATE _state)
    {
        state = _state;
    }
    public UNIT_STATE GetUnitState { get { return state; } }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        state = UNIT_STATE.IDLE;
    }
    private void OnCollisionExit2D(Collision2D collision)
    {
    
    }
}

상세한 설명은 아래의 글을 참조하면 되겠다

 

유니티 애드몹 부업 프로젝트 : [3] 캐릭터 점프

목표 캐릭터에 RigidBody2d 컴포넌트를 추가시켜서 점프연출을 구현해 보자 RigidBody2D 물리를 적용하는 컴포넌트로 중력을 이용하여 캐릭터가 점프를 연출하는데 자연스럽게 보이도록 한다. 'Hierachy

moblieandlife.tistory.com

 

테스트를 진행할 'TestPlatform' 오브젝트를 만들어 다음과 같이 코딩해준다

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

public class TestPlatform : MonoBehaviour
{
    [SerializeField] PlatformManager platform;
    [SerializeField] Unit unit;

    // Start is called before the first frame update
    void Start()
    {
        //유닛의 초기 위치 지정
        unit.transform.position = new Vector3(0, -4, 0);
        //platform의 시작위치와 간격을 설정
        platform.MakePlatforms(1, 2);
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonUp(0))
        {
            //유닛 점프 - platform의 간격보다 조금 높게 점프
            unit.Jump(2.2f);
        }
        
        //유닛의 현재위치로 발판을 갱신해준다
        platform.UpdatePlatform(unit.transform.position.y);
    }
}

화면을 아래와 같이 구성한다

그리고 'TestPlatform' 의 'Inspector' 에 'Platform'과 'Unit' 을 

'DragAndDrop' 해준다.

이제 실행해주면 'Unit'의 위치에 따라서 'Platform'에 재배치 되는 것을 볼 수 있다.

 

 

유니티 애드몹 부업 프로젝트 : [1] 시작

목표 아주 단순한 점프게임을 만들어서 광고를 붙이고 광고수익을 발생 시켜보는 것이 이 프로젝트의 목표입니다. 서버도 없고 단지 클라이언트로 로그라이크형의 게임을 만들것이기 때문에

moblieandlife.tistory.com