프로젝트/프로젝트 B

# 002 Development Log

효따 2025. 9. 5. 23:55

https://github.com/Kimhyogyeom/ProjectA

 

GitHub - Kimhyogyeom/ProjectA: Unity-MOBA-Prototype

Unity-MOBA-Prototype. Contribute to Kimhyogyeom/ProjectA development by creating an account on GitHub.

github.com


https://github.com/Kimhyogyeom/ProjectB

 

GitHub - Kimhyogyeom/ProjectB: Drill-inspired Project

Drill-inspired Project. Contribute to Kimhyogyeom/ProjectB development by creating an account on GitHub.

github.com


안녕하세요.

 

오늘은 게임의 UI를 업데이트해 줬습니다.

 

음.. 일단 생각보다 정말 원하는 Sprite를 구하기가 쉽지 않구나..라고 생각이 들었습니다.

 

Chat GPT로 프롬프트를 작성하고,

 

LMArena를 사용해 이미지들을 생성해 보며

 

Unity Asset Store도 사용해 이미지를 구하고

 

작업을 해주었는데요,

 

이게.. 생각보다 시간이 너무 많이 들었습니다.😂

 


 

 

먼저 영상부터 보겠습니다.

 

어제에 비해 많이 느낌이 달라진 것 같은데요!

 

역시 디자인이 있고 없고의 차이는

 

판다에 아이라인이 있고 없고의 차이 같습니다.

(비유가 이상한가 하하..)

 

 

이어서 오늘 작업한 내용을 보겠습니다.


 

Background는 이미지 두 개를 사용하였습니다.

 

BackgroundLooper 스크립트입니다.

using UnityEngine;

public class BackgroundLooper : MonoBehaviour
{
    [SerializeField] private float _backgroundSpeed = 1.0f;
    [SerializeField] private Transform[] _backgrounds;

    private int _startIndex = 0;
    private int _endIndex = 2;

    private float _backgroundHeight = 9.99f;

    void Update()
    {
        transform.position += Vector3.up * _backgroundSpeed * Time.deltaTime;

        if (_backgrounds[_startIndex].position.y > 11f)
        {
            _backgrounds[_startIndex].localPosition = _backgrounds[_endIndex].localPosition + new Vector3(0f, -_backgroundHeight, 0f);

            _endIndex = _startIndex;
            _startIndex = (_startIndex + 1) % _backgrounds.Length;
        }
    }
}

 

_backgrouinds 에는 3개의 배열을 받아왔는데

 

각 사용할 이미지들이 담긴 배열입니다.

 

3개를 가져온 이유는

 

패럴랙스 기법을 사용하기 위함입니다.

 

 

0번 인덱스는 배열은 첫 번째 Background Sprite를 사용했고

1~2번 인덱스는 Background Sprite2 (검정 / 화이트)를 사용하였습니다.

 

 

스크립트를 이어서 보자면

 

Update()를 활용하여 3개의 배경 (A, B, C)를 일정 속도로 올라가게 해 주었으며,

 

A가 일정 구간(11f) 위로 올라가면 맨 아래 C 밑으로 이동하게 해 주었습니다.

 

 

또한 배열 인덱스도 같이 변경해 주어서

 

무한 스크롤을 구현해 보았습니다.

 


 

다음음 어제 작성한 MinerController 스크립트입니다.

using System.Collections;
using UnityEngine;

public class MinerController : MonoBehaviour
{
    [SerializeField] private byte _minerDirection;
    [SerializeField] private Transform _startPosLeft;
    [SerializeField] private Transform _startPosRight;
    [SerializeField] private Transform _endPos;
    [SerializeField] private float _minerMoveSpeed = 2f;

    [SerializeField] private SpriteRenderer _spriteRenderer;

    [SerializeField] private Animator _bodyAnim;
    [SerializeField] private Animator _minerAnim;
    [SerializeField] private GameObject _minerAnimObj;

    [SerializeField] private GameObject _starObj;
    private void Start()
    {
        StartCoroutine(MiningLoop());
    }

    private IEnumerator MiningLoop()
    {
        while (true)
        {
            if (_minerDirection == 0)
            {
                _spriteRenderer.flipX = false;
                yield return StartCoroutine(MoveToPosition(_startPosLeft.position));
            }
            else if (_minerDirection == 1)
            {
                _spriteRenderer.flipX = true;
                yield return StartCoroutine(MoveToPosition(_startPosRight.position));
            }

            for (int i = 0; i < 4; i++)
            {
                _bodyAnim.SetTrigger("Mine");
                _minerAnimObj.SetActive(true);
                _minerAnim.SetTrigger("Mine");
                // _spriteRenderer.enabled = false;

                yield return new WaitForSeconds(1f);
                _minerAnimObj.SetActive(false);
                // _spriteRenderer.enabled = true;

            }
            _starObj.SetActive(true);
            if (_minerDirection == 0)
            {
                _spriteRenderer.flipX = true;
            }
            else if (_minerDirection == 1)
            {
                _spriteRenderer.flipX = false;
            }
            yield return StartCoroutine(MoveToPosition(_endPos.position));

            if (_minerDirection == 0)
            {
                _spriteRenderer.flipX = false;
            }
            else if (_minerDirection == 1)
            {
                _spriteRenderer.flipX = true;
            }
        }
    }

    private IEnumerator MoveToPosition(Vector3 target)
    {
        while (Vector3.Distance(transform.position, target) > 0.01f)
        {
            Vector3 dir = (target - transform.position).normalized;
            transform.Translate(dir * _minerMoveSpeed * Time.deltaTime, Space.World);
            yield return null;
        }

        transform.position = target;
        if (_starObj.activeSelf == true)
        {
            _starObj.SetActive(false);
        }
    }
}

 

크게 변경이 된 부분은 없으며

    private IEnumerator MiningLoop()
    {
        while (true)
        {
            if (_minerDirection == 0)
            {
                _spriteRenderer.flipX = false;
                yield return StartCoroutine(MoveToPosition(_startPosLeft.position));
            }
            else if (_minerDirection == 1)
            {
                _spriteRenderer.flipX = true;
                yield return StartCoroutine(MoveToPosition(_startPosRight.position));
            }

            for (int i = 0; i < 4; i++)
            {
                _bodyAnim.SetTrigger("Mine");
                _minerAnimObj.SetActive(true);
                _minerAnim.SetTrigger("Mine");
                // _spriteRenderer.enabled = false;

                yield return new WaitForSeconds(1f);
                _minerAnimObj.SetActive(false);
                // _spriteRenderer.enabled = true;

            }
            _starObj.SetActive(true);
            if (_minerDirection == 0)
            {
                _spriteRenderer.flipX = true;
            }
            else if (_minerDirection == 1)
            {
                _spriteRenderer.flipX = false;
            }
            yield return StartCoroutine(MoveToPosition(_endPos.position));

            if (_minerDirection == 0)
            {
                _spriteRenderer.flipX = false;
            }
            else if (_minerDirection == 1)
            {
                _spriteRenderer.flipX = true;
            }
        }
    }

 

Miner가 채굴을 할 때 Animator의 전이 조건인 Trigger 실행과

 

flipX를 조정해 주었습니다.

 


 

마지막으로 Guage에 동적인 효과를 줄 SmoothRotateUI입니다.

using UnityEngine;

public class SmoothRotateUI : MonoBehaviour
{
    [SerializeField] private float _minAngle = 80f;
    [SerializeField] private float _maxAngle = 100f;
    [SerializeField] private float _angelSpeed = 15f;

    private float _currentAngle;
    private int _direction = 1;

    void Update()
    {
        _currentAngle += _direction * _angelSpeed * Time.deltaTime;

        if (_currentAngle > _maxAngle)
        {
            _currentAngle = _maxAngle;
            _direction = -1;
        }
        else if (_currentAngle < _minAngle)
        {
            _currentAngle = _minAngle;
            _direction = 1;
        }

        transform.localEulerAngles = new Vector3(0f, 0f, _currentAngle);
    }
}

 

_minAngle / _maxAngle의 값을 정해주었으며,

 

해당 각도가 넘어가면 회전할 방향을 바꿔주는 방식으로 구현했습니다.

 


 

뭔가 작업을 하다 보니 자꾸 귀염뽀짝(?) 한 느낌을 주고 싶어 지는데요 ㅎㅎ

 

뭔가 이것저것 시도는 많이 해보는데 하고 나서 전체적인 느낌을 보면

 

약간.. 어색한..? 자연스럽지 않은..?? 그런 느낌이 들더라고요😥

 

 

또한 텍스트나, 각 이미지 배치나 기타 등..

 

정말 사소한 것 하나하나 전부

 

디테일하게 신경을 많이 썼구나..라고 느껴졌습니다.

 

(물론 모든 게임이 그렇겠지만요! 🤣)

 


 

 

또한 엑셀로 파악 중인 기능 데이터들을 정리해 봤는데요.

 

남은 기능 구현과 함께 UI도 하나씩 업데이트를 해보겠습니다. 

 

감사합니다!

 

'프로젝트 > 프로젝트 B' 카테고리의 다른 글

# 005 Development Log  (0) 2025.09.09
# 004 Development Log  (1) 2025.09.07
# 003 Development Log  (1) 2025.09.06
# 001 Development Log  (3) 2025.09.04
인사말  (0) 2025.09.04