728x90
SMALL

UI 출력용 자동차 프리팹 추가

기존에 만들었던 게임 플레이용 프리팹을 모두 복사한 후 아래 작업들 진행하였습니다.

  • PlayerCar, BoxCollider, Rigidbody, CinemachineVirtualCamera 제거
  • 왼쪽, 오른쪽을 구분하기 위해 배치 했던 빈 오브젝트 제거
  • 자동차의 중심축을 가운데로 변경
  • 레이어 UI로 수정

추가한 프리팹들은 Resources 폴더에 추가하였습니다.

 

추가한 프리팹을 게임에서 불러올 수 있도록 Car 템플릿을 수정하였습니다.
Car 템플릿에 있던 Prefab 컬럼 Player Prefab 으로 수정하고, Car 템플릿에 UI Prefab 컬럼을 추가하였습니다.

 

template_generator.py 수정한 후 DB에 수정한 템플릿을 새로 등록하였습니다.

def generate_car(file_path, sheet_name):
    book = load_workbook(file_path, data_only=True)
    sheet = book[sheet_name]
    skip = 0
    temp_group = []
    for row in sheet.rows:
        if skip < 2:
            skip += 1
            continue      
        if row[0].value == None:
            continue
        new_temp = {
            'Id': row[0].value,
            'Name': {
                'Table': row[1].value,
                'Key': row[2].value
            },
            'Icon': row[3].value,
            'Player Prefab': row[4].value,
            'UI Prefab': row[5].value,
            'Cost': int(row[6].value),
            'EnableReward': int(row[7].value)
        }
        temp_group.append(new_temp)
    return temp_group

 

클라이언트 CarTemplate 도 변경된 자동차 데이터들을 저장할 수 있도록 수정하였습니다.

public class CarTemplate
{
    [JsonIgnore]
    public int Index
    {
        get;
        set;
    }
    public string Id
    {
        get;
        set;
    }
    public LocalizationTemplate Name
    {
        get;
        set;
    }
    [JsonProperty("Icon")]
    public string IconPath
    {
        get;
        set;
    }
    [JsonIgnore]
    public Sprite Icon => Resources.Load<Sprite>(IconPath);
    [JsonProperty("PlayerPrefab")]
    public string PlayerPrefabPath
    {
        get;
        set;
    }
    [JsonIgnore]
    public GameObject PlayerPrefab => Resources.Load<GameObject>(PlayerPrefabPath);
    [JsonProperty("UiPrefab")]
    public string UiPrefabPath
    {
        get;
        set;
    }
    [JsonIgnore]
    public GameObject UiPrefab => Resources.Load<GameObject>(UiPrefabPath);
    public int Cost
    {
        get;
        set;
    }
}

 

자동차 목록창 수정

 

자동차 선택창에서 자동차를 자주 선택하기 때문에 계속 오브젝트를 생성/제거하지 않고, 활성화/비활성화로 관리할 수 있도록 UICarManager를 추가하였습니다.

public class UICarManager : MonoBehaviour
{
    Dictionary<string, GameObject> unused = new();

    public string SelectedId
    {
        get;
        private set;
    }

    public GameObject SelectedObject
    {
        get;
        private set;
    }

    public void Select(string id)
    {
        if (SelectedId == id)
            return;
        if (SelectedObject != null)
            Deselect();
        if (!unused.TryGetValue(id, out var go))
        {
            var template = ClientManager.Instance.TemplateService.Cars.Find(e => e.Id == id);
            go = Instantiate(template.UiPrefab, transform);
            go.transform.localPosition = Vector3.zero;
            go.transform.localRotation = Quaternion.identity;
            go.transform.localScale = Vector3.one;
        }
        go.SetActive(true);
        SelectedId = id;
        SelectedObject = go;
    }

    public void Deselect()
    {
        if (SelectedObject == null)
            return;
        SelectedObject.SetActive(false);
        unused[SelectedId] = SelectedObject;
        SelectedObject = null;
        SelectedId = null;
    }
}

 

자동차 모델은 RenderTexture가 연결된 다른 카메라로 자동차 모델을 촬영하고, RenderTextureRawImage를 이용하여 UI에 출력하도록 구현하였습니다.

 

보상획득창 구현

 

UGUI를 이용하여 보상획득 창 제작하였습니다.

 

RewardPopupViewUI 스크립트 구현하였습니다.
보상으로 자동차를 획득하면 자동차 모델을 출력하고, 돈을 획득하였다면 코인 아이콘을 출력하도록 구현하였습니다.
과거에 획득했던 자동차를 또 획득할 때는 자동차 모델을 출력하고, 아래 이미 획득했던 자동차라고 알려주는 텍스트가 출력되도록 구현하였습니다.

public class RewardPopupViewUI : MonoBehaviour
{
    [SerializeField]
    Image coinImage;
    [SerializeField]
    RawImage carImage;
    [SerializeField]
    UICarManager carManager;
    [SerializeField]
    TMP_Text contentText;
    [SerializeField]
    Button closeButton;

    void Start()
    {
        closeButton.onClick.AddListener(() =>
        {
            carManager.Deselect();
            gameObject.SetActive(false);
        });
    }

    public void Show(int coin)
    {
        coinImage.gameObject.SetActive(true);
        carImage.gameObject.SetActive(false);
        contentText.text = $"Gain {coin}";
        gameObject.SetActive(true);
    }

    public void Show(string carId, bool newCar)
    {
        coinImage.gameObject.SetActive(false);
        carImage.gameObject.SetActive(true);
        carManager.Select(carId);
        if (newCar)
        {
            contentText.text = $"Gain {carId}";
        }
        else
        {
            var car = ClientManager.Instance.UserService.User.Cars.Find(e => e.Id == carId);
            contentText.text = $"{carId} is already exit. Gain {car.Cost}";
        }
        gameObject.SetActive(true);
    }
}

 

룰렛으로 자동차 획득했을 때, 출석보상 받았을 때, 자동차 구매했을 때 보상회득창 출력하도록 구현하였습니다.

 

보상획득창을 출력하도록 구현하면서 UserService 클래스도 약간 수정하였습니다.

출석 보상을 받을 수 없을 때는 보상팝업창의 출력하지 않도록 구현하기 위해 출석보상 받을 수 있는지 없는지 체크하는 메소드를 추가하였습니다.

public bool CheckEnableAttendance()
{
    var now = DateTime.UtcNow;
    if (User.NumberOfAttendance >= templateService.DailyRewards.Count)
    {
        Debug.LogWarning("Attendance failed. Because attendance is already completed.");
        return false;
    }
    if (now <= User.DailyRewardedAtUtc.Date.AddDays(1))
    {
        Debug.LogWarning($"Attendance failed. Because of already rewarded today({now}/{User.DailyRewardedAtUtc}).");
        return false;
    }
    return true;
}

 

룰렛으로 획득한 자동차가 이미 획득했던 자동차인지 아닌지 구분할 수 있도록 UserServiceSpinRoulette 메소드를 수정하였습니다.

public async UniTask<(int index, bool newCar)> SpinRoulette()
{
    var now = DateTime.UtcNow;
    var res = await http.Put<RouletteResponse>("User/SpinRoulette", new DateRequest
    {
        UtcDate = now
    });
    if (!res.Item1.IsSuccess())
    {
        Debug.LogWarning($"Spin roulette failed. - {res}");
        UserUpdateFailed?.Invoke(this, EventArgs.Empty);
        return (-1, false);
    }
    User.RouletteSpunAtUtc = now;
    var car = User.RouletteCarRewards[res.Item2.Index];
    if (User.Cars.Contains(car))
    {
        User.Coin += car.Cost;
        return (res.Item2.Index, false);
    }
    else
    {
        User.Cars.Add(car);
        return (res.Item2.Index, true);
    }
}

 

 

이번주는 밖으로 자주 나가서 글을 오랜만에 게시하였습니다.
다음 주도 밖에 자주 나갈 예정이어서 글을 많이 못 올릴 것 같습니다


다음에는 게임 사운드를 추가하고, 옵션창을 제작해보도록 하겠습니다.

 

깃 허브 저장소 : taxi-game-3d-unity

728x90
LIST

+ Recent posts