블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2794)
Unity3D (852)
Programming (478)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (185)
협업 (11)
3DS Max (3)
Game (12)
Utility (68)
Etc (98)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (55)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday


링크 : http://shader.tistory.com/126

반응형

'Android > cocos2d-x' 카테고리의 다른 글

cocos2d-x (cocos2d c++버전)  (0) 2011.03.28
Posted by blueasa
, |

유니티에서 3D 캐릭터가 달리는 중에 상체만 공격애니메이션을 하게 만드려고 이리저리 삽질한 결과 정리..


[중요사항]

1. 우선 AnimationState.Layer가 같은 애니메이션은 Play(or CrossFade)하려는 애니메이션 외 모두를 정지시키면서 실행된다.

    같이 실행되려면 레이어를 달리해야된다.


2. 그리고, Layer 디폴트는 0이고 Layer 숫자가 높을수록 애니메이션 우선순위가 높다.

    애니메이션 두 개가 동시에 Play 될 때, Layer가 높은 애니메이션이 우선시 된다.


3. AddMixingTransform에 해당 애니메이션이 적용되는 부위(상체라던지..)의 Bone을 찾아서 넣어준다.

예) Transform mixTransform = transform.Find("Bip00 Spine");

      animation["Attack"].AddMixingTransform(mixTransform);


[정리]

animation["RUN"].layer = 0;

animation["ATTACK"].layer = 1;

animation["ATTACK"].blendMode = AnimationBlendMode.Blend;

animation["ATTACK"].AddMixingTransform(trBone); // trBone은 알아서 받기..


- 이렇게 하고 RUN 중에 ATTACK 애니를 CrossFade 해주면 하체는 달리면서 상체는 공격하는 애니가 실행된다.


참조 : http://www.devkorea.co.kr/reference/Documentation/ScriptReference/AnimationState.AddMixingTransform.html

반응형

'Unity3D' 카테고리의 다른 글

간단한 Nav Mesh 예제  (0) 2012.11.21
런타임 중 텍스쳐 교체  (0) 2012.11.20
Unity3d Android 해상도 설정하기 ( Screen.SetResolution )  (0) 2012.11.14
Unity remote 사용방법 (iPhone, Android)  (0) 2012.11.08
Smooth Follow Camera  (0) 2012.11.06
Posted by blueasa
, |

애니메이션 스크립팅 Animation Scripting

유니티의 애니메이션 시스템은 멋지게 애니메이션이 적용된 스키닝이 된 캐릭터를 만드는 것을 가능하게 해줍니다. 애니메이션 시스템은 애니메이션 블렌딩 blending, 믹싱 mixing, 가산 additive 애니메이션, 걷기사이클 시간동기화 walk cycle time synchronization, 애니메이션 레이어, 애니메이션 재생에 관한 모든 면에서의 제어 (시간, 속도, 블렌드 웨이트 blend-weights), 버텍스 당 1, 2, 혹은 4개 본 bone 들의 메쉬 스키닝뿐만 아니라 물리 기반의 랙돌 ragdoll 과 절차적 애니메이션 procedural animation 도 지원합니다. 가장 만족스런 결과를 얻기 위해서는Modeling Optimized Characters 페이지의 유니티에서 최적의 성능을 내는 리깅된 캐릭터 생성을 위한 가장 좋은 방법들과 기법들에 대해 읽어 보시는 것을 추천해 드립니다.

애니메이션 캐릭터를 만드는 것은 두 가지와 관련이 있습니다: 세상에서 그들이 움직이게 만들고 그에 따라 캐릭터가 애니메이션을 하게 만드는 것 입니다. 캐릭터를 움직이는 것에 대해 더 알고 싶으시다면 다음 Character Controller page를 참조하세요. 이 페이지는 애니메이션에 촛점을 맞추고 있습니다. 실제 캐릭터들의 애니메이션 적용은 유니티의 스크립팅 인터페이스를 통해 이루어 집니다.

여기에서 미리 셋업이 된 애니메이션 적용 캐릭터가 있는 example demos를 다운로드 받으세요. 이 페이지에서 기본을 익히면 animation script interface도 보시기 바랍니다.

원하신다면 이 페이지에서 다루는 아래의 주제들을 탐구해 보세요:

애니메이션 블렌딩 Animation Blending

오늘날의 게임에서 애니메이션 블렌딩 blending 은 캐릭터의 부드러운 애니메이션을 위해서 필수적인 요소입니다. 애니메이션을 만드는 사람은 각각의 애니메이션을 만듭니다. 예를 들어, 걷고, 뛰고, 쉴 때 idle 동작, 또는 사격하는 애니메이션이 있습니다. 게임 중에서는 어떤 때라도 가만히 있는 idle 애니메이션에서 걷는 애니메이션 또는 반대로 바꿀 수가 있어야 합니다. 물론 사용자는 움직임이 갑작스레 튀지 않고 부드럽게 전환되는 애니메이션을 원할 것입니다.

이때 필요한 것이 바로 애니메이션 블렌딩입니다. 유니티에서는 하나의 같은 캐릭터에 어떤 수의 애니메이션도 넣을 수가 있습니다. 모든 애니메이션들은 최종 애니메이션을 만들기 위해 서로 섞여지거나 더해집니다.

사용자가 할 첫 스텝은 캐릭터를 가만히 쉬는 애니메이션에서 걷는 애니메이션으로 부드럽게 전환하는 것입니다. 스크립트 작성시 작업을 쉽게 하기위해 애니메이션의 랩 모드 Wrap Mode를 `반복 `Loop으로 설정합니다. 그리고 사용자가 만드는 스크립트가 애니메이션이 재생되는 유일한 것이 되게 자동으로 재생되게 Play Automatically`` 를 꺼놓습니다.

캐릭터를 동작시키기 위한 첫 스크립트는 꽤 간단한 편입니다. 사용자가 알아야 할 것은 단지 캐릭터가 얼마나 빨리 움직이는지 감지할 방법과 걷는 애니메이션과 쉬는 애니메이션 사이에 녹아들어 사라지게 합니다. 이 간단한 테스트를 위해서 미리 설정된 입력 축들 input axes 을 사용합니다.

function Update () {
   if (Input.GetAxis("Vertical") > 0.2)
       animation.CrossFade ("walk");
   else
      animation.CrossFade ("idle");
} 

이 스크립트를 실행하기 위해서는:

  1. Assets->Create Other->Javascript를 이용해 자바 스크립트 Javascript 를 만듭니다.
  2. 그 안에 코드를 복사 & 붙여넣기를 합니다
  3. 스크립트를 캐릭터로 드래그하세요 (그것은 애니메이션과 같은 게임 오브젝트여야 합니다)

사용자가 재생 Play 버튼을 누르고, 위방향키를 누르고 있으면 캐릭터가 걷기 시작하고 손가락을 떼면 쉬는 포즈로 돌아갈 것입니다.

애니메이션 레이어 Animation Layer

레이어는 사용자가 애니메이션을 그룹화하고 가중치 weighting 에 우선 순위를 매기는 것을 가능하게 해주는 굉장히 중요한 개념입니다.

유니티 애니메이션 시스템에서 사용자는 원하는 만큼 애니메이션 클립들을 서로 블렌드 할수 있습니다. 사용자는 수동으로 가중치를 주거나 간단히 자동으로 가중치를 주는 animation.CrossFade()를 이용할 수 있습니다.

블렌드 가중치는 적용되기 전에 항상 정규화됩니다 Blend weights are always normalized before being applied.

걷는 것과 뛰는 애니메이션이 있고 둘 모두 1 (100%) 의 가중치를 가진다고 가정해 보세요. 유니티가 최종 애니메이션을 생성할 때 가중치를 정규화 합니다. 즉 걷는 것과 뛰는 애니메이션이 50%씩의 가중치를 각각 부여하게 되는 것입니다.

하지만 대부분의 경우 사용자는 두 개의 애니메이션이 있을 때 어떤 애니메이션이 더 가중치를 적용받을지 우선 순위를 정하길 원합니다. 물론 이때 모든 가중치의 합이 수동으로 100%가 되도록 할 수도 있겠지만 레이어들을 사용하는 것이 훨씬 쉬운 방법이 됩니다.

레이어만들기 예제 Layering Example

한 예로써 사용자가 사격하고, 쉬고, 그리고 걷는 애니메이션이 있다고 가정합니다. 걷는 애니메이션과 쉬는 애니메이션은 플레이어의 속도에 따라 블렌드되어 섞이겠지만, 사격 버튼이 눌러졌을때는 사격하는 애니메이션만이 나와야 합니다. 그러므로 사격 애니메이션은 이들 중 더 높은 우선 순위를 가지게 됩니다.

이것을 위한 가장 쉬운 방법은 사격 중에도 걷고 쉬는 애니메이션을 재생하게 하는 것입니다. 그러기 위해서는 사격 애니메이션을 쉬거나 걷기 보다 높은 레이어로 위치시켜야 하고 이것은 사격 애니메이션이 블렌드 가중치 blend weights 를 가장 우선 순위로 받게 된다는 뜻입니다. 걷기와 쉬기 애니메이션은 사격 애니메이션이 100% 블렌드 가중치를 다 사용하지 않을 때에만 가중치를 받게 됩니다. 그래서 크로스페이딩 CrossFading 으로 사격 애니메이션을 걷기나 쉬기 애니메이션 안에 들여보낼 때 사격 애니메이션의 가중치는 0에서 시작해 짧은 순간에 100%로 가중치가 변할 것입니다. 처음에 걷기와 정지레이어는 블렌드 가중치를 받지만 사격 애니메이션이 완전히 들어오면 (fade in) 가중치를 전혀 받을 수 없게 될 것입니다. 이것은 정확히 우리가 원하던 바입니다!

function Start () {
   // 모든 애니메이션을 룹으로 설정
   animation.wrapMode = WrapMode.Loop;
   // 사격은 제외
   animation["shoot"].wrapMode = WrapMode.Once;

   // 쉬기와 걷기를 아래 레이어로 놓습니다. (디폴트 레이어는 항상 0)
   // 이것은 두 가지를 할 것입니다.
   // - 사격과 쉬기/걷기는 다른 레이어에 있으므로,
   //   크로스페이드 CrossFade 를 호출할 때 그들은 서로의 재생에 영향을 끼치지 않을 것입니다..
   // - 사격은 더 높은 레이어에 있으므로,
   //  페이드-인 (fade-in) 할때 그 애니메이션은 쉬기/걷기 애니메이션을 대체할 것입니다.
   animation["shoot"].layer = 1;

   // 이미 재생되는 애니메이션을 정지시킵니다.Stop animations that are already playing
   //(사용자가 자동재생을 비활성화 시켰을 경우)
   animation.Stop();
}

function Update () {
   // 눌려진 키에 따라서,
   // 걷기나 쉬기 애니메이션을 재생합니다.
   if (Mathf.Abs(Input.GetAxis("Vertical")) > 0.1)
      animation.CrossFade("walk");
   else
      animation.CrossFade("idle");

   // Shoot
   if (Input.GetButtonDown ("Fire1"))
      animation.CrossFade("shoot");
} 

기본 설정으로 animation.Play()나 animation.CrossFade() 는 같은 레이어에 있는 애니메이션을 정지시키거나 사라지게 fade-out 합니다. 이것이 대부분의 경우 이것은 사용자가 원하는 바입니다. 위의 우리의 예제에서는 쉬기/걷기는 사격 애니매이션에 영향을 주지 않으며 그 반대의 경우도 마찬가지 입니다 (원한다면animation.CrossFade의 옵션 파라미터에서 이 것을 바꿀 수 있습니다).

애니메이션 믹싱 Animation Mixing

애니메이션 믹싱은 애니메이션을 몸의 어떤 일 부분에만 적용시켜 게임에서 생성해야 하는 애니메이션의 수를 줄여줍니다. 이것은 그런 애니메이션들이 다른 애니메이션들과 여러 조합으로 이루어져 사용될 수 있다는 뜻입니다.

사용자는 주어진 애니메이션상태 AnimatioState 에 AddMixingTransform()을 호출하여 애니메이션 믹싱 트랜스폼 animation mixing transform 을 다른 애니메이션에 더합니다.

믹싱 예 Mixing Example

믹싱의 한 예로는 손을 흔드는 애니메이션이 있습니다. 사용자는 캐릭터가 쉬거나 걸을 때 이 손 흔드는 애니메이션을 사용하길 원합니다. 애니메이션 믹싱이 없다면 사용자는 걸으며 손 흔드는 것 쉬면서 손흔드는 두개의 애니메이션을 만들어야 할 것입니다. 그러나 만약 사용자가 손 흔드는 애니메이션에 어깨 트랜스폼을 믹싱 트랜스폼으로써 추가하면, 손 흔드는 애니메이션은 어깨 조인트에서 손까지는 완전히 제어할 수 있게 될 것입니다. 나머지 몸은 그것에 의해 영향을 받지 않기 때문에 캐릭터는 쉬거나 걷는 애니메이션을 계속할 것입니다. 그러므로 몸의 나머지 부분이 쉬거나 걷는 동안에 손이 흔들리게 하려면 위와 같은 단 하나의 애니메이션 만이 필요하게 됩니다.

/// 트랜스폼 변수를 사용하여 믹싱 트랜스폼을 더합니다.
var shoulder : Transform;
animation["wave_hand"].AddMixingTransform(shoulder);

경로 path 를 이용한 또 다른 예.

function Start () {
   // 경로를 이용하여 믹싱 트랜스폼을 더합니다.
   var mixTransform : Transform = transform.Find("root/upper_body/left_shoulder");
   animation["wave_hand"].AddMixingTransform(mixTransform);
}

부가 애니메이션 Additive Animations

부가 애니메이션 Additive animation 과 애니메이션 믹싱은 게임을 위해 생성해야 하는 애니메이션 수를 줄이는 것을 줄이고, 얼굴표정 facial 애니메이션을 만드는데 중요한 역할을 합니다.

사용자가 걷거나 뛰면서 방향을 돌때 옆으로 기우는 캐릭터를 만든다고 가정해 봅시다. 이 경우 각각 애니메이션이 필요한 다음과 같은 네가지 조합이 필요하게 됩니다: 왼쪽으로 기울며 걷기 walk-lean-left, 오른쪽으로 기울며 걷기 walk-lean-right, 왼쪽으로 기울며 뛰기 run-lean-left, 오른쪽으로 기울며 뛰기 run-lean-right. 각 조합을 위해 각각 별개의 애니메이션을 만드는 것은 이와 같은 간단한 경우에도 훨씬 더 많은 추가 작업을 시키게 되고, 다른 액션들이 추가될 때마다 조합의 수는 기하급수적으로 늘어날 것입니다. 다행히도 가산 애니메이션 additive animation 과 믹싱은 단순 움직임들의 조합을 위해 각각 따로 애니메이션을 만들어야 하는 번잡함을 줄여 줍니다.

가산 애니메이션의 예 Additive Animation Example

가산 애니메이션은 한 애니메이션의 효과를 재생중인 다른 애니메이션들 위에 겹치게 overlay 합니다. 가산 애니메이션을 만들때 유니티는 애니메이션 클립의 첫번째 프레임과 현재 프레임의 차이를 계산할 것입니다. 그리고 이 차이를 다른 모든 재생 중인 애니메이션 위에 적용합니다.

다시 아까의 예로 돌아가서 이제 사용자는 왼쪽이나 오른쪽으로 기운 애니메이션을 만들면 유니티는 이것을 걷거나 쉬거나 뛰는 동작의 애니메이션 위에 상위 레이어로 놓을 수 있습니다.

이것을 만들기 위한 코드입니다:

private var leanLeft : AnimationState;
private var leanRight : AnimationState;

function Start () {
   leanLeft = animation["leanLeft"];
   leanRight = animation["leanRight"];

   //기우는 애니메이션 lean animation 을 별개의 레이어에 놓아서,
   //CrossFade 를 호출하는 다른 것들이 그것에 영향을 주지 않도록 합니다.
   leanLeft.layer = 10;
   leanRight.layer = 10;

   //기우는 애니메이션을 가산 additive 으로 설정합니다.
   leanLeft.blendMode = AnimationBlendMode.Additive;
   leanRight.blendMode = AnimationBlendMode.Additive;

   //기우는 애니메이션을 ClampForever 로 설정합니다.
   //ClampForever가 설정되면 애니메이션은 클립의 끝에 도달해도
   //자동적으로 정지되지 않습니다.
   leanLeft.wrapMode = WrapMode.ClampForever;
   leanRight.wrapMode = WrapMode.ClampForever;

   //애니메이션을 활성화 Enable 하고 그것을 완전히 들어오게 fade in 합니다.
   //여기서 사용자는 animation.Play 를 사용하지 않습니다. 왜냐하면
   //그것은 업데이트 함수에서 시간을 수동적으로 조절할 수 있기 때문입니다.
   //대신에 사용자는 그냥 애니메이션을 활성화시키고, 그것을 최대 가중치 weight 로 설정합니다.
   leanRight.enabled = true;
   leanLeft.enabled = true;
   leanRight.weight = 1.0;
   leanLeft.weight = 1.0;

   //테스트를 위해서 걷기 애니메이션을 재생한 후 반복 Loop 을 시킵니다.
   animation["walk"].wrapMode = WrapMode.Loop;
   animation.Play("walk");
}

//모든 프레임을 정규화된 normalized 시간으로 설정합니다.
//사용자가 적용시키기 원하는 정도에 따라서 말입니다.
function Update () {
   var lean = Input.GetAxis("Horizontal");
   // normalizedTime 은 첫 프레임때는 0 이고 클립의 마지막 프레임에는 1 이 됩니다.
   leanLeft.normalizedTime = -lean;
   leanRight.normalizedTime = lean;
} 

팁: 가산 애니메이션을 사용할 때 사용자가 가산 애니메이션과 함께 사용된 모든 트랜스폼 위에 가산이 아닌 다른 일반 애니메이션들도 같이 재생하는 것은 굉장히 중요합니다. 그렇지 않으면 그 애니메이션들은 마지막 프레임의 결과 위에 추가되 얹혀질 것입니다. 이것은 확실히 사용자가 원하는 바가 아닐 것입니다.

순차적으로 캐릭터 애니메이션화 하기 Animating Characters Procedurally

사용자는 가끔 캐릭터의 본 bone 을 순차적으로 애니메이션 만들기를 원합니다. 예를 들어, 사용자는 3D공간에서 캐릭터의 머리가 목표점을 추적하는 스크립트에 의해 조정되어 어느 한 점을 바라보기를 원합니다. 다행히도 유니티에서 본 bone 들은 그 스킨된 메쉬를 움직이는 트랜스폼일 뿐이기에 유니티는 이것을 매우 쉽게 할 수 있습니다. 사용자는 스크립트를 써서 어떤 게임오브젝트의 트랜스폼을 다루듯 캐릭터의 본들도 제어할 수 있는 것입니다.

한가지 중요하게 알아야 할 것은 애니메이션 시스템은 Update() 함수 후에 그리고 LateUpdate() 함수 전에 트랜스폼들을 업데이트 한다는 것입니다. 그러므로 만약 사용자가LookAt() 함수를 사용하고 싶다면 사용자는 사용자가 정말로 애니메이션을 오버라이딩 override 하는 것을 확실히 하기 위해 그 함수를 LateUpdate() 안에서 해야만 합니다.

랙돌 Ragdoll 들도 같은 방법으로 생성됩니다. 사용자는 단지 강체 Rigidbodies, 캐릭터 조인트 Character Joints 그리고 캡슐 충돌체 Capsule Colliders 들을 다른 본들에 붙여주기만 하면 됩니다. 그럼 이것은 사용자의 스킨된 캐릭터를 물리적으로 애니메이션화 하게 됩니다.

애니메이션 플레이백과 샘플링 Animation Playback and Sampling

이 섹션은 유니티에서 애니메이션들이 엔진에 의해 재생될 때 어떻게 샘플링이 되는지 설명해 줍니다.

애니메이션 클립 AnimationClips 들은 보통 고정된 프레임 비율로 만들어 집니다. 예를 들어, 사용자는 3D 맥스나 마야에서 프레임 속도 60fps (frames per second) 의 애니메이션을 만들수 있습니다. 유니티에서 그 애니메이션을 불러올 때 이 프레임 속도는 임포터 importer 에 의해 읽히게 되어 불려온 애니메이션의 데이타도 60 fps로 샘플링 됩니다.

하지만 게임은 일반적으로 다양한 프레임 속도로 실행됩니다. 프레임 속도는 어떤 컴퓨터에서는 다른 컴퓨터에서보다 더 높을 수 있고, 특정 순간에 카메라가 보고 있는 뷰의 복잡도에 따라 1초부터 수 초까지 또 다양한 결과를 냅니다. 기본적으로 이것은 게임이 실행되고 있는 프레임의 정확한 속도에 관해 우리는 어떤 가정도 만들수 없다는 것을 의미합니다. 즉 애니메이션이 60 fps로 만들어 졌어도 이것은 56.72 fps나 83.14 fps 혹은 어떤 다른 fps 속도로도 재생될지 모르는 것입니다.

그래서 그 결과로, 유니티는 애니메이션을 원래 지정되어진 프레임 속도가 아닌 이런 다양한 속도로 샘플링을 하게 됩니다. 다행히도 3D 컴퓨터 그래픽 애니메이션은 개별적으로 분리된 프레임이 아닌 연속적인 커브 curve 로 이루어져 있습니다. 이런 커브들은 원래의 애니메이션의 프레임들의 시간들에 딱딱 들어맞는 것이 아니라 어떤 시간에나 샘플링 될 수 있게 되어 있습니다. 그래서 실제적으로는 만약 게임이 만들어진 것보다 더 높은 프레임 속도로 실행이 될 경우 애니메이션은 애니메이션이 제작된 소프트웨어에서보다 더 부드럽고 유연하게 보일 것입니다.

가장 실제적인 상황에서는 사용자는 유니티가 애니메이션을 다양한 프레임 속도 variable fps 로 샘플을 한다는 것은 무시해도 좋습니다. 하지만 만약 사용자가 트랜스폼이나 속성을 어떤 아주 특정한 설정으로 애니메이트하는 애니메이션들에 의지하는 게임플레이 로직을 가지고 있다면, 사용자는 재샘플링 resampling 이 보이지 않는 곳에서 일어난다는 것을 알고 있어야 합니다. 예를 들어, 만약 사용자가 30프레임에 걸쳐 객체가 0에서 180도로 회전하는 애니메이션을 가지고 있고 그리고 그것이 언제 중간까지 도달했는지 코드에서 알고 싶다면, 사용자는 현재 회전 각도가 90도인지 체크하는 조건문을 만들어서 확인하면 안됩니다. 유니티는 애니메이션을 게임속의 다양한 프레임 속도로 샘플링을 하므로, 회전이 90도가 조금 안될때 샘플링을 하고 나중에는 90도 바로 이후에 할지도 모릅니다. 만약 사용자가 애니메이션에서 어떤 특정 점에 다다랐을 때 알림 받기를 원한다면 AnimationEvent를 이용해야 합니다.

또한 다양한 프레임 속도의 샘플링의 결과로 WrapMode.Once 를 사용한 애니메이션이 재생될 때 정확히 마지막 프레임에서 샘플링되지 않을 수도 있다는 것에 주의하세요. 게임의 한 프레임에서는 애니메이션의 마지막 바로 전에 샘플되고, 다음 프레임에서는 시간이 애니메이션의 길이를 초과해 버려 비활성화되고 더 이상 샘플링이 되지 않을지도 모릅니다. 만약 마지막 프레임이 반드시 샘플링이 되게 해야한다면WrapMode.ClampForever를 사용해야 합니다. 이 경우 사용자가 애니메이션을 직접 멈출때까지 마지막 프레임 샘플링을 계속 할 것입니다.


출처 : http://unitykoreawiki.com/index.php?n=KrMain.AnimationScripting

반응형

'Unity3D > Script' 카테고리의 다른 글

특정시간 뒤에 함수 호출하도록 설정하기 (WaitForSeconds)  (0) 2012.11.21
AnimationEvent 추가 방법  (0) 2012.11.21
WaitForSeconds()  (0) 2012.11.21
Attributes 설명 모음  (0) 2012.11.18
FadeInOut  (0) 2012.10.31
Posted by blueasa
, |

유니티로 게임을 만들었는데
기기마다 해상도의 가로세로 비율이 다 제각각 이여서 개발자 입장에서는 각각의 해상도마다 수정작업을 하러면 좀 짜증이 난다.
뭔가 방법이 있을거 같아서 검색해봤더니 답이 있었다.


Screen.SetResolution 라는 메소드를 사용하면 대부분의 안드로이드 단말기의 해상도에 맞춰 게임화면을 변경할 수 있다.

Screen.SetResolution( 원하는 해상도 width값, 원하는 해상도 height값, 풀스크린 여부 );


나의 경우는 아이폰 해상도 비율인 2:3에 맞춰서 작업을 해두었기 때문에 
안드로이드에서도 2:3 비율로 작업한 이미지들이 짤리지 않게 하기 위해 게임이 실행하는 단말기의 스크린값을 아래와 같이 수정하였다.

Screen.SetResolution(Screen.width, (Screen.width/2)*3, true);  // 2:3 screen rate


겔럭시S 의 경우 해상도가 480 x 800 인데 위와 같이 입력해주면 의도했던 모든 UI가 짤림 없이 화면에 다 보여진다.
단점으로는 이미지가 단말기의 해상도 비율에 따라 UI가 길죽하게 보여지거나 넓직하게 보여지게 된다. 
( 16:9  비율의 디지털TV 에서 4:3 비율의 케이블 방송을 보는것과 같은 현상)


※ 주의 : SetResolution 메소드가 동작하지 않는 단말기도 있다고 한다.



출처 : http://clack.tistory.com/146


반응형
Posted by blueasa
, |

Finite State Machine

Contents

 [hide

Description

This is a Deterministic Finite State Machine framework based on chapter 3.1 of Game Programming Gems 1 by Eric Dybsend. Therea are two classes and two enums. Include them in your project, and follow the explanations to get the FSM working properly. There´s also a complete example script at the end of this page.

Components

  • Transition enum: this enum contains the lables to the transitions that can be fired by the system. Don´t change the first lable, NullTransition, as the FSMSystem class uses it.
  • StateID enum: this is the ID of the states the game may have. You could use references to the real States´ classes but using enums makes the system less susceptible to have code having access to objects it is not supposed to. All the states´ ids should be placed here. Don´t change the first lable, NullStateID, as the FSMSystem class uses it.
  • FSMState class: this class has a Dictionaty with pairs (Transition-StateID) indicating which new state S2 the FSM should go to when a transition T is fired and the current state is S1. It has methods to add and delete pairs (Transition-StateID), a method to check which state to go to if a trasition is passed to it. Two methods are used in the example given to check which transition should be fired (Reason()) and which action(s) (Act()) the GameObject that has the FSMState attached should do. You don´t have to use this schema, but some kind of transition-action code must be used in your game.
  • FSMSystem: This is the Finite State Machine class that each NPC or GameObject in your game must have in order to use the framework. It stores the NPC´s States in a List, has methods to add and delete a state and a method to change the current state based on a transition passed to it (PerformTransition()). You can call this method anywhere within your code, as in a collision test, or within Update() or FixedUpdate().

C# - FSMSystem.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
/**
A Finite State Machine System based on Chapter 3.1 of Game Programming Gems 1 by Eric Dybsand
 
Written by Roberto Cezar Bianchini, Jully 2010
 
 
How to use:
	1. Place the lables for the transitions and the states of the Finite State System
	    in the corresponding enums.
 
	2. Write new class(es) inheriting from FSMState and fill each one with pairs (transition-state).
	    These pairs represent the state S2 the FSMSystem should be if while being on state S1, a
	    transition T is fired and state S1 has a transintion from it to S2. Remember this is a Deterministic FSM. 
	    You can´t have one transition leading to two different states.
 
	   Method Reason is used to determine which transition should be fired.
	   You can write the code to fire transitions in another place, and leave this method empty if you
	   feel it´s more appropriate to your project.
 
	   Method Act has the code to perform the actions the NPC is supposed do if it´s on this state.
	   You can write the code for the actions in another place, and leave this method empyt if you
	   feel it´s more appropriate to your project.
 
	3. Create an instance of FSMSystem class and add the states to it.
 
	4. Call Reason and Act (or whicheaver methods you have for firing transitions and making the NPCs
	     behave in your game) from your Update or FixedUpdate methods.
 
	Assynchronous transitions from Unity Engine, like OnTriggerEnter, SendMessage, can also be used, 
	just call the Method PerformTransition from your FSMSystem instance with the correct Transition 
	when the event occurs.
 
 
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 
AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/// <summary>
/// Place the lables for the Transitions in this enum.
/// Don´t change the first lable, NullTransition as FSMSystem class uses it.
/// </summary>
public enum Transition
{
    NullTransition = 0, // Use this transition to represent a non-existint transition in your system
}
 
/// <summary>
/// Place the lables for the States in this enum.
/// Don´t change the first lable, NullTransition as FSMSystem class uses it.
/// </summary>
public enum StateID
{
    NullStateID = 0, // Use this ID to represent a non-existing State in your system	
}
 
/// <summary>
/// This class represents the States in the Finite State System.
/// Each state has a Dictionary with pairs (transition-state) showing
/// which state the FSM should be if a transition is fired while this state
/// is the current state.
/// Method Reason is used to determine which transition should be fired .
/// Method Act has the code to perform the actions the NPC is supposed do if it´s on this state.
/// </summary>
public abstract class FSMState
{
    protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
    protected StateID stateID;
    public StateID ID { get { return stateID; } }
 
    public void AddTransition(Transition trans, StateID id)
    {
        // Check if anyone of the args is invallid
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("FSMState ERROR: NullTransition is not allowed for a real transition");
            return;
        }
 
        if (id == StateID.NullStateID)
        {
            Debug.LogError("FSMState ERROR: NullStateID is not allowed for a real ID");
            return;
        }
 
        // Since this is a Deterministc FSM,
        //   check if the current transition was already inside the map
        if (map.ContainsKey(trans))
        {
            Debug.LogError("FSMState ERROR: State " + stateID.ToString() + " already has transition " + trans.ToString() + 
                           "Impossible to assign to another state");
            return;
        }
 
        map.Add(trans, id);
    }
 
    /// <summary>
    /// This method deletes a pair transition-state from this state´s map.
    /// If the transition was not inside the state´s map, an ERROR message is printed.
    /// </summary>
    public void DeleteTransition(Transition trans)
    {
        // Check for NullTransition
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("FSMState ERROR: NullTransition is not allowed");
            return;
        }
 
        // Check if the pair is inside the map before deleting
        if (map.ContainsKey(trans))
        {
            map.Remove(trans);
            return;
        }
        Debug.LogError("FSMState ERROR: Transition " + trans.ToString() + " passed to " + stateID.ToString() + 
                       " was not on the state´s transition list");
    }
 
    /// <summary>
    /// This method returns the new state the FSM should be if
    ///    this state receives a transition and 
    /// </summary>
    public StateID GetOutputState(Transition trans)
    {
        // Check if the map has this transition
        if (map.ContainsKey(trans))
        {
            return map[trans];
        }
        return StateID.NullStateID;
    }
 
    /// <summary>
    /// This method is used to set up the State condition before entering it.
    /// It is called automatically by the FSMSystem class before assigning it
    /// to the current state.
    /// </summary>
    public virtual void DoBeforeEntering() { }
 
    /// <summary>
    /// This method is used to make anything necessary, as reseting variables
    /// before the FSMSystem changes to another one. It is called automatically
    /// by the FSMSystem before changing to a new state.
    /// </summary>
    public virtual void DoBeforeLeaving() { } 
 
    /// <summary>
    /// This method decides if the state should transition to another on its list
    /// NPC is a reference to the object that is controlled by this class
    /// </summary>
    public abstract void Reason(GameObject player, GameObject npc);
 
    /// <summary>
    /// This method controls the behavior of the NPC in the game World.
    /// Every action, movement or communication the NPC does should be placed here
    /// NPC is a reference to the object that is controlled by this class
    /// </summary>
    public abstract void Act(GameObject player, GameObject npc);
 
} // class FSMState
 
 
/// <summary>
/// FSMSystem class represents the Finite State Machine class.
///  It has a List with the States the NPC has and methods to add,
///  delete a state, and to change the current state the Machine is on.
/// </summary>
public class FSMSystem
{
    private List<FSMState> states;
 
    // The only way one can change the state of the FSM is by performing a trasintion
    // Don´t change the CurrentState directly
    private StateID currentStateID;
    public StateID CurrentStateID { get { return currentStateID; } }
    private FSMState currentState;
    public FSMState CurrentState { get { return currentState; } }
 
    public FSMSystem()
    {
        states = new List<FSMState>();
    }
 
    /// <summary>
    /// This method places new states inside the FSM,
    /// or prints an ERROR message if the state was already inside the List.
    /// First state added is also the initial state.
    /// </summary>
    public void AddState(FSMState s)
    {
        // Check for Null reference before deleting
        if (s == null)
        {
            Debug.LogError("FSM ERROR: Null reference is not allowed");
        }
 
        // First State inserted is also the Initial state,
        //   the state the machine is in when the simulation begins
        if (states.Count == 0)
        {
            states.Add(s);
            currentState = s;
            currentStateID = s.ID;
            return;
        }
 
        // Add the state to the List if it´s not inside it
        foreach (FSMState state in states)
        {
            if (state.ID == s.ID)
            {
                Debug.LogError("FSM ERROR: Impossible to add state " + s.ID.ToString() + 
                               " because state has already been added");
                return;
            }
        }
        states.Add(s);
    }
 
    /// <summary>
    /// This method delete a state from the FSM List if it exists, 
    ///   or prints an ERROR message if the state was not on the List.
    /// </summary>
    public void DeleteState(StateID id)
    {
        // Check for NullState before deleting
        if (id == StateID.NullStateID)
        {
            Debug.LogError("FSM ERROR: NullStateID is not allowed for a real state");
            return;
        }
 
        // Search the List and delete the state if it´s inside it
        foreach (FSMState state in states)
        {
            if (state.ID == id)
            {
                states.Remove(state);
                return;
            }
        }
        Debug.LogError("FSM ERROR: Impossible to delete state " + id.ToString() + 
                       ". It was not on the list of states");
    }
 
    /// <summary>
    /// This method tries to change the state the FSM is in based on
    /// the current state and the transition passed. If current state
    ///  doesn´t have a target state for the transition passed, 
    /// an ERROR message is printed.
    /// </summary>
    public void PerformTransition(Transition trans)
    {
        // Check for NullTransition before changing the current state
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("FSM ERROR: NullTransition is not allowed for a real transition");
            return;
        }
 
        // Check if the currentState has the transition passed as argument
        StateID id = currentState.GetOutputState(trans);
        if (id == StateID.NullStateID)
        {
            Debug.LogError("FSM ERROR: State " + currentStateID.ToString() +  " does not have a target state " + 
                           " for transition " + trans.ToString());
            return;
        }
 
        // Update the currentStateID and currentState		
        currentStateID = id;
        foreach (FSMState state in states)
        {
            if (state.ID == currentStateID)
            {
                // Do the post processing of the state before setting the new one
                currentState.DoBeforeLeaving();
 
                currentState = state;
 
                // Reset the state ot its desired contition before it can reason or act
                currentState.DoBeforeEntering();
                break;
            }
        }
 
    } // PerformTransition()
 
} //class FSMSystem

Example

Here´s an example that implements the above framework. The gameobject with this script follows a path of waypoints and starts chasing a target if it comes within a certain distance from it. Attach this class to your NPC. Besides the framework transition and stateid enums, you also have to setup a reference to the waypoints and to the target (player). I used FixedUpdate() in the MonoBehaviour because the NPC reasoning schema doesn´t need to be called everyframe, but you can change that and use Update().

using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
 
[RequireComponent(typeof(Rigidbody))]
public class NPCControl : MonoBehaviour
{
    public GameObject player;
    public Transform[] path;
    private FSMSystem fsm;
 
    public void SetTransition(Transition t) { fsm.PerformTransition(t); }
 
    public void Start()
    {
        MakeFSM();
    }
 
    public void FixedUpdate()
    {
        fsm.CurrentState.Reason(player, gameObject);
        fsm.CurrentState.Act(player, gameObject);
    }
 
	// The NPC has two states: FollowPath and ChasePlayer
	// If it´s on the first state and SawPlayer transition is fired, it changes to ChasePlayer
	// If it´s on ChasePlayerState and LostPlayer transition is fired, it returns to FollowPath
    private void MakeFSM()
    {
        FollowPathState follow = new FollowPathState(path);
        follow.AddTransition(Transition.SawPlayer, StateID.ChasingPlayer);
 
        ChasePlayerState chase = new ChasePlayerState();
        chase.AddTransition(Transition.LostPlayer, StateID.FollowingPath);
 
        fsm = new FSMSystem();
        fsm.AddState(follow);
        fsm.AddState(chase);
    }
}
 
public class FollowPathState : FSMState
{
    private int currentWayPoint;
    private Transform[] waypoints;
 
    public FollowPathState(Transform[] wp) 
    { 
        waypoints = wp;
        currentWayPoint = 0;
        stateID = StateID.FollowingPath;
    }
 
    public override void Reason(GameObject player, GameObject npc)
    {
        // If the Player passes less than 15 meters away in front of the NPC
        RaycastHit hit;
        if (Physics.Raycast(npc.transform.position, npc.transform.forward, out hit, 15F))
        {
            if (hit.transform.gameObject.tag == "Player")
                npc.GetComponent<NPCControl>().SetTransition(Transition.SawPlayer);
        }
    }
 
    public override void Act(GameObject player, GameObject npc)
    {
        // Follow the path of waypoints
		// Find the direction of the current way point 
        Vector3 vel = npc.rigidbody.velocity;
        Vector3 moveDir = waypoints[currentWayPoint].position - npc.transform.position;
 
        if (moveDir.magnitude < 1)
        {
            currentWayPoint++;
            if (currentWayPoint >= waypoints.Length)
            {
                currentWayPoint = 0;
            }
        }
        else
        {
            vel = moveDir.normalized * 10;
 
            // Rotate towards the waypoint
            npc.transform.rotation = Quaternion.Slerp(npc.transform.rotation,
                                                      Quaternion.LookRotation(moveDir),
                                                      5 * Time.deltaTime);
            npc.transform.eulerAngles = new Vector3(0, npc.transform.eulerAngles.y, 0);
 
        }
 
        // Apply the Velocity
        npc.rigidbody.velocity = vel;
    }
 
} // FollowPathState
 
public class ChasePlayerState : FSMState
{
    public ChasePlayerState()
    {
        stateID = StateID.ChasingPlayer;
    }
 
    public override void Reason(GameObject player, GameObject npc)
    {
        // If the player has gone 30 meters away from the NPC, fire LostPlayer transition
        if (Vector3.Distance(npc.transform.position, player.transform.position) >= 30)
            npc.GetComponent<NPCControl>().SetTransition(Transition.LostPlayer);
    }
 
    public override void Act(GameObject player, GameObject npc)
    {
        // Follow the path of waypoints
		// Find the direction of the player 		
        Vector3 vel = npc.rigidbody.velocity;
        Vector3 moveDir = player.transform.position - npc.transform.position;
 
        // Rotate towards the waypoint
        npc.transform.rotation = Quaternion.Slerp(npc.transform.rotation,
                                                  Quaternion.LookRotation(moveDir),
                                                  5 * Time.deltaTime);
        npc.transform.eulerAngles = new Vector3(0, npc.transform.eulerAngles.y, 0);
 
        vel = moveDir.normalized * 10;
 
        // Apply the new Velocity
        npc.rigidbody.velocity = vel;
    }
 
} // ChasePlayerState


출처 : http://wiki.unity3d.com/index.php/Finit_State_Machine

반응형

'Unity3D > Design Pattern' 카테고리의 다른 글

유니티 4.2버전에 대한 Simple Observer Pattern  (0) 2013.12.02
Posted by blueasa
, |

스크롤/드래그 이벤트를 받는 방법

  • NGUI에서는 BoxCollider를 붙인 오브젝트만  UICamera의 마우스 이벤트를 받는다
    • BoxCollider 뿐만 아니라  Collider면 다 될 것 같긴 하지만 확인해보진 않았다
  • 따라서 BoxCollider와 UIDragPanelContents를 붙인 오브젝트에 UIForwardEvents 스크립트를 붙인다
  • UIForwardEvents의 OnDrag를 true로 설정하고, UIForwardEvents의 target을 UIDragPanelContents 오브젝트로 지정한다
  • UIDragPanelContents 오브젝트에 UIEventListener 스크립트를 붙이고 이벤트를 받거나, 직접 OnDrag() 를 구현한다
  • OnScroll은 위 과정을 참고하여 알아서 구현한다




반응형

'Unity3D > NGUI' 카테고리의 다른 글

NGUI: Events(Event Functions)  (2) 2012.12.07
NGUI Virtual Joystick  (1) 2012.12.05
유니티 NGUI 에서 라벨에 한글(폰트) 적용하기  (2) 2012.11.05
NGUI - Sticky Floating Text  (0) 2012.10.28
NGUI: HUD Text  (0) 2012.10.26
Posted by blueasa
, |


링크 : http://clack.tistory.com/89

반응형
Posted by blueasa
, |


링크 : http://blog.naver.com/khaetnim/100158344211

반응형

'Unity3D > Effect' 카테고리의 다른 글

Scrolling UVs  (0) 2012.11.08
MeleeWeaponTrail  (0) 2012.10.11
Posted by blueasa
, |

Scrolling UVs

Unity3D/Effect / 2012. 11. 8. 16:03

Scrolling UVs

Overview

A C# script that smoothly scrolls a material's UVs in an arbitrary direction/speed given by "Uv Animation Rate". Supports changing which material index and texture name, but the defaults will work with single material, single texture renderers.

C#

using UnityEngine;
using System.Collections;
 
public class ScrollingUVs : MonoBehaviour 
{
    public int materialIndex = 0;
    public Vector2 uvAnimationRate = new Vector2( 1.0f, 0.0f );
    public string textureName = "_MainTex";
 
    Vector2 uvOffset = Vector2.zero;
 
    void LateUpdate() 
    {
        uvOffset += ( uvAnimationRate * Time.deltaTime );
        if( renderer.enabled )
        {
            renderer.materials[ materialIndex ].SetTextureOffset( textureName, uvOffset );
        }
    }
}



출처 : http://wiki.unity3d.com/index.php/Scrolling_UVs

반응형

'Unity3D > Effect' 카테고리의 다른 글

파티클 한 번만 사용하고 종료하기  (0) 2012.11.08
MeleeWeaponTrail  (0) 2012.10.11
Posted by blueasa
, |

toon-water shader

Unity3D/Shader / 2012. 11. 7. 00:13


링크 : http://forum.unity3d.com/threads/41401-Problem-with-own-toon-water-shader-(lighting)

반응형

'Unity3D > Shader' 카테고리의 다른 글

Toon/Tf2Shader  (0) 2013.07.19
Toon/Basic with Alpha  (0) 2013.07.19
Toon/Lighted with Alpha  (0) 2013.07.19
스크립트로 Shader 변경  (0) 2012.11.06
AlphaVertexColor  (0) 2012.11.04
Posted by blueasa
, |