2014년 5월 30일 금요일

Unity2D_ 2D Object Class


Explain.
Unity 2D Sprite Renderer
+
2D Physics
+
Animator
를 활용하여 오브젝트를 제작시 사용.
AutoDepth, ColorFade 기능구현


using UnityEngine;
using System.Collections;
[RequireComponent(typeof(BoxCollider2D))]
[RequireComponent(typeof(SpriteRenderer))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(Rigidbody2D))]
public class MyObject : MonoBehaviour
{
    private SpriteRenderer mSpriteRenderer;
    private BoxCollider2D mBoxCollider2D;
    private Animator mAnimator;
    private Transform mTransform;

    public void FadeOut()
    {
        StartCoroutine(fadeOutCoroutine());
    }

    public void ONObject()
    {
        _BoxCollider2D.enabled = true;
        _SpriteRenderer.enabled = true;
        _Animator.enabled = true;
    }

    public void OFFOjbect()
    {
        _BoxCollider2D.enabled = false;
        _SpriteRenderer.enabled = false;
        _Animator.enabled = false;
    }

    private IEnumerator fadeOutCoroutine(float duration = 3f)
    {
        float startTime = Time.time;
        while (Time.time - startTime < duration)
        {
            mSpriteRenderer.color = Color.Lerp(Color.white, Color.clear, (Time.time - startTime) / duration);
            yield return true;
        }
        _SpriteRenderer.color = Color.clear;
    }
    public void ColorFade(Color fadeColor)
    {
        StartCoroutine("colorFade", fadeColor);
    }
    public void ColorFade(Color fadeColor, float duration, int rc)
    {
        StartCoroutine(colorFade(fadeColor, duration, rc));
    }

    public void StartAutoDepth()
    {
        StartCoroutine("depthCoroutine");
    }

    public void SetDepth()
    {
        _SpriteRenderer.sortingOrder = (int)(-_LocalPosition.y * 200f);
    }

    public void StopAutoDepth()
    {
        StopCoroutine("depthCoroutine");
    }

    private IEnumerator depthCoroutine()
    {
        yield return new WaitForSeconds(.1f);
        _SpriteRenderer.sortingOrder = (int)(-_LocalPosition.y * 200f);
        StartCoroutine("depthCoroutine");
    }

    private IEnumerator colorFade(Color fadeColor, float duration = 2f, int rc = 3)
    {
        float once = duration / (rc * 2);

        float startTime = Time.time;

        for (int i = 0; i < rc; i++)
        {
            while (Time.time - startTime < once)
            {
                mSpriteRenderer.color = Color.Lerp(Color.white, fadeColor, (Time.time - startTime) / once);
                yield return null;
            }
            mSpriteRenderer.color = fadeColor;
            startTime = Time.time;
            while (Time.time - startTime < once)
            {
                mSpriteRenderer.color = Color.Lerp(fadeColor, Color.white, (Time.time - startTime) / once);
                yield return null;
            }
            mSpriteRenderer.color = Color.white;
            startTime = Time.time;
        }

    }
    public Vector2 _LocalPosition
    {
        get { if (mTransform == null) mTransform = transform; return mTransform.localPosition; }
        set { if (mTransform == null) mTransform = transform; mTransform.localPosition = value; }
    }
    public Vector2 _LocalScale
    {
        get { if (mTransform == null) mTransform = transform; return mTransform.localScale; }
        set { if (mTransform == null) mTransform = transform; mTransform.localScale = value; }
    }

    public Animator _Animator
    {
        get {
            if (mAnimator == null) mAnimator = GetComponent <Animator>();
            return mAnimator; }
        set { mAnimator = value; }
    }

    public SpriteRenderer _SpriteRenderer
    {
        get
        {
            if (mSpriteRenderer == null) mSpriteRenderer = GetComponent<SpriteRenderer>();
            return mSpriteRenderer;
        }
        set { mSpriteRenderer = value; }
    }


    public BoxCollider2D _BoxCollider2D
    {
        get
        {
            if (mBoxCollider2D == null) mBoxCollider2D = GetComponent<BoxCollider2D>();
            return mBoxCollider2D;
        }
        set { mBoxCollider2D = value; }
    }
}

2014년 5월 15일 목요일

Unity_Pannel Fade In&Out With NGUI

Explan.
NGUI이용시
Script상에서 UIPannel 의 alpha scale을 조정하면서
페이드 인,아웃 효과를 주는 스크립트.
Tween Alpha를 활용하여 줄수도 있으나
개인적으로 직접 코딩하여 진행하는것이 더편하기에...
UIPannel뿐만아니라 그외의 컴포넌트라도
Alpha 속성이 구현되어있는 놈이라면
동일하게 이용할수있다.
Timescale값은 원하는값으로 수정하면된다.


FadeInOut.cs

using UnityEngine;
using System.Collections;

public class PannelFadeInOut : MonoBehaviour {

    private UIPanel mPannel;

    private float mFadeTime = 1f;
    private float mWaitTime = 1f;
    private bool on = false;
    void Start()
    {
        mPannel = GetComponent<UIPanel>();
        mPannel.enabled = false;
    }

    public void StartFade()
    {
        if(!on)
            StartCoroutine("fadeCoroutine");
    }

    public void StopFade()
    {
        StopCoroutine("fadeCoroutine");
    }

    IEnumerator fadeCoroutine()
    {
        mPannel.enabled = true;
        float startTime = RealTime.time;
        Time.timeScale = .2f; // slow Time scale
        while(RealTime.time - startTime < mFadeTime) // fade in
        {
            mPannel.alpha = Mathf.Lerp(.1f, .95f, (RealTime.time - startTime) / mFadeTime);
            yield return null;
        }

        startTime = RealTime.time;
        while (RealTime.time - startTime < mWaitTime) // wait
            yield return null;
        
        startTime = RealTime.time;
        while (RealTime.time - startTime < mFadeTime) // fade out
        {
            mPannel.alpha = Mathf.Lerp(.95f, 0, (RealTime.time - startTime) / mFadeTime);
            yield return null;
        }
        Time.timeScale = 1f;
        mPannel.alpha = 0; // default 0
    }
}

2014년 5월 13일 화요일

Unity_NGUI Sprite Auto Depth Script with NGUI

Explanation.
NGUI를 사용하여 게임제작시
자동으로 Depth를 조정해주는 스크립트
depth의 범위를 지정안하고 그냥 
포지션의 y값을 가지고와서 depth로 적용.

Todo.
정해진 depth 범위내에서 적용되도록 변경.

기본

Auto Depth 적용전

Auto Depth 적용후

using UnityEngine;
using System.Collections;

public class AutoDepth : MonoBehaviour {

    private UISprite mSprite;
    private Transform mTransform;
    private int waitFrameCount = 15;
    
 void Start () {
        mSprite = GetComponent();
        mTransform = transform;
        StartCoroutine("depthCoroutine");
 }
 
 IEnumerator depthCoroutine()
    {
        for (int i = 0; i < waitFrameCount ; ++i)
            yield return null;
        mSprite.depth = -(int)mTransform.localPosition.y;
        StartCoroutine("depthCoroutine");
    }

}

Unity_2D Movement(Click to move) with NGUI

Explanation.

NGUI로 게임제작시
UI Root        
└Camera
└Pannel
            └2d Object(Sprite)
의 구조로 게임제작을 진행할때 사용하는 Movement
제목처럼 화면클릭시 목표좌표를 계산(NGUI에 맞게)한뒤
움직이는 방법.(Click to Move)
Movement2D.cs
using UnityEngine;
using System.Collections;

//click to move with NGUI
public class Movement2D : MonoBehaviour {
    private int mUIWidth = 720; // UI Root width size
    private int mUIHeight = 1280; // UI Root height size
    private int mScreenWidth = Screen.width;
    private int mScreenHeight = Screen.height;
    private int mSpeed = 200; // pixel per sec

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            clickToMove(Input.mousePosition);
        }
    }

    void clickToMove(Vector2 mousePos)
    {
        StopCoroutine("move");
        StartCoroutine("move", calcurateTargetPos(mousePos));
    }
    
    IEnumerator move(Vector2 endPos)
    {
        Vector2 startPos = transform.localPosition;
        float startTime = Time.time;
        float movedTime = Vector2.Distance(startPos, endPos) / mSpeed;
        while (Time.time - startTime < movedTime)
        {
            transform.localPosition = Vector2.Lerp(startPos, endPos, (Time.time - startTime) / movedTime);
            yield return null; // wait frame
        }
        transform.localPosition = endPos; // end Position set
    }

    Vector2 calcurateTargetPos(Vector2 mousePos)
    {
        Vector2 result;

        result.x = Mathf.Lerp(-mUIWidth / 2, mUIWidth / 2, mousePos.x / mScreenWidth);
        result.y = Mathf.Lerp(-mUIHeight / 2, mUIHeight / 2, mousePos.y / mScreenHeight);

        return result;
    }
}

2014년 5월 1일 목요일

Unity_Screen Capture.cs _ Screen Shot


Explanation.
현재 게임 화면 캡쳐기능.
현재 스크린 그대로를 readpixel하는 방식이라
OnGUI로 그려지는 UI는 캡쳐X
스크린 사이즈 그대로 RGB24 포멧으로 저장.

ScreenCapture.cs
using UnityEngine;
using System.Collections;
using System.IO;

public class ScreenCapture : MonoBehaviour
{
    int height = Screen.height;
    int width = Screen.width;

    Texture2D captureTexture;
    float startTime;
    string saveDir = "ScreenShot"; // 저장 폴더 이름.

    bool draw = false;
    void OnGUI()
    {
        if (GUI.Button(new Rect(10, 50, 100, 50), "Capture"))
        {
            StartCoroutine(screenCapture());
        }
    }

    IEnumerator screenCapture()
    {
        yield return new WaitForEndOfFrame();
        captureTexture = new Texture2D(width, height, TextureFormat.RGB24, true); // texture formoat setting
        captureTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0, true); // readPixel
        captureTexture.Apply(); // readPixel data apply

        byte[] bytes = captureTexture.EncodeToPNG();

        File.WriteAllBytes(getCaptureName(), bytes);
        Debug.Log(string.Format("Capture Success: {0}", getCaptureName()));

    }
    string getCaptureName()
    {
        string dirPath = Application.dataPath + "/" + saveDir;
        if (!Directory.Exists(dirPath))
        {
            Directory.CreateDirectory(dirPath);
        }
        return string.Format("{0}/capture_{1}.png",
                             dirPath,
                             System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
    }
    
}

Unity_Effect Manager.cs


Explanation.

이전에 프로젝트에서 사용했던 Effect Manager 저장용
Effect 전용 카메라 생성후 
카메라 내부에 Effect Manager Script Add

카메라기준 이펙트 스폰 위치의 local position값을 기준으로
이펙트 생성.


TODO.
Wolrd position값을 기준으로 effect생성?
PlayType별로 effect play


EffectManager.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class EffectManager : MonoBehaviour
{
    #region Singleton
    private static EffectManager sInstance;

    public static EffectManager GetInstance
    {
        get
        {
            if (sInstance == null) sInstance = (EffectManager)FindObjectOfType(typeof(EffectManager));

            if (sInstance == null)
            {
                if (GameObject.Find("Singleton"))
                {
                    GameObject goInst = GameObject.Find("Singleton");
                    sInstance = goInst.AddComponent<EffectManager>();
                }
                else
                {
                    GameObject goInst = new GameObject("Singleton");
                    sInstance = goInst.AddComponent<EffectManager>();
                }
            }
            return sInstance;
        }
    }
    #endregion

    public EffectObject[] _Effects;

    public Dictionary<EffectType, EffectObject&g; Effects = new Dictionary<EffectType, EffectObject>();


    public void Spwan(EffectType type, Vector2 pos)
    {
        Effects[type].Spawn(pos);
    }

    private void Awake()
    {
        Initialize();
    }

    private void Initialize()
    {
        for (int i = 0; i < _Effects.Length; i++)
        {
            _Effects[i].Initialize(this.transform);
            Effects.Add(_Effects[i]._Type, _Effects[i]);
        }
    }
}

[System.Serializable]
public class EffectObject
{
    public GameObject _Effect;
    public EffectType _Type;
    public int _Length; // 한화면에 보여질 최대 이펙트 숫자.
    private List<GameObject> mList = new List<GameObject>();
    private int mIndex = 0;


    public void Spawn(Vector2 pos)
    {
        mList[mIndex].transform.localPosition = pos;
        mList[mIndex].particleSystem.Play();
        mIndex++;
        if (mIndex == _Length) mIndex = 0;
    }

    public void Initialize(Transform trans)
    {
        GameObject parent = new GameObject(_Type.ToString());
        parent.transform.parent = trans;
        for (int i = 0; i < _Length; i++)
        {
            GameObject tmp = MonoBehaviour.Instantiate(_Effect) as GameObject;
            tmp.name = i.ToString();
            tmp.transform.parent = parent.transform;
            tmp.transform.localScale = new Vector2(1, 1);
            mList.Add(tmp);
        }
    }
}

public enum EffectType
{
    Once,
    Loop,
    Move,
    Last
}
(e.g)

Unity3D_Screen Capture And Mosaic


Explanation.
현재 화면을 capture한뒤 mosaic처리.
잠깐 시간이나서 구현.
최적화 X(개선필요)
모자이크 처리방식 매우 비효율적.(개선필요)
어디 쓰일지도 의문.
정리해두고 추후 필요시 사용.


CaptureAndMosaic.cs
using UnityEngine;
using System.Collections;

public class CaptureAndMosaic : MonoBehaviour
{
    int height = Screen.height;
    int width = Screen.width;

    Texture2D captureTexture;
    float startTime;

    bool draw = false;
    void Start()
    {
        startTime = Time.realtimeSinceStartup;
        StartCoroutine(getScreenAndMosaic());
    }
    void OnGUI()
    {
        if (captureTexture != null)
            GUI.DrawTexture(new Rect(0, 0, captureTexture.width, captureTexture.height), captureTexture);

        if (!string.IsNullOrEmpty(log))
            GUI.Label(new Rect(100, 100, 100, 100), log);
    }
    bool end = false;
    IEnumerator getScreenAndMosaic() 
    {
        yield return new WaitForEndOfFrame();
        captureTexture = new Texture2D(width, height, TextureFormat.RGB24, true);
        captureTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0, true);
        captureTexture.Apply();
        StartCoroutine(makeNoise());
    }

    IEnumerator makeNoise()
    {
        yield return StartCoroutine(makeNoiseTexture(40));
    }

    int index = 0;
    IEnumerator makeNoiseTexture(int dist)
    {
        int distDiv = dist;
        int nBoxSize = width / distDiv;
        int x = 0;
        int y = 1;
        Color[] colors = new Color[nBoxSize * nBoxSize];
        Color preColor = Color.white;
        int mid = height / (nBoxSize * y);
        while (nBoxSize * y < height)
        {
            preColor = captureTexture.GetPixel(0 + x * nBoxSize, height - nBoxSize * y);

            for (int i = 0; i < colors.Length; ++i)
                colors[i] = captureTexture.GetPixel(0 + x * nBoxSize, height - nBoxSize * y);
            if (height - nBoxSize * y <= 0)
                captureTexture.SetPixels(0 + x * nBoxSize, 0, nBoxSize, nBoxSize, colors);
            else
                captureTexture.SetPixels(0 + x * nBoxSize, height - nBoxSize * y, nBoxSize, nBoxSize, colors);

            ++x;

            if (x * nBoxSize > width - nBoxSize)
            {
                x = 0;
                ++y;
                if (y % 3 == 0) // 3행 처리후 apply
                {
                    captureTexture.Apply();
                    yield return null;
                }
            }
        }
        yield return null;
        captureTexture.Apply(); 

        log = "mosaic ended Time : " + (Time.realtimeSinceStartup - startTime);

        Debug.Log("end");
    }
    string log = string.Empty;

}
Result.

Before

After