레이블이 Unity Script인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Unity Script인 게시물을 표시합니다. 모든 게시물 표시

2015년 6월 2일 화요일

Unity_코루틴 함수를 활용한 Lerp함수 활용 using IEnumerator with Lerp

Explain.

Unity Coroutine 함수를 활용한 Object의 Lerp(선형보간)운동 구현구현
가장 심플하게 구현한 예제.
C#의 Generic , Reflection을 활용하여 기능 확장 가능.

Code.
IEnumerator moveCoroutine(float duration, Vector3 end)
{
 WaitEndOfFrame wait = new WaitEndOfFrame();

 Vector3 start = transform.position;
 float elapsed = 0.0f;

 while(elapsed < duration){
  elapsed += Time.deltatime;
  transform.position = Vector3.Lerp(start,end elapsed / duration);
  yield return wait;
 }

 transform.position = end;
}

IEnumerator colorCoroutine(float duration, Color start, Color end)
{
 WaitEndOfFrame wait += new WaitEndOfFrame();

 float elapsed = 0.0f;

 while(elapsed < duration){
  elapsed = Time.deltaTime;
  renderer.material.color  = Color.Lerp(start,end elapsed / duration);
  yield return wait;
 }

 renderer.material.color = end;
}

2015년 4월 15일 수요일

Finite State Machine for CSharp_Step2. 활용 예제

Explain.
게임 제작시 MainFrame(MainManager, GameManager 등)에서 FSM을 구현하는 방법 정리


MainFrame.cs
class MainFrame
{
    public enum State
    {
        Game,
        Lobby
    }

    FiniteStateMachine<MainFrame, State> FSM;
    
    LobbyState stateLobby = new LobbyState();
    GameState stateGame = new GameState();

    void Awake()
    {
        FSM = new FiniteStateMachine<MainFrame, State>(this);
        FSM.AddState(stateLobby);
        FSM.AddState(stateGame);

        FSM.ChangeState(stateLobby); // 시작시 stateLobby State
    }
}
LobbyState.cs
class LobbyState : FiniteState<MainFrame, MainFrame.State>
{
    public override void SetEntity(MainFrame entity)
    {
        base.SetEntity(entity);
    }
    public override void Enter()
    {
        base.Enter();
        //게임 입장시 이벤트 구현부
    }
    public override void Excute()
    {
        base.Excute();
        //게임 실행시 이벤트 구현부
    }
    public override void Exit()
    {
        base.Exit();
        //게임 퇴장시 이벤트 구현부
    }

    public override MainFrame.State _StateID
    {
        get
        {
            return MainFrame.State.Game;
        }
    }
}
GameState.cs
class GameState : FiniteState<MainFrame, MainFrame.State>
{
    public override void SetEntity(MainFrame entity)
    {
        base.SetEntity(entity);
    }
    public override void Enter()
    {
        base.Enter();
        //게임 입장시 이벤트 구현부
    }
    public override void Excute()
    {
        base.Excute();
        //게임 실행시 이벤트 구현부
    }
    public override void Exit()
    {
        base.Exit();
        //게임 퇴장시 이벤트 구현부
    }

    public override MainFrame.State _StateID
    {
        get
        {
            return MainFrame.State.Game;
        }
    }
}

Finite State Machine for CSharp_Step1. FSM 구현

Explain. 
유한 상태 기계라고 하며, 특정한 Input(event) 에 따라 해당하는 state(output)으로 변화하는 방법론. 다양한 분야(특히 게임)에 사용되어 지고있으며 상태에 변화에 따른 이벤트를 발생시킬수있으므로 좀더 유연한 로직을 구성할수있다. 이전에 게임 제작시 사용했던 현재도 사용하고있는 FSM에 대해 정리. 스크립트 설명의경우 주석으로 진행.

Step. 
1. FiniteStateMachine 구현
2. 간단한 사용법

FSM 구현

Summary.
 IState ( FiniteState의 명세를 담은 Interface )
 FiniteState ( State 클래스 )
 FiniteStateMachine ( FSM 클래스 )

IState.cs

interface IState<T>
{
    
    void Enter();
    void Excute();
    void Exit();

    T _StateID
    {
        get;
    }
}

FiniteState.cs
class FiniteState<T, U> : IState<U>
{
    protected T entity;

    public virtual void SetEntity(T entity)
    {
        this.entity = entity;
    }

    public virtual void Enter()
    {
        Console.WriteLine(typeof(T).ToString() + "Enter");
    }

    public virtual void Excute()
    {
        Console.WriteLine(typeof(T).ToString() + "Excute");
    }

    public virtual void Exit()
    {
        Console.WriteLine(typeof(T).ToString() + "Exite");
    }

    public virtual U _StateID
    {
        get
        {
            throw new ArgumentException("Exception");
        }
    }

}

FiniteStateMachine.cs
class FiniteStateMachine<T, U>
{
    private T entity; // State의 주체가 되는 class

    private Dictionary<U, FiniteState<T, U>> stateDic; // 전체 State

    private FiniteState<T, U> currentState; // 현재 상태
    private FiniteState<T, U> previousState; // 이전 상태

    /// <summary>
    /// 생성자
    /// </summary>
    /// <param name="entity">주체 class</param>
    public FiniteStateMachine(T entity)
    {
        this.entity = entity;
        stateDic = new Dictionary<U, FiniteState<T, U>>();
    }

    public void ExcuteState()
    {
        if (currentState != null) currentState.Excute();
    }

    public void ChangeState(FiniteState<T, U> nextState)
    {
        if (currentState == nextState) return;

        if(currentState != null)
        {
            currentState.Exit();
            previousState = currentState;
        }

        currentState = nextState;

        currentState.Enter();
    }

    public void ChangeState(U stateID)
    {
        try
        {
            FiniteState<T, U> state = stateDic[stateID];
            ChangeState(state);
        }
        catch(KeyNotFoundException)
        {
            // exception 처리
        }
    }

    //이전 state로 상태 되돌리기
    public void RevertState()
    {
        if (previousState != null)
            ChangeState(previousState);
    }

    public void AddState(FiniteState<T, U> state)
    {
        if (state == null) return;
        state.SetEntity(entity);
        stateDic.Add(state._StateID, state);
    }

    public void RemoveState(FiniteState<T, U> state)
    {
        stateDic.Remove(state._StateID);
    }
}

2014년 10월 1일 수요일

CSharp_Visual Studio Custom Snippet 적용 시키기. in Visual Studio & Unity

Explain.
Visual Studio를 사용할경우 snippet파일을 직접 만들어서 적용.
Snippet을 적용하여 작업하는 이유는 모든 스크립트의 전체적으로 통일된 디자인을 적용하고 반복되어지는 작업을 최소화 시켜줌.

How to use.
아래처럼 xml형식으로 snippet 파일을 생성후 저장(*.snippet)으로 저장 하여야 한다.
(아래 형식은 제가 사용하는(unity)에서 형식이고 내용은 필요한대로 편집하여 사용하시면됩니다.)
저장경로 : Users\User\Documents\Visual Studio XXXX\Code Snippets\Visual C#\My Code Snippets

그 이후
프로젝트에서 우클릭-> Insert Code Snippet -> My Code Snippet -> 해당 Snippet 선택
해주시면 snippet이 짠 하고 나타나는것을 보실수 있습니다.
ctrl + K + X가 Hotkey이니 애용하시면 될듯합니다. -End.

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>#Classregion</Title>
      <Shortcut>#Classregion</Shortcut>
      <Description>Code snippet for #Classregion</Description>
      <Author>Author Name</Author>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
        <SnippetType>SurroundsWith</SnippetType>
      </SnippetTypes>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>name</ID>
          <ToolTip>Region name</ToolTip>
          <Default>MyRegion</Default>
        </Literal>
      </Declarations>
      <Code Language="csharp">
        <![CDATA[
        #region -------Public Field-------
        $selected$ $end$
        #endregion
    
        #region -------Private Field-------
        $selected$ $end$
        #endregion
    
        #region -------Default Method-------
        $selected$ $end$
        #endregion

        #region -------Public Method-------
        $selected$ $end$
        #endregion
    
        #region -------Private Method-------
        $selected$ $end$
        #endregion
    
        #region -------Property-------
        $selected$ $end$
        #endregion
    ]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

2014년 7월 9일 수요일

Unity C#_Array Refernce & Copy


Explain.
자주있는 일은 아니지만, 종종
System.Array type의 값, 즉 C#에서 배열로 선언한 값들을 사용할때
orgArr[원본]
destArr[복사본]
즉 Array 에 대한 Reference가 아닌 Copy가 필요한경우

무의식중에 destArr = orgArr;
이런식으로 코딩하고 넘어가는경우(즉, 아직 저처럼 실력이 부족한경우겠지만..)
가 발생할수도 있지만 이경우 destArr가 orgArr의 data를 Copy한것이아닌
reference(참조)하고 있는것이므로
orgArr의 데이터값 변화가 생기면 자동으로 destArr의값또한 변화가 생긴다.

이러한특징은 C#의 System.Array type(int [] , string[] , float [] 등등)
으로 선언된 데이터는 모두 reference형식으로 선언되는점때문에 일어나는 현상이다.

이럴때 copy가 필요한경우
System.Array.Copy 메소드를 사용해서 array자체를 복사해주는것으로 해결하면된다.

자세한내용의 MSDN에 잘명시되어있다. 링크


Code.

System.Array.Copy(orgArray, destArray, orgArray.Length); // prams (원본 배열 , 복사본 배열, 원본배열의 길이)

2014년 6월 17일 화요일

Unity Script_ Debug 전용 Logger 예제


Explain.
C#의 기능중하나인 전처리기를 활용하여 Debug모드시에만 
Log를 출력하게끔 구현해주는 방식.
릴리즈시 전처리기의 해제로 log기능을 끌수있다.
구현방식은 매우 간단.

Logger.cs
#define DEBUG
//#undef DEBUG // realease version

public class Logger {
 public static void Log(string msg)
    {
#if DEBUG
        UnityEngine.Debug.Log(msg);
#endif
    }

    public static void ErrorLog(string msg)
    {
#if DEBUG
        UnityEngine.Debug.LogError(msg);
#endif
    }
}

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

2014년 4월 24일 목요일

Ad@m_Adam.cs

Adam.cs
public class Adam : MonoBehaviour {

    AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    AndroidJavaObject activity;
    #region Singleton
    private static Adam sInstance;

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

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

    public void LoadInterstitial()
    {
        activity = jc.GetStatic<AndroidJavaObject>("currentActivity");
        activity.Call("LoadInterstitial");
    }

}
Test.cs
public class Test : MonoBehaviour {

 // Use this for initialization
 void Start () {
        Adam.GetInstance.LoadInterstitial();
 }
}

How to Use.
Adam.cs생성후 다른 스크립트에서 LoadInterstitial() 함수를 호출하면 된다.

Unity2D_ Generic Object Pool Class v1.2


Summary.
기존의 Object Pooling을 사용하기위해 사용하던것을 Generic Class화 하여 봤습니다.
코드의 문제가 군데군데 보이지만 이후 조금씩 보완해 나가겠습니다.

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

public class Pool<T> : MonoBehaviour where T : MonoBehaviour {

    public GameObject _PoolObject;
    public int _PoolLength;

    private int mPoolLength;
    private List<T> mPoolList;
    private int? mIndex = null;

    void Awake()
    {
        Initialize(_PoolLength);
    }


    private void Initialize(int length)
    {
        mPoolLength = length;
        mPoolList = new List<T>();
        for (int i = 0; i < mPoolLength; ++i)
        {
            GameObject tmp = Instantiate(_PoolObject) as GameObject;
            tmp.transform.parent = transform;
            tmp.name = typeof(T).ToString() + i;
            mPoolList.Add(tmp.GetComponent<T>());
        }
    }

    public T _GetObject
    {
        get 
        {
            if (mIndex == null)
                mIndex = 0;
            else
                mIndex++;

            return mPoolList[(int)mIndex];
        }
    }

    public int? _Index
    {
        get { return mIndex; }
        set { mIndex = value; }
    }

 public List<T> _PoolList
    {
        get { return mPoolList; }
        set { mPoolList = value; }
    }

    public int Length
    {
        get { return mPoolLength; }
    }
}

How to Use.

Enemy.cs
using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour
{
    public void Spawn(Vector2 pos)
    {
        Debug.Log("Spawn : " + name + "pos :" + pos);
    }
    public void Die()
    {
        Debug.Log("Die : " + name);
    }
}
EnemyPool.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class EnemyPool : Pool<Enemy>
{
    public void AllEnemySpawn()
    {
        foreach (Enemy ene in _PoolList)
            ene.Spawn(Vector2.zero);
        _Scope = 0;
    }

    public void AllEnemyDie()
    {
        foreach (Enemy ene in _PoolList)
            ene.Die();
        _Scope = 0;
    }

    public void EnemySpwan(Vector2 pos)
    {
        _GetObject.Spawn(pos);
    }

    public void EnemySpawn()
    {
        _GetObject.Spawn(Vector2.zero);
    }

    public void EnemyDie(Enemy target)
    {
        _PoolList.Find(
            delegate(Enemy enemy)
            {
                if (enemy == target)
                {
                    enemy.Die();
                    return true;
                }
                else return false;
            }
            );
    }
}
fix-
v1.0 - 첫 업데이트. 기본적인 Object Pool 구조 작성.
v1.1 - value name modify
v1.2 - method name modify

2013년 11월 22일 금요일

Unity_PlayerPref 에 Class , Sturct형 Data 저장하기

 이번에 게임 제작진행중 Setting값을 PlayerPref를 활용해 저장할 방법을 궁리하던중 찾아낸방법.

// String<->Binary format 변환시 필요한 아이
using System.Runtime.Serialization.Formatters.Binary; 


//class property
private SettingInfo _setValue = new SettingInfo();

//PlayerPref에 저장할 Struct SettingInfo

[Serializable]
public struct SettingInfo{
    public bool Vibration;
    public bool Sound;
    public int Volume;
    public bool BGM;
}




// is Save
public void Save() {
        var b = new BinaryFormatter();
        var m = new MemoryStream();
        b.Serialize(m , _setValue);
        PlayerPrefs.SetString("Setting",Convert.ToBase64String(m.GetBuffer())); 
    }


// is load
public void Load() {
        var data = PlayerPrefs.GetString("Setting");
        if(!string.IsNullOrEmpty(data)) {
            var b = new BinaryFormatter();
            var m = new MemoryStream(Convert.FromBase64String(data));
            _setValue = (SettingInfo) b.Deserialize(m);
                        
        } else {
                 // load data is empty
        }
    }

2013년 11월 21일 목요일

Unity_ Generic Singletone 사용법


*.아래글에 코드가 잘안보여서 다시올립니다 ^^;

Generic Singleton 사용법에 대해서는 수많은.. 정말 무수히 많은 방법론이 존재하지만 제가생각하기에 Unity상에서 사용하기 괜찮은(좋은방법있으면 알려주시길 ㅠㅠ) 코드이다.

Singleton.cs
using UnityEngine;
using System.Collections;

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    protected static T sInstance;

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

            if (sInstance == null)
            {
                Create();
            }

            return sInstance;
        }
    }

    private static void Create()
    {
        if (GameObject.Find("_Singleton"))
        {
            GameObject goInst = GameObject.Find("_Singleton");
            sInstance = goInst.AddComponent<T>();
        }
        else
        {
            GameObject goInst = new GameObject("_Singleton");
            sInstance = goInst.AddComponent<T>();
        }
    }
}


how to used
public class SettingManager : Singleton<Settingmanager> {

    private void OnApplicationQuit() {
        sInstance = null;
    }
}


싱글톤의 가장 기본적인 구조이고 이를 응용하여 생산성을 높이는 방법은 끝도없이 존재한다는 ^^




2013년 8월 18일 일요일

Unity_Tilt 형식의 움직임 구현






1
2
3
4
float tiltAng = Input.acceleration.x; // Device의 기울기값(return value = -1~1)
float speed = 60.0f; // move object speed

transform.Translate (new Vector3 (1, 0, 0) * tiltAng * Time.smoothDeltaTime * speed);
 


게임 기획시 tilt(device의 기울기에 따른 움직임)형식의 
움직임으로 게임을 만들고자 기획하였다면 위의 소스를 참고하시면 됩니다. ^^