728x90

1. 개발 현황

생각보다 빠르게 게임 개발이 끝나가고 있다.

1. 프리팹 일원화

- 추후 다양한 무기 추가를 위해 프리팹 구조를 개선하였다.

이전: 무기별 개별 프리팹 활용

현재: 무기별 공통 프리팹 활용 (스프라이트 및 콜라이더 제어)

2. 오디오 시스템 추가

- BGM과 SFX 시스템으로 나눠 오디오가 출력되는 시스템을 구현했다.

3. 아이템 드롭 & 픽업 시스템 구현

- 몬스터 사냥 시 게임 내 경험치 오브젝트를 드롭하는 시스템을 구현했다.

- 픽업 범위 내 드롭 오브젝트가 포함된 경우 아이템을 획득하는 시스템을 구현했다.

4. Setting HUD 구현

- 게임 옵션 세팅을 위한 HUD를 제작했다.

5. Window Screen 제어 로직 구현

- Setting HUD 내 옵션 중 Window Screen과 관련된 옵션을 제어하는 로직을 구현하였다.

2. 상세 개발 내용

1. 프리팹 일원화

    public enum PrefabType
    {
        Enemy,
        MeleeBox,
        MeleeCircle,
        RangeBox,
        RangeCircle,
        DropItem
    }
public class WeaponCtrl : MonoBehaviour
{
    int mId;
    bool mEnable;

    PoolManager mWeaponPool;

    public void Init(int id)
    {
        mEnable = true;
        if (id >= GameManager.instance.mPlayerData.WeaponSize)
            Debug.Assert(false, "Error");
        mId = id;

        // initialize Pool Manager (general setting)
        mWeaponPool = new GameObject("WeaponPool").AddComponent<PoolManager>();
        mWeaponPool.transform.parent = transform;
        mWeaponPool.transform.localPosition = Vector3.zero;
        mWeaponPool.transform.localRotation = Quaternion.identity;
        mWeaponPool.Init((int) GameManager.instance.mWeaponJsonData[GameManager.instance.mWeaponCtrlData[mId].Id].PrefabType);
        mWeaponPool.mPool[0].GetComponent<SpriteRenderer>().sprite = GameManager.instance.mWeaponSprite[GameManager.instance.mWeaponJsonData[GameManager.instance.mWeaponCtrlData[mId].Id].SpriteId];
        mWeaponPool.mPool[0].tag = GameManager.instance.mWeaponJsonData[GameManager.instance.mWeaponCtrlData[mId].Id].WeaponTag.ToString();

        // initialize Root Prefab (particular setting)
        switch (GameManager.instance.mWeaponJsonData[GameManager.instance.mWeaponCtrlData[mId].Id].WeaponType)
        {
            case Enum.WeaponType.Melee:
            case Enum.WeaponType.RangeDagger:
                mWeaponPool.mPool[0].GetComponent<BoxCollider2D>().size = new Vector2(0.4f, 1);
                break;
            case Enum.WeaponType.RangeBullet:
                mWeaponPool.mPool[0].GetComponent<BoxCollider2D>().size = new Vector2(0.4f, 0.4f);
                break;
            case Enum.WeaponType.RangeAxe:
                mWeaponPool.mPool[0].GetComponent<BoxCollider2D>().size = new Vector2(0.5f, 0.7f);
                mWeaponPool.mPool[0].GetComponent<Rigidbody2D>().gravityScale = 1;
                break;
            case Enum.WeaponType.Garlic:
                mWeaponPool.mPool[0].GetComponent<CircleCollider2D>().radius = 0.5f;
                break;
            case Enum.WeaponType.Web:
                mWeaponPool.mPool[0].GetComponent<BoxCollider2D>().size = new Vector2(3, 3);
                break;
            case Enum.WeaponType.Boom:
                mWeaponPool.mPool[0].GetComponent<CircleCollider2D>().radius = 1;
                break;
            case Enum.WeaponType.ThrowBoom:
                mWeaponPool.mPool[0].GetComponent<CircleCollider2D>().radius = 1;
                break;
            default:
                Debug.Assert(false, "Error");
                break;
        }
    }
 }

 

2. 오디오 시스템 추가

public class GameManager : MonoBehaviour
{
    public static GameManager instance;
    // 생략
    [Header("# BGM")]
    public AudioClip mBGMClip;
    public float mBGMVolume;
    public AudioSource mBGMPlayer;
    public AudioHighPassFilter mBGMFffect;
    [Header("# SFX")]
    public AudioClip[] mSFXClip;
    public float mSFXVolume;
    public int mMaxSFXChannel;
    public AudioSource[] mSFXPlayer;

	public void PlayBGM(bool en)
    {
        if (en)
        {
            mBGMPlayer.Play();
        }
        else
        {
            mBGMPlayer.Stop();
        }
    }
    public void PlayEffect(bool en)
    {
        mBGMFffect.enabled = en;
    }
    public void PlaySFX(Enum.SFX sfx)
    {
        for(int i=0; i < mSFXPlayer.Length; ++i)
        {
            if (mSFXPlayer[i].isPlaying)
                continue;
            mSFXPlayer[i].clip = mSFXClip[(int)sfx];
            mSFXPlayer[i].Play();
            break;
        }
    }
}

3. 아이템 드롭 & 픽업 시스템 구현

- 드롭 시스템

        if (mHealth > 0)
        {
            StartCoroutine(KnockBack());
            mAnim.SetTrigger("Hit");
        }
        else
        {
            mIsLive = false;
            mIsGarlic = false;
            mMovementSpeedCoef = 1.0f;
            mColl.enabled = false;
            mRigid.simulated = false;
            mSpriter.sortingOrder = 1;
            mAnim.SetBool("Dead", true);
            GameManager.instance.mPlayerData.Kill++;
            
            // 경험치 드롭
            GameObject item = GameManager.instance.mDropPool.Get();
            item.transform.position = transform.position;
            item.transform.rotation = Quaternion.identity;
            item.GetComponent<DropItem>().mData = mDropExp;
            switch (mDropExp)
            {
                case > 50:
                    item.GetComponent<DropItem>().mType = Enum.DropItemSprite.Exp2;
                    item.GetComponent<SpriteRenderer>().sprite = GameManager.instance.mDropItemSprite[(int)Enum.DropItemSprite.Exp2];
                    break;
                case > 10:
                    item.GetComponent<DropItem>().mType = Enum.DropItemSprite.Exp1;
                    item.GetComponent<SpriteRenderer>().sprite = GameManager.instance.mDropItemSprite[(int)Enum.DropItemSprite.Exp1];
                    break;
                default:
                    item.GetComponent<DropItem>().mType = Enum.DropItemSprite.Exp0;
                    item.GetComponent<SpriteRenderer>().sprite = GameManager.instance.mDropItemSprite[(int)Enum.DropItemSprite.Exp0];
                    break;
            }

            GameManager.instance.PlaySFX(Enum.SFX.Dead);
        }

- 픽업 시스템

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

public class DropItem : MonoBehaviour
{
    public Enum.DropItemSprite mType;
    public int mData;

    public bool mEnable;
    Rigidbody2D mRigid;
    Rigidbody2D mTarget;

    private void Awake()
    {
        mRigid = GetComponent<Rigidbody2D>();
        mTarget = GameManager.instance.mPlayer.GetComponent<Rigidbody2D>();
    }
    private void OnEnable()
    {
        mEnable = false;
    }
    private void FixedUpdate()
    {
        if (!GameManager.instance.mIsLive)
            return;
        if (!mEnable)
            return;

        Vector2 dirVec = mTarget.position - mRigid.position;
        Vector2 nextVec = dirVec.normalized * 2 * Time.fixedDeltaTime;
        mRigid.MovePosition(mRigid.position + nextVec);
        mRigid.velocity = Vector2.zero;
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.CompareTag("Player"))
        {
            mEnable = false;
            switch (mType)
            {
                case Enum.DropItemSprite.Exp0:
                case Enum.DropItemSprite.Exp1:
                case Enum.DropItemSprite.Exp2:
                    GameManager.instance.GetExp(mData);
                    break;
                case Enum.DropItemSprite.Health:
                    GameManager.instance.GetHealth(mData);
                    break;
                case Enum.DropItemSprite.Mag:
                    foreach (GameObject item in GameManager.instance.mDropPool.mPool)
                    {
                        if (item.GetComponent<DropItem>().mType == Enum.DropItemSprite.Exp0 || item.GetComponent<DropItem>().mType == Enum.DropItemSprite.Exp1 || item.GetComponent<DropItem>().mType == Enum.DropItemSprite.Exp2)
                            item.GetComponent<DropItem>().mEnable = true;
                    }
                    break;
                default:
                    Debug.Assert(false, "Error");
                    break;
            }
            gameObject.SetActive(false);
            return;
        }

        if (collision.CompareTag("PickupCollider"))
            mEnable = true;
    }
}

 

4. 옵션창 추가

public class GameManager : MonoBehaviour
{
    public static GameManager instance;
	// 생략
    public HUDSetting mHUDSetting;

    public void SetWindowScreen()
    {
        Debug.Log("hi");
        Screen.SetResolution(Screen.resolutions[mHUDSetting.mDropdownResoultion.value].width, Screen.resolutions[mHUDSetting.mDropdownResoultion.value].height, mHUDSetting.mToggleResoultion.isOn, Screen.resolutions[mHUDSetting.mDropdownResoultion.value].refreshRate);
    }
 }
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class HUDSetting : MonoBehaviour
{
    public TMP_Dropdown mDropdownResoultion;
    public Toggle mToggleResoultion;
    public TMP_Dropdown mDropdownLanguage;

    private void Awake()
    {
        for(int i=0; i< Screen.resolutions.Length; ++i)
        {
            TMP_Dropdown.OptionData option = new TMP_Dropdown.OptionData();
            option.text = Screen.resolutions[i].width + "x " + Screen.resolutions[i].height + " " + Screen.resolutions[i].refreshRate + "hz";
            mDropdownResoultion.options.Add(option);
            if (Screen.resolutions[i].width == Screen.width && Screen.resolutions[i].height == Screen.height)
                mDropdownResoultion.value = i;
        }
        mDropdownResoultion.RefreshShownValue();
        mToggleResoultion.isOn = Screen.fullScreenMode.Equals(FullScreenMode.FullScreenWindow) ? true : false;
    }
}

3. TODO

1. 필드 파괴형 오브젝트 추가 (e.g. 박스, 촛대, etc.)

2. 언어 제어 로직 추가

3. 볼륨 제어 로직 추가

+ Recent posts