반응형

EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());

이것을 호출 하면 instantiate 한 GameObject 가 에디터를 껐다 킨 이후에도 정상적으로 저장되어 있음

 

하단은 저장 관련한 내용들..

 

 

I am using Unity 2019.2.6f1

I have a single scene that I am using for the main field of play. All characters are prefabs. Each level is saved to a JSON file that controls which characters are to be loaded for the scene and where they are to be positioned.

I have an editor script (SaveLevel) that will create the JSON file based on how I have the scene configured in the editor. I have a second editor script (LoadLevel) that will read the JSON file and set up the scene for that level.

This is all done in the editor at design time. I can save and load levels fine. However, after I load a level, if I hit the play button, to test the level, the scene resets to an empty scene (how it was before I loaded the level).

How can I load my prefabs into my scene and save the scene so that I can test the level?

Here is my code for loading the level:

-- EDIT -- Based on the response by @Ron the fix is the code change in LoadLevel() below.

 

 

...

 

Are you saying that you run this code inside the editor, see the gameobjects created in the hierarchy and scene view, and when you hit play it resets to an empty scene? – Ron Nov 10 '19 at 20:48

  • Yes, except the scene's not completely empty. All of the gameobjects that are saved with the scene, before I run my script, are still there. Only the gameobjects added by my script are missing. – Don Shrout Nov 10 '19 at 22:22
  • C# != UnityScript (which is a Javascript derivative created for unity). – Llama Nov 11 '19 at 0:51
  • @John thanks for the clarification. I added the UnityScript tag because this is a question about code not just the editor. I didn't realize that UnityScript was the official title for Unity's version of JavaScript. I've only ever used C# with Unity. – Don Shrout Nov 11 '19 at 12:50
  • Can you try calling EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); before you call EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo(); – Ron Nov 13

 

 

 

stackoverflow.com/questions/58790108/load-prefabs-via-script-and-save-scene-in-unity-editor

반응형
반응형

아래 그림 처럼 부모가 Cube 자식이 비어 있는 Sphere 트리거 인 경우 

 

[상황 설정]

자식 오브젝트와 부모 오브젝트 각각에 BoxCollide (Trigger 가 켜진) 와 스크립트가 변로로 존재하고(OnTriggerEnter 가 각각 있는) 부모에만 Rigidbody 가 있다면

 

Sphere 에 충돌시 부모의 OnTriggerEnter 와 자식의 OnTriggerEnter 가 모두 불리는데 

이는 자식과 부모를 하나의 닫힌 Mesh 라고 판단하기 때문

 

그래서 각각 부모와 자식의 스크립트의 OnTriggerEnter 가 호출되게 하려면 

자식에도 Rigidbody 를 추가해줘야 한다

 

 

 

 

 

Trigger in child object calls OnTriggerEnter in parent object

The parent object is a small cube with a box collider trigger to fit and a kinematic rigidbody. the child of that object is an empty with a sphere collider trigger that is larger than the box collider.

different scripts are in both parent and child with OnTriggerEnter functions.

expected behavior: when the larger sphere collider (a component of the child) is triggered without triggering the parent, OnTriggerEnter is called in the child object's script.

observed behavior: when the larger sphere collider is triggered, OnTriggerEnter is called in both the parent and the child scripts.

 

 

 

 

Answer by hoy_smallfry · '13년 Mar월 04일 PM 09시 47분

Read the section labeled "Compound Colliders" on this page.

Long story short, collider shapes can't be concave and the only way to accomplish something concave is to treat all convex colliders in children under a parent as if they are one shape, if the parent is the only one with a rigidbody. So, your parent is treating it as if its a complex shape, hence OnTriggerEnter in your parent is getting called.

Try this: give the child a kinematic rigidbody. This will separate it from the parent collision, but still allow it to be moved by the parent's transform instead of physics.

However, be aware that if one touches or encompasses the other, now that they are seen as separate entities, a collision trigger will get registered between the two, even if it's just at the beginning of the scene. They won't bounce off each other since one is a trigger, but you may want to have each OnTriggerEnter function ignore the other Collider if it matches the tag of the other:

 

 

I hope that helps!

Add comment ·  Hide 11 · Share

buscommando · '13년 Mar월 05일 AM 02시 34분 1

 

I will experiment with this. Thank you much!

The parent's trigger matches the parent's mesh exactly, if something triggers it the parent dies.

The child's trigger is a spatial buffer - if something triggers the child's collider, the parent moves/runs away from the object that triggered it.

I had not considered giving both the parent and the child I$$anonymous$$ rigidbodies, currently only the parent has a rigidbody.

$$anonymous$$y solution in the interim was to remove the collider from the parent and add a second child with its own OnTriggerEnter script and a trigger collider identical to the parent's old collider. It worked but felt kludgey, your solution seems a bit more elegant.

kalibcrone  buscommando · '17년 Jul월 13일 PM 01시 06분 2

 

Just a friendly note, "I$$anonymous$$" stands for "Inverse $$anonymous$$inematics" and doesn't really mean the same thing in this context of a $$anonymous$$inematic RigidBody. The term I$$anonymous$$ is generally used when talking about rigging a model for animation.

pas0003 · '13년 Jun월 03일 AM 10시 27분 0

 

Thank you so much for that tip!! :D

filip_andry · '14년 Jul월 01일 AM 06시 58분 0

 

Thanks, It worked for me.

einzweidrei · '15년 Feb월 24일 AM 10시 42분 1

 

Yes, $$anonymous$$inematic Rigidbody did it exactly. Thanks, this made it work finally after long period of banging my head around. :-)

dgreedy · '15년 Apr월 29일 PM 11시 23분 0

 

Buscommando's solution of seperating the triggers and trigger scripts into separate children of the parent object worked well for me. Thanks.

 

 

ref : answers.unity.com/questions/410711/trigger-in-child-object-calls-ontriggerenter-in-pa.html

반응형
반응형

 

두개 벡터 값을 곱한다 * 연산자가 모호해서 Scale 이 추가 된것이라 볼 수 있다

 

Multiplies two vectors component-wise.

Every component in the result is a component of a multiplied by the same component of b.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
// Calculate the two vectors generating a result.
// This will compute Vector3(2, 6, 12)
 
using UnityEngine;
using System.Collections;
 
public class ExampleClass : MonoBehaviour
{
    void Example()
    {
        print(Vector3.Scale(new Vector3(123), new Vector3(234)));
    }
}
 
 

 

 

ref : 

docs.unity3d.com/ScriptReference/Vector3.Scale.html

반응형
반응형

 

 

        GameObject rootObject = contentsRoot.transform.root.gameObject;

        var all = rootObject.GetComponentsInChildren<Transform>(true);

        foreach (var el in all)

        {

            if(PrefabUtility.IsPartOfRegularPrefab(el.gameObject))

            {

                PrefabUtility.UnpackPrefabInstance(el.gameObject, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);

            }

        }

Colored by Color Scripter

 

 

 

using UnityEngine;

using UnityEditor;

 

public class Example

{

    [MenuItem("Examples/Add BoxCollider to Prefab Asset")]

    static void AddBoxColliderToPrefab()

    {

        // Get the Prefab Asset root GameObject and its asset path.

        GameObject assetRoot = Selection.activeObject as GameObject;

        string assetPath = AssetDatabase.GetAssetPath(assetRoot);

 

        // Load the contents of the Prefab Asset.

        GameObject contentsRoot = PrefabUtility.LoadPrefabContents(assetPath);

 

        // Modify Prefab contents.

        contentsRoot.AddComponent<BoxCollider>();






        // Save contents back to Prefab Asset and unload contents.

        PrefabUtility.SaveAsPrefabAsset(contentsRoot, assetPath);

        PrefabUtility.UnloadPrefabContents(contentsRoot);

    }

 

    [MenuItem("Examples/Add BoxCollider to Prefab Asset"true)]

    static bool ValidateAddBoxColliderToPrefab()

    {

        GameObject go = Selection.activeObject as GameObject;

        if (go == null)

            return false;

 

        return PrefabUtility.IsPartOfPrefabAsset(go);

    }

}

 

 

 

 

 

 

ref : docs.unity3d.com/ScriptReference/PrefabUtility.LoadPrefabContents.html?_ga=2.99521374.1778878325.1608379497-1959443505.1601370427

 

반응형
반응형

개요

기술이 발전하고 시간이 지남에 따라 그래픽카드 성능 역시 계속 발전해왔습니다. 그 덕에 더욱 놀랍고 사실적인 그래픽을 표현할 수 있게 되어왔습니다. 그 결과 현대의 PC 및 콘솔 게임의 그래픽은 현실과 그래픽을 분간하기 어려울 지경입니다. 이토록 그래픽 카드는 얼마나 더 멋진 그래픽을 얼마나 더 고속으로 처리할 수 있는 지가 가장 큰 이슈이고 이에 초점을 맞추어서 발전해왔습니다.

이미지 출처 : http://www.slideshare.net/ozlael/unitylightingslide-public

하지만 모바일 기기의 그래픽카드는 조금 다른 행보를 갖습니다.  모바일기기는 항상 전원이 연결되어있는 상황이 아니기때문에 전력 소모가 가장 큰 이슈가 됩니다. 또한 휴대가 용이하게 만들어야 하기 때문에 칩셋을 얼마나 물리적으로 작게 만드냐가 관건입니다. 게다가 물리적으로 작게 만드려면 쿨러를 장착할 수가 없기때문에 발열도 큰 문제가 됩니다. 이러한 모바일 기기의 특징들때문에 모바일에서는 Tile Based Rendering(타일 기반 렌더링)이라는 독특한 방식을 사용합니다. 이번 글에서는 Tile Based Rendering에 대해서 알아보고, 유니티에서 Tile Based Rendering을 고려시 주의점에 대해 다루고자 합니다.

 

Tile Based Rendering

우선 Tile Based Rendering에 대한 설명에 앞서 데스크톱의 렌더링 과정을 간단히 살펴보겠습니다. OpenGL에서 드로우콜을 날리면 지오메트리 데이터가 버텍스 쉐이더를 거쳐서 트랜스폼된 뒤 레스터화되고 픽셀쉐이더로 넘어가서 픽셀 컬러를 거칩니다. 픽셀쉐이더의 결과물은 바로 프레임 버퍼로 출력이 되면서 필요에따라 블렌딩 처리가 됩니다. 이처럼 드로우콜의 명령이 프레임버퍼까지 전달되는 과정이 한번의 패스로 이루어지고 매번 프레임버퍼 영역 전체가 갱신이 됩니다. 즉, 드로우콜 한번 당 한번에 바로 화면 전체에 렌더링합니다. (그래서 이러한 전통적인 렌더링 방식을 Immediate Mode Rendering이라 부르기도 합니다.)

이미지 출처 : http://www.ntu.edu.sg/home/ehchua/

하지만 모바일에서는 조금은 다른 방식을 사용합니다. 앞서 언급하였듯이 모바일에서는 전력 소모와 물리적 크기 등을 고려해야합니다. 이를 위해서 많은 고려사항들이 반영되며 설계가 됩니다만 그 중 가장 큰 고려 사항중 하나가 바로 대역폭입니다. 대역폭을 넉넉하게 쓰다보면 전력소모가 심해지고 물리적 칩셋 크기도 커집니다. 이는 발열로 이어지게 되는데 당연히 발열을 완화시킬 쿨러를 달 공간도 없습니다. 그래서 모바일에서는 대역폭을 줄이기위해 Tile Based Rendering(이하 TBR)이라는 아키텍쳐를 채용하고 있습니다.

앞서 말했던 것 처럼 전통적으로 데스크톱의 그래픽에서는 드로우콜마다 프레임 버퍼 전체를 갱신합니다. 하지만 높은 해상도의 프레임버퍼 전체를 매 번 갱신하는 것은 높은 메모리 대역폭을 요구하게 됩니다. 따라서 모바일에서는 프레임버퍼 전체를 매 번 갱신하는것이 아니라 타일 단위로 쪼개서 갱신을 하는 방식을 사용합니다. 드로우콜 발생 시 즉시 프레임버퍼에 기록하는 것이 아니라, 칩셋에 내장된 메모리에 존재하는 타일에 렌더링합니다. 이로 인해서 매번 화면 전체를 렌더링 하는 것이 아니라 실제 도형이 그려지는 타일만 렌더링 하게 됩니다.

이미지 출처 : Performance Tuning for Tile-Based Architectures

우선, 프레임버퍼를 일정 크기의 타일로 영역을 나눕니다. (이 타일 크기는 칩셋 벤더마다 차이가 있습니다.) 드로우콜이 발생하면 지오메트리 데이터가 버텍스쉐이더를 거쳐서 트랜스폼을 수행 후 레스터화됩니다. 여기까지는 전통적인 렌더링 방식과 동일합니다만 그 이후부터가 달라집니다. 버텍스 쉐이더의 결과가 바로 픽셀 쉐이더로 넘어가지 않고 타일을 선택하는 과정을 거칩니다. 그 후에 픽셀쉐이더가 수행되고 칩 내부 버퍼에 존재하는 타일에 그려집니다. 그 후 타일들이 완성되면 프레임버퍼에 그려집니다. 이런 식으로 타일 단위로 프레임버퍼를 갱신해주기때문에 적은 대역폭으로도 화면을 렌더링 할 수 있게됩니다.

이미지 출처 : http://wenku.baidu.com/view/85ea8fec998fcc22bcd10dcb.html

 

Tile Based Deferred Rendering

또한, TBR에서 변형되어 파생한 Tile Based Deferred Rendering(이하 TBDR) 라는 방식도 있습니다. 이 방식은 기본적으로는 TBR입니다. 다만 버텍스 쉐이더에서 트랜스폼 연산을 거치고나서 바로 픽셀 쉐이더로 넘기는 것이 아닙니다. 대신 버텍스 쉐이더의 결과를 중간 데이터를 담는 파라미터 버퍼에 담아둡니다. (이 버퍼를 ImgTec에서는 파라미터 버퍼라 부르고, ARM에서는 폴리곤 리스트라 부르는 등 여러 이름이 존재하지만 편의상 파라미터 버퍼로 통일하여 칭하겠습니다.) 이 파라미터 버퍼에 담은 후 픽셀 쉐이더로 바로 넘기는 것이 아니라, 매 드로우 콜 마다 버텍스 쉐이더의 결과를 계속 담아둡니다. 그 후 모든 드로우콜이 끝나면 그때서야 비로소 타일을 렌더링하고 프레임버퍼에 출력합니다. 그렇게되면 한 타일에 들어오는 모든 폴리곤을 한번에 처리 할 수가 있게됩니다. 이 과정에서 타일의 각 픽셀에는 은면제거가 처리되고 나서 도달하기 때문에 픽셀 오버드로우가 발생하지 않습니다. 이러한식으로 TBR을 지연해서 처리하기때문에 Tile Based Deferred Rendering(타일 기반 지연 렌더링)이라고 불립니다. 

이미지 출처 : Unity: iOS and Android - Cross Platform Challenges and Solutions

예전에는 TBDR 방식이 ImgTec의 PowerVR 즉 아이폰과 아이패드에서만 사용되었으나 최근들어서는 다른 칩셋들에서도 사용되고 있습니다. 하지만 여전히 안드로이드 기기는 TBDR보다는 TBR이 많이 사용되고 있습니다. 따라서 현 시점에서는 TBR을 사용하는 디바이스와 TBDR을 사용하는 디바이스가 공존하고 있는 상태입니다. (타일 기반이 아닌 전통적인 렌더링 기법을 쓰는 디바이스는 점유율이 매우 낮아서 논외로 합니다.)

이처럼 모바일에서는 타일 단위로 쪼개서 렌더링하는 방식을 사용하다보니 몇 가지 주의 사항이 존재합니다. 서론이 좀 길어지긴 했는데 결국 전달고자 하는 내용들은 다음과 같습니다.

 

 

 

 



앞선 글에서 설명드린 바와 같이 모바일에서는 타일 단위로 쪼개서 렌더링하는 방식을 사합니다. 그러다보니 전통적인 렌더링 방식에서와는 조금 다른 주의 사항이 몇 가지 존재합니다. 

 

알파블렌딩(Alpha Blending) VS 알파테스트(Alpha Test)

전통적으로 데스크톱 게임의 리소스에는 알파블렌딩보다 알파테스트의 사용이 권장되어왔습니다. 불투명한 철망이라든가 찢어진 옷감같은 경우는 불투명하기때문에 비싼 블렌딩 연산을 사용하기보다는 알파테스트를 사용함으로써 픽셀 연산도 절약하자는 의도였습니다. 하지만 모바일의 TBR(Tile Based Rendering, 타일 기반 렌더링)에서는 정반대로 알파테스트보다는 알파블렌딩의 사용이 권장됩니다. 

알파테스트처리를 하기 위해서는 픽셀쉐이더에서 동적분기(if문)가 사용됩니다. 데스크톱에서는 쉐이더의 동적 분기가 고속으로 처리되지만, 모바일에서는 동적 분기 성능이 취약합니다. 때문에 알파테스트는 쉐이더의 성능윽 하락시키는 원인이 됩니다.

게다가, TBDR(Tile Based Deferred Rendering, 타일 기반 지연 렌더링)에서는 픽셀 차폐의 고속 처리를 깨트립니다. 앞서 언급했다시피 TBDR에서는 여러 드로우콜의 버텍스 쉐이더 결과를 모아두었다가 은면 제거(Hidden Surface Removal)를 거친 뒤 실제 보이는 픽셀만 처리합니다. 하지만 이는 알파테스트를 사용하지 않는 완전한 불투명메시일 경우에만 해당됩니다. 알파테스트를 사용하면 버텍스 처리 단계에서는 해당 폴리곤이 차폐 되는지의 여부를 판단할 수 없기때문에 Deferred 처리를 깨트릴 수 밖에 없게됩니다.

유니티에서는 이를 방지하기위해서 완전 불투명 오브젝트들을 모두 렌더링처리한 후에 알파테스트 오브젝트들을 렌더링합니다. 따라서 알파 테스트를 제한적으로만 사용한다면 그렇게 치명적이지는 않습니다. 하지만 애초에 TBDR 칩셋의 구조가 알파테스트 처리에 적합하지 않기 때문에 알파테스트를 사용하지 않는 것이 좋습니다. 그런 이유로, 유니티의 내장 쉐이더 중 Mobile 카테고리에는 알파 테스트 쉐이더가 존재하지 않습니다.

반면에, 알파블렌딩은 데스크톱에 비해서 고속으로 처리가됩니다. 알파블렌딩과정은 출력 내부적으로 대상 버퍼의 읽기/쓰기가 발생합니다. 데스크톱에서는 DRAM에 존재하는 프레임버퍼 전체에 접근해야하기때문에 높은 대역폭을 잡아먹게됩니다. 하지만 TBR에서는 이 처리가 타일 단위로 이루어지고 칩 내부에 존재하는 메모리에서 이루어지므로 고속으로 처리됩니다.

 

오버드로우

다만 명심해야 할 것은 알파 블렌딩 처리 자체가 빠르다는 것일 뿐이지 오버드로우에서 자유로와진다는 것은 아닙니다. 예를 들어서 넓은 영역의 파티클을 높은 밀도로 뿌리는 것은 여전히 오버드로우 문제를 일으켜서 성능 저하로 직결됩니다. 모바일은 쉐이더 성능이 기종에 따라 천차만별이므로 오버드로우로 인해서 쉐이더 싸이클이 낭비되는 것은 치명적인 문제가 됩니다. 웬만하면 불투명 오브젝트 위주로 리소스를 만들기를 권장합니다. 알파 블렌딩 오브젝트 또는 파티클은 오버드로우를 최대한 피해서 사용하시기를 권장합니다.

 

로우 폴리곤

너무나 당연한 이야기라 뜬금없어 보일수도 있겠지만 많은 폴리곤을 처리하면 성능이 하락합니다. 게다가, TBDR에서는 많은 폴리곤 처리의 부담이 더욱 큽니다. 앞서 설명드린 버텍스 쉐이더의 결과물들을 담아두는 파라미터 버퍼(Parameter Buffer)의 크기는 당연하게도 무한하지 않습니다. 따라서 이 버퍼가 넘쳐버리면 더 이상의 버텍스 쉐이더 결과물을 받아들이지 못하고 버퍼를 비워줘야합니다. 이 버퍼를 비워주기 위해서는 타일의 픽셀 처리 후 프레임버퍼로 출력하는 사이클을 거쳐야합니다. 때문에, 이론상으로는 TBDR에서는 픽셀의 오버드로우가 발생하지 않아야하지만, 현실적으로는 폴리곤이 많을수록 오버드로우가 발생하게 발생하게 됩니다. 그러므로 오브젝트의 렌더링 퀄리티를 높여야한다면 버텍스를 늘리는 것 보다는 픽셀쪽 연산을 늘리는 것이 오히려 이득일 수도 있습니다.

 

렌더 텍스쳐(Render Texture)

렌더 텍스쳐를 사용하면 유니티 내부적으로 렌더 타겟(Render Target)을 변경하는 행위를 거치게됩니다. 이러한 렌더타겟을 변경하는 행위는 데스크톱에서도 성능을 잡아먹는 행위가 됩니다. 렌더 타겟을 바꾸기위해서는 CPU가 GPU를 대기하는 과정을 거치게되면서 CPU와 GPU의 병렬 관계가 잠기 깨지는 현상이 발생하기 때문입니다. 

게다가, TBDR에서는 더욱 치명적인 행위가 됩니다. 렌더 타겟을 변경할 시에는 현재 파라미터 버퍼에 쌓여있는 데이터들을 모두 처리해주고 프레임버퍼에 출력합니다. 그 후 다음 렌더 타겟을 위해서 파라미터 버퍼를 비워줍니다. 이런식으로 렌더 타겟을 바꿀 시 deferred 사이클을 추가적으로 처리해줘야 합니다. 때문에 유니티의 카메라에서 타겟 텍스쳐(Target Texture)로 렌더 텍스쳐를 사용하는 경우에는 TBDR의 효율이 떨어지게 됩니다.

이미지 후처리 효과(Image post process Effect)

최근 디바이스들은 컬러 그레이딩이나 블룸 효과 등 이미지 후처리들을 사용할 수 있을 만큼 성능이 좋아졌습니다. 하지만 이러한 이미지 후처리들을 너무 남발해서 사용하면 안되고 필요한 것만 선택적으로 사용해야 합니다. 

우선, 이미지 후처리들은 내부적으로 렌더 타겟을 변경하는 행위를 합니다. 하지만, 더 큰 문제는 대역폭입니다.  물론 픽셀 처리 능력도 관건이지만 대역폭이 더욱 큰 문제가 됩니다. 이미지 후처리들은 현재 렌더링 한 결과를 담고있는 렌더 타겟을 픽셀쉐이더의 입력 텍스쳐로 가져옵니다. 이 때 입력받는 텍스쳐는 칩 내부에 있는 타일이 아니라 공용 메모리에 있는 렌더 타겟을 가져오기때문에 엄청난 대역폭을 잡아먹게 됩니다. (예 : 1080p) 그러므로 이미지 후처리는 신중하게 사용해야 합니다.

 

카메라 클리어(Clear)

예전의 데스크톱 그래픽카드에서는 한 프레임의 렌더링을 시작하기 전 일부러 화면을 클리어해주지 않고 렌더링을 시작하는 경우도 있었습니다. 하지만 현대의 데스크톱 그래픽카드에서는 반드시 클리어를 해주어야만 하드웨어의 고속 처리를 지원받을 수 있습니다. 이는 모바일 기기의 TBR에서도 마찬가지입니다. 클리어를 수행하여 칩 내부의 버퍼들을 비워줘야만 이후 렌더링 과정을 고속으로 처리할 수 있습니다. 따라서, 유니티의 카메라에서 Clear Flag를 Don’t clear로 두는 것은 데스크톱에서나 모바일에서나 웬만해서는 권장되지 않습니다. 

 

MSAA

데스크톱에서는 MSAA가 매우 큰 부담이 됩니다. 역시 마찬가지로 대역폭이 가장 큰 원인입니다. 예를 들어 1080p해상도의 화면을 MSAA 2X로 처리하려면 2160p만큼의 대역폭이 필요해집니다. DRAM으로부터 그만큼의 대역폭을 요구한 다는 것은 매우 큰 부담이 되는것입니다. 하지만 TBR에서는 이 역시 칩 내부의 타일에서 이루어집니다. 16x16 혹은 32x32정도에 불과한 타일로 MSAA처리해주는 것은 그리 부담이 되지 않습니다. 

유니티에서 MSAA를 사용하기위해서는 퀄리티 셋팅에서 Anti Aliasing을 2 혹은 4로 선택해주면 됩니다. 다만 개인적으로는, 매우 높은 DPI를 자랑하는 대부분의 모바일 기기에서 안티 앨리어싱이 굳이 필요할 지는 모르겠습니다 :)

 

프로파일링

유니티5부터 프레임 디버거(Frame Debugger)가 추가되어서 프레임 별 렌더링 과정을 디버깅해볼 수 있게 되었습니다. 이를 통해서 오브젝트의 렌더링 과정이나 배칭 현황을 손쉽게 확인 해 볼 수 있게 되었습니다.  

이미지 출처 : http://docs.unity3d.com/Manual/FrameDebugger.html

하지만 애석하게도 유니티의 프레임 디버거만으로는 드로우콜 별 GPU 퍼포먼스나 세부 상태를 확인하기는 힘듭니다. 다행히도, 칩셋 벤더마다 렌더링 과정을 세부적으로 프로파일링을 해볼 수 있는 툴을 제공해주고 있습니다. 아드레노 칩셋은 아드레노 프로파일러를 통해서, 말리 칩셋은 말리 프로파일러나 DS-5를 통해서, 아이폰은 XCODE를 통해서 프로파일링을 해볼 수 있습니다.

이미지 출처 : http://www.slideshare.net/ozlael/graphics-opt-ndc

다만 문제가 하나 있습니다. TBR 방식을 사용하는 칩셋은 콜 별 설능을 확인하는데 어려움이 없습니다. 하지만 TBDR 방식을 사용하는 칩셋은 콜 별 성능을 직관적으로 확인하는게 사실상 불가능하다는 것입니다. TBDR은 앞서 언급했다시피, 드로우콜 발생 시 픽셀 쉐이더를 즉시 처리하는 것이 아니라 파라미터 버퍼에 결과를 담아둡니다. 그 후 모든 드로우콜을 마치고 나면 그때서야 실제 렌더링을 수행하기 때문에 콜 별 성능을 실질적으로 확인해 볼 수가 없는 것입니다. 따라서 X-code에서 아이폰의 렌더링을 프로파일링 해보면 성능 관련 숫자가 0으로 나오게 됩니다. 0이 아닌 숫자가 나오는 경우도 있지만 이 역시 신뢰할 수 없는 숫자입니다. 대신 프레임 전체에 걸린 성능을 확인해보거나 콜 당시의 사용 텍스쳐 등 주변 정보로 유추해보는 수 밖에 없습니다. 이처럼 아이폰의 프로파일링은 좀 까다로운 편입니다.

이미지 출처 : http://www.slideshare.net/ozlael/graphics-opt-ndc

 

화면 변화율

TBR에서는 렌더링을 칩 내부의 타일에다 하는 과정은 대역폭을 먹지 않지만, DRAM 영역에 존재하는 프레임 버퍼에 타일을 출력하는 과정에서는 어느 정도는 대역폭이 필요할 수 밖에 없게됩니다. 이러한 대역폭을 조금이나마 절약하기 위해서 말리에서는 트랜잭션 엘리미네이션(Transaction Elimination)이라는 기술을 사용합니다. 타일 별로, 이전 프레임과 화면 결과가 달라지지 않은 타일의 영역은 프레임버퍼를 갱신하지 않고 이전 프레임의 결과를 재활용 하는 것입니다. 그렇게 하면 칩 내부 메모리에서 시스템 메모리로 복사하는 양이 줄어드는 효과를 갖게됩니다. 아래 예시 이미지의 파란 글자 타일이 바로 그 부분에 해당합니다. 

이미지 출처 : http://community.arm.com/

따라서, 고정 카메라를 사용한다면 스카이박스 등의 배경에는 최대한 변화를 피하는 것도 좋은 방법이 될 수도 있습니다. 현실적으로는 3D 게임에는 이러한 조건에 해당하는 경우가 많지는 않을 것입니다. 하지만 2D 게임에는 적합하는 부분이 많은 것입니다.

 

마치며

TBR에 관한 내용이랑 TBDR에 관한 내용을 같이 언급하긴 하였습니다. 하지만 대부분은 아이폰이나 안드로이드폰만 타겟으로 설정하고 개발할 것이고, 플랫폼마다 데이터를 별도로 제작하지는 않을 것이라 예상합니다. 따라서 현실적으로는 TBR, TBDR 모두 고려대상으로 삼고 이러한 사항들을 인지하면서 개발하여야 할 것이라 생각합니다.

 

ref :https://ozlael.tistory.com/24

반응형
반응형

 

시작시 에디터 스크립트 실행

Unity 시작 직후에 사용자의 작업 없이 프로젝트 에디터 스크립트 코드를 실행하는 것이 유용한 경우가 종종 있습니다. 이것은 InitializeOnLoad 속성을 static constructor (정적 생성자)가 있는 클래스에 적용함으로써 얻을 수 있습니다. 정적 생성자는 클래스와 같은 이름의 함수로 정적으로 선언된 함수이며, 반환 값이나 인수가 없습니다(자세한 내용은 여기를 확인하시기 바랍니다) : -

 

1

2

3

4

5

6

7

8

9

using UnityEngine;

using UnityEditor;

[InitializeOnLoad]

public class Startup {

    static Startup()

    {

        Debug.Log("Up and running");

    }

}

 

 

 

 

 

정적 생성자는 어떤 정적 함수와 클래스의 인스턴스가 사용되는 것보다 먼저 호출되는 것이 보증되고 있지만, InitializeOnLoad 속성에 의해 에디터 시작할 때 호출되는 것을 보장합니다.

이 기술이 사용되는 예는 에디터에서 일반 콜백을 설정할 때(“프레임 업데이트” 등) 입니다. EditorApplication 클래스에는 update라는 대리자(Delegate)가 있고, 이것은 에디터가 실행되는 동안 초당 여러 번 호출됩니다. 프로젝트 시작할 때 이 대리자를 사용하려면 다음과 같은 코드를 사용합니다 : -

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

using UnityEditor;

using UnityEngine;

 

[InitializeOnLoad]

class MyClass

{

    static MyClass ()

    {

        EditorApplication.update += Update;

    }

 

    static void Update ()

    {

        Debug.Log("Updating");

    }

}

 

 

 

 

ref : https://docs.unity3d.com/kr/530/Manual/RunningEditorCodeOnLaunch.html

반응형
반응형

 

 

hat I am trying to do is in my Start() method of a prefab GameObject in my scene is I want to get the location of where this prefab is as a string but I cannot figure out how to do this.

Example of how I am using this: I put a Sword Prefab GameObject in my scene and on Start() I would like to get the file directory of where this GameObject is in my project.

 

 

 

Include using UnityEditor;

NOTE: This will only work if the prefab is to to public.

Then use AssetDatabase.GetAssetPath to get the path of the prefab.

public GameObject prefab; void Start(){ string prefabPath = AssetDatabase.GetAssetPath(prefab); Debug.Log("Path: " + prefabPath); }

Edit:

I did some experiment with PrefabUtility.GetPrefabType, PrefabUtility.GetPrefabObject and PrefabUtility.GetPrefabParent. PrefabUtility.GetPrefabParent solved the problem. You don't need to make the prefab public with PrefabUtility.GetPrefabParent.

void Start() { GameObject prefab = GameObject.Find("PrebabTest"); Object GameObject2 = PrefabUtility.GetPrefabParent(prefab); string prefabPath = AssetDatabase.GetAssetPath(GameObject2); Debug.Log("Path: " + prefabPath); }

 

 

ref  : https://stackoverflow.com/questions/36850296/get-a-prefabs-file-location-in-unity

 

Get a prefabs file location in Unity

What I am trying to do is in my Start() method of a prefab GameObject in my scene is I want to get the location of where this prefab is as a string but I cannot figure out how to do this. Example ...

stackoverflow.com

 

 

프리팹을 가져오는 함수는 AssetDatabase.LoadAssetAtPath() 이 함수로 에디터 상에서 얻어올 수 있다

반응형
반응형

MonoBehaviour.Reset()

Leave feedback

 

Description

Reset to default values.

Reset is called when the user hits the Reset button in the Inspector's context menu or when adding the component the first time. This function is only called in editor mode. Reset is most commonly used to give good default values in the Inspector.

// Sets target to a default value. // This could be used in a follow camera.

using UnityEngine;

public class Example : MonoBehaviour { public GameObject target;

void Reset() { //Output the message to the Console Debug.Log("Reset"); if (!target) target = GameObject.FindWithTag("Player"); } }

 

 

ref : https://docs.unity3d.com/ScriptReference/MonoBehaviour.Reset.html

반응형
반응형

Coroutine

C언어 등에서 일반적으로 사용하는 함수는 시작할 때 진입하는 지점이 하나 존재하고 함수가 모두 실행되거나, return 구문에 의해 종료되는 지점을 설정할 수있다.

이러한 함수를 Subroutine( 서브루틴 )이라 부르는데, 코루틴은 이를 더 일반화한 개념으로 진입하는 시점까지 여러 개를 가질 수 있는 함수를 의미한다. 개념적으로만 본다면 서브루틴의 한 종류라고 볼 수 있겠다.

 

C#, JavaScript, Python 등이 제공하는 Generator가 사실 코루틴의 한 형태이다.

 

caller가 함수를 call하고, 함수가 caller에게 값을 return하면서 종료하는 것에 더해 return하는 대신 suspend(혹은 yield)하면 caller가 나중에 esume하여 중단된 지점부터 실행을 이어갈 수 있다.

 

즉, 코루틴 함수가 호출되면 코루틴 함수 내부코드가 실행되고 있다가 suspend 혹은 yield에 의해 함수가 호출된 부분에 값이 반환되고 이후 다시 코루틴 함수를 호출하게 되면 코루틴 함수 내부에 suspend 혹은 yield 지점 이후 코드로 돌아와서 실행을 하게 된다는 말이다.

 

부분적으로, 그리고 특정한 상황이 맞아 떨어졌을 때 실행되는 함수.

 

- 장점

1. 성능

일반적으로 게임에서 코루틴을 사용하지 않는다면 매 프레임마다 Update구문에서 동작을 확인해야하는 상황이 발생한다.

하지만 코루틴을 사용하면 코루틴이 지정한 시간이 후에 자동으로 확인된다.

이러한 점 때문에 특히 모바일 기기에서 코루틴의 활용은 성능 향상에 큰 영향을 미친다.

2. 가독성

코드 가독성이 좋아진다. 이건 써보면 알 것 이다.

 

- 특성

* 특정 작업을 단계적으로 발생하게 한다.

* 시간 흐름에 따라 발생하는 루틴을 작성할 수 있다.

* 다른 연산이 완료될때까지 기다리는 루틴을 작성할 수 있다.

* 비동기가 아니다. = 동시에 발생하지 않는다.

 

 

 

 

Thread

현재에 와서 스레드의 경우는 멀티코어를 넘어서 many 코어 시대로 전환 되고 있기 때문에 이 자원들을 충분히 모두 이용하기 위해 병렬 프로그래밍을 하게 되는데 이 병렬 처리의 핵심도구가 스레드 이다.

 

멀티프로세스 기께에서, 스레드는 실제 다른 스레드와 함께 동시에 코드가 실행 될 수 있다. 하지만 여러 스레드를 사용하는 멀티스레드 프로그래밍은 코드를 이해하기 복잡하게 만든다.

다른 스레드가 특정 부분을 읽고 있는 동시에 그것을 변경할 수 있기 때문이다.

이 때문에, 공유 메모리영역을 만들지 않거나, 공유된 자원을 읽거나 변경시켜야 되는 경우라면, 공유된 자원으로 부터 다른 스레드를 잠궈버림으로써( Lock ) 이런 상황이 발생하지 않도록 하고 있다.

 

스레드를 이용하면 하나의 프로그램에서 한 번에 하나의 일을 처리하는 것이 아니라 동시에 많은 일을 처리할 수 있다.

 

- 특성

* 비동기 이다. = 동시에 발생한다.

 

 

 

 

 

 

ref : https://www.slideshare.net/QooJuice/coroutine-119750550

ref : https://poppy-leni.tistory.com/entry/%EC%BD%94%EB%A3%A8%ED%8B%B4-vs-%EC%93%B0%EB%A0%88%EB%93%9C

반응형
반응형

Why does Mathf.Sign(0.0f) return 1?

According to this wikipedia article it should return 0 if x == 0. Unity3D however returns 1 if x == 0.

Now I'm not sure if I'm blaming Unity3D correctly, maybe I misinterpreted the article. But is there a Math function which does work like Mathf.Sign() only returns 0 when x == 0?

For example I want this:

  1. Mathf.Sign(0.1f) == 1;
  2. Mathf.Sign(10.6f) == 1;
  3. Mathf.Sign(-0.2f) == -1;
  4. Mathf.Sign(0.0f) == 0;

 

 

Answer by whydoidoit · '12년 Jul월 11일 PM 01시 29분

Because 0 is considered a positive number by Unity it returns 1 you will have to test for 0 explicitly or write your own function.

  1. static function Sign(number : float) {
  2. return number < 0 ? -1 : (number > 0 ? 1 : 0);

 

 

https://answers.unity.com/questions/282813/why-does-mathfsign00f-return-1.html

 

Why does Mathf.Sign(0.0f) return 1? - Unity Answers

 

answers.unity.com

 

반응형
반응형

 

메카님의 Any State의 Can Transition To Self 옵션은 자기 자신의 State로도 전이가 가능한지를 체크하는 옵션이다.

 

유니티 메카님 이용할 때 캐릭터 이동 애니메이션 상태제어를 하기위해 아래와 같이 설정했었다.

Trigger로 상태값과 speed값에 따라 모든상태로 전이가 가능하다.

조건에 대해 설정하는데도 시간이 많이 걸렸다.

이 기능을 몰랐을때..하아..

 

 

 

처음엔 아래와 같이 설정했었는데.. 계속 자기 상태로도 전이가 되는것이다.

예를 들면 LeftUp 상태에서 다시 같은 LeftUp상태로 계속 전이가 된다.

8프레임짜리 스프라이트 애니메이션이었는데.. 2번프레임까지 플레이되고 다시 상태 전이로 2번 프레임까지만 플레이 되었다.

 

LeftUp 상태전이 0번 1번 프레임 플레이, LeftUp 상태전이 0번 1번 프레임 플레이

 

 

바로 이기능이다. Any State에서는 Settings에 Can Transition To Self 체크옵션을 빼주면 자기 자신한테 상태이전은 하지 않는다. 이로서 위처럼 깔끔하게 처리를 할수 있었다.



 

ref : https://bbangdeveloper.tistory.com/entry/%EB%A9%94%EC%B9%B4%EB%8B%98-Any-State-Can-Transition-To-Self-%EA%B8%B0%EB%8A%A5

반응형
반응형

Introduction

We wanted to have the enemies in Timefight Zone sort of “burn” into existence when they spawn, and burn away when they die. We began to look into how to do this, and quickly came across something called a dissolve shader.

We're going to assume you have a basic knowledge of Unity shaders for this tutorial, if you don’t, there are lots of excellent tutorials that can familiarize you with the basics just one Google search away.


Basic Dissolve Shader

So thanks to the Unity wiki page I linked above, we have a dissolve shader to work with. It looks like this:

  Shader "Dissolving" {
    Properties {
      _MainTex ("Texture (RGB)", 2D) = "white" {}
      _SliceGuide ("Slice Guide (RGB)", 2D) = "white" {}
      _SliceAmount ("Slice Amount", Range(0.0, 1.0)) = 0.5
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      Cull Off
      CGPROGRAM
      //if you're not planning on using shadows, remove "addshadow" for better performance
      #pragma surface surf Lambert addshadow
      struct Input {
          float2 uv_MainTex;
          float2 uv_SliceGuide;
          float _SliceAmount;
      };
      sampler2D _MainTex;
      sampler2D _SliceGuide;
      float _SliceAmount;
      void surf (Input IN, inout SurfaceOutput o) {
          clip(tex2D (_SliceGuide, IN.uv_SliceGuide).rgb - _SliceAmount);
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }

This shader takes a value (_SliceAmount) and a texture (_SliceGuide), and uses a function called clip() to hide any pixels on _SliceGuide who's brightness is less than _SliceAmount.

Below is a gif showing the basic dissolve shader in action. I mapped the same texture to _SliceGuideand _MainTex to better illustrate how the brightness of the pixel in _SliceGuide determines at which point a pixel is hidden.

 

 

https://thumbs.gfycat.com/RegalWanIrishsetter-mobile.mp4

불러오는 중입니다...

 

Note how the darkest pixels are the first to dissolve when dissolving, and the last to re-appear when un-dissolving.

Adding Burnt Edges

Now for the interesting part, adding the burn effect around the areas that are about to dissolve. If you just want the code, here it is:

    Shader "Dissolving" {
    Properties {
      _MainTex ("Texture (RGB)", 2D) = "white" {}
      _SliceGuide ("Slice Guide (RGB)", 2D) = "white" {}
      _SliceAmount ("Slice Amount", Range(0.0, 1.0)) = 0.5


 _BurnSize ("Burn Size", Range(0.0, 1.0)) = 0.15
 _BurnRamp ("Burn Ramp (RGB)", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      Cull Off
      CGPROGRAM
      //if you're not planning on using shadows, remove "addshadow" for better performance
      #pragma surface surf Lambert addshadow
      struct Input {
          float2 uv_MainTex;
          float2 uv_SliceGuide;
          float _SliceAmount;
      };


      sampler2D _MainTex;
      sampler2D _SliceGuide;
      float _SliceAmount;
 sampler2D _BurnRamp;
 float _BurnSize;


      void surf (Input IN, inout SurfaceOutput o) {
          clip(tex2D (_SliceGuide, IN.uv_SliceGuide).rgb - _SliceAmount);
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
 
 half test = tex2D (_SliceGuide, IN.uv_MainTex).rgb - _SliceAmount;
 if(test < _BurnSize && _SliceAmount > 0 && _SliceAmount < 1){
    o.Emission = tex2D(_BurnRamp, float2(test *(1/_BurnSize), 0));
 o.Albedo *= o.Emission;
 }
      }
      ENDCG
    } 
    Fallback "Diffuse"
  }


We have added a new value (_BurnSize), and a new texture (_BurnRamp). To recap, we are hiding parts of the model using clip(), which hides the pixel if the value passed into it is less than 0. We subtract_SliceAmount from the RGB value (brightness) of _SliceGuide, so if _SliceAmount is greater than the brightness of the given pixel of _SliceGuide, the pixel is hidden.

To add the burn effect, we again subtract _SliceAmount from the RGB value (brightness) of _SliceGuide, and this time if the resulting value is less than _BurnSize, we choose a pixel on _BurnRamp to color the pixel. This means that we can change _BurnSize to modify how far out from the dissolved area gets a burn effect. The higher _BurnSize is, the farther the burn effect extends.


The pixel on _BurnRamp is chosen based on how far past _BurnSize test is. At 0 you get the far left pixel, and as the value approaches _BurnSize you move farther to the right side of the image. So you're generally going to want to have the bright ember colors on the left, and the dimmer charred colors on the right on your _BurnRamp.

Below is a gif of _BurnSize being modified in real time to illustrate it's effect.

 

https://thumbs.gfycat.com/WarlikeKaleidoscopicAplomadofalcon-mobile.mp4

 

 

 

 

Note how increasing _BurnSize does not effect the areas that are dissolved, it merely changes how large the burned area extends.

That's about it. It's a relatively simple effect to achieve, but surprisingly hard to find concrete information on. Hopefully this post will help a few people add a cool effect to their game.

Notes

  • The way we are coloring the burnt edges is by setting the emission (o.Emission) to the color of the pixel we chose off _BurnRamp, as well as multiplying the base color (o.Albedo). This will cause the burnt areas to glow in the dark. If you want to achieve an effect with this shader where the edges shouldn't glow, you'll have to change o.Emission, to o.Albedo, and remove the next line down where we multiply o.Albedo by o.Emission.
  • Our _BurnRamp is designed for a cartoony art style. If your game has a more realistic art style, you may want a smoother gradient.
  • Feel free to use this shader and _BurnRamp in your game. We made this tutorial because we couldn't find any specific information on this type of shader outside paid Unity assets. Hopefully this has been informative, but even if it made absolutely no sense, we'd like for more people to be able to achieve this effect in their games, so just steal our version. :)

 

https://thumbs.gfycat.com/AnimatedUnderstatedJunebug-mobile.mp4

불러오는 중입니다...

https://thumbs.gfycat.com/WellinformedMadAlaskajingle-mobile.mp4

 

 

ref : http://www.codeavarice.com/dev-blog/tutorial-burning-edges-dissolve-shader-in-unity

반응형
반응형

 

 

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

[ExecuteInEditMode]
public class testScript : MonoBehaviour
{
    [SerializeField]
    protected bool awoken = false;

    // Start is called before the first frame update
    void Start()
    {
             awoken = true;
    }

    // Update is called once per frame
    void Update()
    {
   
    }
}

 

이 스크립트를 Create Empty 를 만들어 붙인다

이후 Inspector 에서 awoken 의 값을 체크 해치를 한번 하고

이후 에디터 모드에서 실행한다음 중단 하면!

awoken 값이 true 로 남아 있는 것을 볼 수 있다

반응형
반응형

애니메이터 오버라이드 컨트롤러

애니메이터 오버라이드 컨트롤러는 원본의 애니메이터 컨트롤러를 확장하는 에셋으로 사용된 특정 애니메이션을 대체하지만 원본 구조, 파라미터와 로직을 유지합니다.

이를 통해 여러 배리언트의 동일한 기본 상태 머신을 만들 수 있습니다. 하지만 각각 다른 애니메이션 세트를 이용합니다. 예를 들어, 게임상에서 다양한 NPC 타입이 있지만 각 타입(고블린, 오거, 엘프 등)은 걷기, 대기, 앉기 등 동작에서 고유의 애니메이션을 가집니다.

모든 NPC 타입을 위한 로직을 가진 하나의 “베이스” 애니메이터 컨트롤러를 만들어서 각 타입의 오버라이드를 작성할 수 있으며 이를 각각의 애니메이션 파일에 연결할 수 있습니다.

이를 시연하기 위해 대표적인 애니메이터 컨트롤러 에셋을 살펴보겠습니다.

다음은 간단한 상태 머신을 담고 있는 애니메이터 컨트롤러를 나타내며 여기에는 다음과 같이 생긴 네 방향 블렌드 트리 조절 애니메이션과 대기 상태 에니메이션을 포함하고 있습니다.

이런 일반적인 NPC 상태 머신을 유니크한 애니메이션을 사용하는 오거 타입으로 확장하기 위해서는 애니메이터 오버라이드 컨트롤러를 만들어서 오거의 애니메이션 클립 안에 드롭함으로써 원본 애니메이션 클립을 대체할 수 있습니다. 오거는 더 느리고 무거우며 근육질적인 움직임 같이 다른 대기 방식과 움직임을 가질 수 있습니다. 그러나 애니메이터 오버라이드 컨트롤러를 사용하면 캐릭터의 움직임 상태 사이의 트랜지션과 블렌드가 어떻게 일어나는지에 대한 기본적인 로직이 다른 애니메이션 세트를 가진 캐릭터들 간에 공유될 수 있습니다. 그렇게 되면 상태 머신을 구축하고 변경하는 데 들어가는 작업을 줄일 수 있습니다.

새 애니메이터 오버라이드 컨트롤러를 만드려면 에셋(Assets) -> 생성(Create) 메뉴를 사용하거나 프로젝트 뷰의 생성(Create) 버튼에서 애니메이터 오버라이드 컨트롤러를 선택합니다.

애니메이터 오버라이드 컨트롤러는 애니메이터 컨트롤러와 비슷한 아이콘을 가지고 있지만, 전자는 아이콘 구석에 “플러스” 기호가 있고 후자는 “재생” 기호가 있습니다.

아이콘 비교: 애니메이터 컨트롤러와 애니메이터 오버라이드 컨트롤러 에셋 아이콘을 나란히 놓고 비교
아이콘 비교: 애니메이터 컨트롤러와 애니메이터 오버라이드 컨트롤러 에셋 아이콘을 나란히 놓고 비교

인스펙터에서 새 애니메이터 오버라이드 컨트롤러를 선택할 때, 처음에는 애니메이터 컨트롤러가 할당되지 않은 상태이며 아래와 같은 모습입니다.

애니메이터 컨트롤러가 할당되지 않은 애니메이터 오버라이드 컨트롤러
애니메이터 컨트롤러가 할당되지 않은 애니메이터 오버라이드 컨트롤러

오버라이드 컨트롤러를 사용하기 위해서는 원본 컨트롤러 에셋을 인스펙터의 새로운 오버라이드 컨트롤러에 할당해야 합니다. 이렇게 하면 원본 컨트롤러에 사용된 모든 애니메이션이 오버라이드 컨트롤러의 인스펙터 리스트상에 나타납니다.

기존 컨트롤러를 애니메이터 오버라이드 컨트롤러의 인스펙터로 드래그
기존 컨트롤러를 애니메이터 오버라이드 컨트롤러의 인스펙터로 드래그

다음으로 원본 애니메이션 클립을 오버라이드 하기 위해 새로운 애니메이션을 할당합니다. 이 예제에서 모든 애니메이션 클립은 “오거” 버전으로 오버라이드 되었습니다.

새로운 클립이 할당된 오버라이드 컨트롤러
새로운 클립이 할당된 오버라이드 컨트롤러

오버라이드 컨트롤러는 이제부터 애니메이터 컨트롤러로서 오거 캐릭터의 게임 오브젝트의 Animator 컴포넌트에 사용될 수 있습니다. 이는 원본 애니메이터 컨트롤러와 동일한 로직을 사용하지만 원본 대신 새롭게 할당된 애니메이션을 재생합니다.

Animator 컴포넌트에서 게임 오브젝트에 사용 중인 오버라이드 컨트롤러
Animator 컴포넌트에서 게임 오브젝트에 사용 중인 오버라이드 컨트롤러

https://docs.unity3d.com/kr/current/Manual/AnimatorOverrideController.html

반응형
반응형


애니메이터 뷰

처음 열린 애니메이터 뷰에는 3개의 스테이트(State)가 생성되어 있습니다. 각 스테이트의 역할은 다음과 같습니다.

스테이트 종류
역할
Entry
시작 스테이트로 최초의 진입점이다.
Exit
종료 스테이트로 모든 스테이트가 종료되는 마지막 스테이트다.
Any State
현재 어느 스테이트를 실행하고 있더라도 조건에 만족하면 분기시켜야 하는 스테이트가 있을 경우 사용한다.




Has Exit Time 속성은 수행중인 애니메이션이 다 끝난 후 전이가 되도록 하는 속성입니다. 바로 전이를 발생시키고자 할 때는 Has Exit Time 속성을 언체크합니다.









 유니티 메카님에서는 트랜지션이 일어나는 도중에 다른 트랜지션에 의해서 해당 트랜지션을 중단시킬 수 있는 기능이 있습니다. 이것은 4.x 버전에서는 atomic 설정의 on/off 를 통해서 트랜지션 중단의 가능 여부를 지정할 수 있었습니다. 유니티 5에서는 이 기능을 더 확장하여 더욱 상세한 설정이 가능한 Transition interruption source 옵션 항목이 추가되었습니다. (atomic 설정방식은 5 버전에서는 제거되었습니다.)


 트랜지션의 인스펙터 창을 열어봅니다:



[Settings] 설정 안에 [Interruption Source] 옵션이 있는 것을 볼 수 있습니다. 이 옵션을 통해서 사용자는 해당 트랜지션이 어떤 스테이트의 트랜지션들에 의해서 중단될 수 있는 지를 설정할 수 있습니다. 


 그럼 어떠한 옵션항목이 있는지 드롭다운 메뉴를 열어보겠습니다: 



위 그림에서와 같이 5가지 interruption source 옵션 항목이 있습니다. 그러면 각 항목들이 의미하는 것은 무엇인지 알아보겠습니다. 조금 더 이해를 쉽게 하기 위해서 아래 그림와 같은 상황을 가정한 상태에서 설명할까 합니다:


그림에서 파란색으로 표시된 트랜지션 t 의 Interruption Source를 설정한다고 했을 때 각 옵션 항목들을 아래와 같이 설명할 수 있습니다.


1) None: 트랜지션 t는 어떠한 상황에서도 간섭 받지 않습니다. 4.x 버전에서 atomic을 켰을 때와 동일합니다.


2) Current State: 트랜지션 t는 A 스테이트에서의 다른 트랜지션들에 의해 중단될 수 있습니다. 
그림 상에서 볼 때, 만약 해당 트랜지션이 일어나고 있는 도중에 A->B 또는 A->C의 트랜지션이 일어나는 조건이 만족하게 된다면 트랜지션 t는 중단되고 조건을 충족한 새로운 트랜지션이 일어나게 됩니다.

3) Next State트랜지션 t는 X 스테이트에서의 다른 트랜지션들에 의해 중단될 수 있습니다. 
그림 상에서 볼 때, 만약 해당 트랜지션이 일어나고 있는 도중에 X->Y 또는 X->Z의 트랜지션이 일어나는 조건이 만족하게 된다면 해당 트랜지션은 중단되어 버리고 조건을 충족한 새로운 트랜지션이 일어나게 됩니다.

4) Current State Then Next State트랜지션 t는 A와 X 스테이트의 다른 트렌지션들에 의해 중단될 수 있습니다. 단, A 스테이트가 우선순위가 높으므로, 양쪽 스테이트의 트랜지션들이 서로 동시에 발생할 수 있는 조건일 경우  A 스테이트에 속한 트랜지션이 먼저 선정됩니다.

5) Next State Then Current State트랜지션 t는 A와 X 스테이트의 다른 트렌지션들에 의해 중단될 수 있습니다. Current State Then Next State 와는 반대로 X 스테이트가 우선순위가 높습니다. 따라서 X 스테이트에 속한 트랜지션이 먼저 선정됩니다. 






ref : https://blog.naver.com/sasayakki/221357530573

ref : https://jinhomang.tistory.com/116

반응형
반응형


FYI I also had to use the updated PackageConversion files in order to get everything in my project converted.




Stephan_B

Unity Technologies


Importing the TMP Examples and Extras would have triggered a rebuild of the project solution which indirectly would have resolved the issue.

I meant these and potentially the Library folder.




반응형
반응형

Physics.BoxCastAll  을 사용하다보면(또는 유사 다른 cast) point 값이 0,0,0 으로 

나오거나 또는 normal 값이 이상한 형태로 나오는 것을 볼 수 있는데 이 이유에 대해 살펴봅시다



Physics.BoxCastAll



public static RaycastHit[] BoxCastAll(Vector3 centerVector3 halfExtentsVector3 directionQuaternion orientation = Quaternion.identity, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

Parameters

centerCenter of the box.
halfExtentsHalf the size of the box in each dimension.
directionThe direction in which to cast the box.
orientationRotation of the box.
maxDistanceThe max length of the cast.
layermaskLayer mask that is used to selectively ignore colliders when casting a capsule.
queryTriggerInteractionSpecifies whether this query should hit Triggers.

Returns

RaycastHit[] All colliders that were hit.

Description

Like Physics.BoxCast, but returns all hits.

Notes: For colliders that overlap the box at the start of the sweep, RaycastHit.normal is set opposite to the direction of the sweep, RaycastHit.distance is set to zero, and the zero vector gets returned in RaycastHit.point. You might want to check whether this is the case in your particular query and perform additional queries to refine the result.



박스 단위로 충돌을 검사하는 함수입니다 



유효한 충돌 범위는


(대상 오브젝트의 centerhalfExtents 위치 기준=)maxDistance  > 충돌 가능 범위 >  centerhalfExtents


.99 그이하 미소 범위[e] 에 대해선 소수점 오차로 인해 충돌 판별 되는 양상을 띕니다 




가정


Cast 보낼 오브젝트 위치 정보

pos   : 0,0,-30

scale : 10,10,10


대상 오브젝트 정보 [1]

pos   : 0,0,-5

scale : 10,10,10


maxDistance 15 


그외 정보는 일반적으로 unit 한 정보라 가정합니다(normal 은 당연히 시작 오브젝트에서 대상을 바라본다 가정 합니다)



위의 경우 충돌이 되지만 


대상 오브젝트가 [2]

pos   : 0,0,-4.5

scale : 10,10,10


인 경우에는 충돌되지 않습니다





계산



충돌 시작점 + half

centerhalfExtents 의 위치에서부터 maxDistance 이 계산 됨으로


 -30 + 15 + 5 = -10


즉 대상체의 충돌 검출 시작점은 -10 (충돌 가능 범위 기준) 이내 범위어야합니다



그리하여 (대상 오브젝트가 [2])

-4.5 - 5 = -9.5  의 범위에선 충돌되지 않지만


그리하여 (대상 오브젝트가 [1])

-5.0 - 5 = -10  의 범위에선 충돌 검출을 하게 됩니다



만약 충돌될 대상 오브젝트가 충돌 시작위치의 halfExtents 을 침범하게 된다면?





주의


은 출돌검사를 시작하는 center 위치에서 halfExtents 까지의 범위 안에 충돌체가 들어왔고 이 충돌체와 충돌 하게 되면 pint 값이 0 이 되며

normal 값은 sweep 의 방향에 반대되는 (- 가 곱해진) normal 을 만듭니다






ref : https://docs.unity3d.com/ScriptReference/Physics.BoxCastAll.html


반응형
반응형


First, Download Custom Web Search of Visual Studio Extension program and select Options -> Environment-> keyboard,

and search Custom Web Search shortcut in 'Show commands containing' blank to go Unity web help page, and then assign your short key to 'Press shortcut keys'  








ref : https://forum.unity.com/threads/api-help-shortcut-in-visual-studio.344137/


반응형
반응형



AddListener to OnPointerDown of Button instead of onClick

I'd like to register a callback to the OnPointerDown and OnPointerUp events of the UnityEngine.UI.Button(s) in my game to trigger two different sounds for down and up click. However, only the onClick event is exposed. Is there any clean method to get these properties through code? I'd rather not add the UnityEngine.EventTrigger component to every button individually and set them up in the scene, because of the amount of buttons in my project and I might want to change behaviour while testing, and therefore rather do it from one central location in code.







I was expecting this to be built into the Unity button component, because it's such a common thing to ask for when assigning sounds to buttons and also the button must use it's OnPointerDown event internally to trigger sprite transitions etc. Why wouldn't they just expose these callback publicly like onClick already is?

Anyway, here is my code that got it working:

  1. EventTrigger trigger = buttons[i].gameObject.AddComponent<EventTrigger>();
  2. var pointerDown = new EventTrigger.Entry();
  3. pointerDown.eventID = EventTriggerType.PointerDown;
  4. pointerDown.callback.AddListener((e) => AkSoundEngine.PostEvent(downEvent, gameObject));
  5. trigger.triggers.Add(pointerDown);

For every button that needs additional listeners, I add an EventTrigger component and the appropriate PointerDown EventTriggerType. This has much more overhead than I wanted it to have, but it still works better than adding sound components to 20 buttons manually.

PS: Of course, I'd still be interested in seeing a better solution than mine.

Edit - Custom UI Button

I just figured, that I could also subclass the existing Unity Button to add my desired functionality. I keep forgetting that the UI source is extendable. This works very well and feels much cleaner. Just to spread community knowledge, here is my button extension, which I use to later add two different click sounds for down and up.

  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using UnityEngine.Events;
  4. using UnityEngine.EventSystems;
  5. using System;
  6. // Button that raises onDown event when OnPointerDown is called.
  7. [AddComponentMenu("Aeronauts/AeButton")]
  8. public class AeButton : Button
  9. {
  10. // Event delegate triggered on mouse or touch down.
  11. [SerializeField]
  12. ButtonDownEvent _onDown = new ButtonDownEvent();
  13. protected AeButton() { }
  14. public override void OnPointerDown(PointerEventData eventData)
  15. {
  16. base.OnPointerDown(eventData);
  17. if (eventData.button != PointerEventData.InputButton.Left)
  18. return;
  19. _onDown.Invoke();
  20. }
  21. public ButtonDownEvent onDown
  22. {
  23. get { return _onDown; }
  24. set { _onDown = value; }
  25. }
  26. [Serializable]
  27. public class ButtonDownEvent : UnityEvent { }
  28. }

To make the ButtonDownEvent also show up in the inspector, you will need to subclass the according ButtonEditor as well.

  1. using UnityEditor;
  2. using UnityEditor.UI;
  3. [CustomEditor(typeof(AeButton), true)]
  4. public class AeButtonEditor : ButtonEditor
  5. {
  6. SerializedProperty _onDownProperty;
  7. protected override void OnEnable()
  8. {
  9. base.OnEnable();
  10. _onDownProperty = serializedObject.FindProperty("_onDown");
  11. }
  12. public override void OnInspectorGUI()
  13. {
  14. base.OnInspectorGUI();
  15. EditorGUILayout.Space();
  16. serializedObject.Update();
  17. EditorGUILayout.PropertyField(_onDownProperty);
  18. serializedObject.ApplyModifiedProperties();
  19. }
  20. }



ref : https://answers.unity.com/questions/1226851/addlistener-to-onpointerdown-of-button-instead-of.html

반응형
반응형


material color alpha doesn't seem to work.

I'm doing a simple box-add, and the alpha in the color doesn't seem to work. Code:

  1. var fieldBox : GameObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
  2. fieldBox.transform.parent = this.transform;
  3. fieldBox.transform.renderer.material.color = Color.blue;
  4. fieldBox.transform.renderer.material.color.a = 0.05;

It just comes out solid blue. I'd expect something that was 95% transparent. What simple n00b mistake am I making?

Thanks!




Answer by Olie 

The immediate answer to the question that I asked is: the default shader does not do transparency. +1 to Eric5h5 for that.

However, the useful answer that I was looking for (and eventually found, but after a long-ish search!) was that I want to include this line:

  1. fieldBox.renderer.material.shader = Shader.Find( "Transparent/Diffuse" );

In the code above. So the whole thing looks like this:

  1. var fieldBox : GameObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
  2. fieldBox.transform.parent = this.transform;
  3. fieldBox.transform.renderer.material.color = Color.blue;
  4. fieldBox.transform.renderer.material.color.a = 0.05;
  5. fieldBox.renderer.material.shader = Shader.Find( "Transparent/Diffuse" );

There are, of course, a variety of shaders and more efficient ways to get at them than Find(), but this is the answer for someone just looking to put a transparent cube on their early-on n00b project -- "how hard can it be?!"

I'm sorry you didn't find my answer sufficient, but I did say "You need to use a shader that has transparency." The second part ("The default diffuse shader doesn't") was merely a qualifier to the more important first part. I figured it would have been fairly obvious that you'd take another look at the shader drop-down list, see the "Transparent" section there, and say "Oh, I get it." Because that is exactly the reaction of several people in the past who've asked this question and gotten the same answer from me. I try to provide only the relevant info rather than wasting your time with fluff.

Also, if you find an answer to be unclear, just post a comment under it saying so, and I'll expand it.

Eric: yeah, good points all. Perhaps I wasn't clear that I was trying to do all of this in script, at which point "use a different shader" is, as I said, technically correct but not helpful. I'm not trying to "start up" with you -- I just noticed that a very many of the answers on this site are like that. I come from a strong StackOverflow background, where the answers are typically more overt, it all. No worries, I'll get the hang of things around here.




















ref : https://answers.unity.com/questions/33556/material-color-alpha-doesnt-seem-to-work.html

반응형
반응형



Suppose I have a class Foo and some member data that I wish to encapsulate in a struct Bar, like so:

Code (csharp):
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. public class Foo : MonoBehaviour
  5. {  
  6.     public struct Bar { public int a; public float b; }
  7.     public Bar m_bar;
  8. }

Is there a way for me to make the members of m_bar editable through the Inspector of Foo?



---------------------------------------------------------



Want to re-resurrect, I have also gotten this to work, I got allot of errors, but I copy and pasted your code, swapped some stuff, deleted your code and put in my own and it works,





EDIT: I would also like to note that structs in structs work also, very good for organization!








ref : https://forum.unity.com/threads/how-do-i-make-member-structs-accessible-in-the-editor.36395/

반응형
반응형



박스로 캐스팅을 하는 것이고 인자 중 maxDistance 를 보면 알 수 있듯이 박스를 최대 던지는 거리(캐스팅 거리)가 있다는 것을 알 수 있습니다


인자 중 layermask 마스크 인자는 캐스팅(픽킹) 하고 싶은 레이어만을 선택 할 수 있습니다


All 은 모든 충돌체 박스 캐스팅 충돌체에 의한





충돌 범위는 center + halfExtention  ~   maxDistance + halfExtention 범위까지 체크됩니다





 



public static RaycastHit[] BoxCastAll(Vector3 centerVector3 halfExtentsVector3 directionQuaternion orientation = Quaternion.identity, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

Parameters

centerCenter of the box.
halfExtentsHalf the size of the box in each dimension.
directionThe direction in which to cast the box.
orientationRotation of the box.
maxDistanceThe max length of the cast.
layermaskLayer mask that is used to selectively ignore colliders when casting a capsule.
queryTriggerInteractionSpecifies whether this query should hit Triggers.

Returns

RaycastHit[] All colliders that were hit.

Description

Like Physics.BoxCast, but returns all hits.

Notes: For colliders that overlap the box at the start of the sweep, RaycastHit.normal is set opposite to the direction of the sweep, RaycastHit.distance is set to zero, and the zero vector gets returned in RaycastHit.point. You might want to check whether this is the case in your particular query and perform additional queries to refine the result.


ref : https://docs.unity3d.com/ScriptReference/Physics.BoxCastAll.html


반응형
반응형



How to get a List<> from GetComponents?

GetComponents returns a []. Is there any one-liner way to convert that to a Generic (List or whatever)?





Answer by ArkaneX 

With LINQ (requires using System.Linq;):

  1. var list = GetComponents<SomeComponent>().ToList();

Without LINQ:

  1. var list = new List<SomeComponent>(GetComponents<SomeComponent>());

Code in C#.





ref : https://answers.unity.com/questions/630680/how-to-get-a-list-from-getcomponents.html

반응형
반응형

Can Rigidbody 2D collide with 3D Colliders?

Reading the extra details that this page talks about the colliders, http://docs.unity3d.com/Documentation/Components/class-Rigidbody2D.html, it seems that this 2d Rigid body can only collide with other 2D objects and not 3D objects. I've tried to make the player using a rigid 2d body collide with the regular 3d box collider but it keeps passing through. It does collide with the 2d box collider object below so I know I'm using the rigidbody 2d correctly at least.

Does anyone have any input on this?

2 Replies

 · Add your reply
avatar image
11

Answer by MiaN KhaLiD 

I stumbled upon this issue myself recently, and have found out that its not possible for a 2D object to collide with 3D object and vice versa. Reason being unity uses PhysX for 3D and Box2D for 2D, which are exclusive of each other.

So what options do we have, if we want a hybrid

There are 2 ways we can achieve collision between the 2 systems:

  1. To your 3D object add an empty game object as a child, with RigidBody2D (GravityScale set to 0) & a BoxCollider2D matching the width of the 3D Object. Then receive the collision event in the OnCollisionEnter2D(Collision2D collision) function.

  2. Or you can add a RigidBody and a 3D Collider (say BoxCollider) to your 2D object and receive the collision event in the OnCollisionEnter (Collision collision) function.

Hope it answers the question :)

avatar image
0

Answer by J0hn4n 

Or just make 2 childs one to handle 2d collision events and another one to handle 3d events, EZ. another alternative its just handle your own system already if you dont need physic its EZ too.


ref : https://answers.unity.com/questions/580769/can-rigidbody-2d-collide-with-3d-colliders.html

반응형
반응형

Box Collider 2D -failed verification- warning even when the size is reasonable

I have a script that is executed in Edit Mode, it creates various gameobjects with a Box Collider 2D component attached to each one of them, and rotates their transforms based on a logic in my game. The problem is that some of those Box Collider 2D components fire this warning after they're set:

The collider did not create any collision shapes as they all failed verification. This could be because they were deemed too small or the vertices were too close. Vertices can also become close under certain rotations or very small scaling. "

As I change the rotation from the inspector of some of those created GOs, the Box Collider 2D component works again, so the warning is due to their rotations. Also note that the scale isn't the problem as it's set to 1.

My question is, what do the "working angles" have in common? I can take into account this information in my script to only include those specific angles and therefore generating working Box Colliders. It would be better if there was a solution for this problem regardless of the transform's rotation.



avatar image
2

Answer by Dewald_Bodenstein 

I've just found that, as soon as the rotation is about 90 degrees around the Y or X axis, the BoxCollider2D breaks. As I understand, this would be because its like scaling the collider down on one axis and it ends up being too small.

I am using 3d objects in my scene so the rotation can be necessary. The solution would be to attach the 3d object to a child and rotate the child instead.

avatar image
0

Answer by qateef20031 

I added a Rigidbody2D component and it worked.

ref : https://answers.unity.com/questions/580769/can-rigidbody-2d-collide-with-3d-colliders.html






반응형
반응형



PlayerPrefs 


- 데이터를 간단하게 저장할 수 있게 해주는 클래스

- key값과 데이터를 넣어 저장할 수 있고 , 반대로 key값을 넣어 데이터를 꺼낼 수도 있다.


저장 가능한 데이터 타입

int , float , string


1. 데이터 세팅 방법

PlayerPrefs.SetInt("hero_hp",10); // hero_hp 라는 key 값으로 10의 정수형 데이터를 집어 넣음

이런식으로 SetFloat, SetString 으로 float 와 String 의 값을 넣으면 된다.


2. 데이터 얻어오는 방법

PlayerPrefs.GetInt("hero_hp"); // hero_hp key에 대응하는 값을 돌려준다. key 가 없을경우 기본값을 돌려준다. ( 0 )

마찬가지로 GetFloat , GetString 도 해주면 된다.


3. 데이터 삭제

 ㄱ PlayerPrefs.DeleteKey("hero_hp"); // key값을 넣어 해당 key값을 가진 값을 삭제

 ㄴ PlayerPrefs.DeleteAll();                // 모든 데이터를 삭제


4. 데이터의 유무 체크

PlayerPrefs.HasKey("hero_hp"); 

key값이 존재한다면 true를 반환, 없다면 false 반환



5. 저장 방법

PlayerPrefs.Save();를 호출하면 된다.


6. 저장되는 공간

ㄱ Mac일 경우 : 

 ~/Library/Preferences 폴더에 unity.[company name].[product name].plist 이름으로 저장된다.

ㄴ Windows일 경우 :

 HKCU\Software\[company name]\[product name] 레지스트리에 저장된다.


ㄷ Mac , Web일 경우

~/Library/Preferences/Unity/WebPlayerPrefs  바이너리 파일 아래에 저장된다.

Windows , Web일 경우


 %APPDATA%\Unity\WebPlayerPrefs 에 저장된다.

* Web 에서는 1mb의 용량제한이 있고 웹 플레이어 URL당 하나의 파일을 사용할 수 있다.

 제한이 초과될 경우 PlayerPrefsException 을 던진다.



6. 보안 문제

다른 플랫폼은 테스트해보지 못했으나 맥에선 해당 plist를 열어볼 수 있다. ( 수정은 불가능하지만 )

일단 열어볼 수 있다는 것 하나만으로 보안이 그렇게 높은건 같지 않고, 정 사용하려면 key 값과 데이터를 암호화 해서 사용하는게 좋을듯 하다.



PlayerPrefs

class in UnityEngine

Description

게임 세션(session)사이에 플레이어 preference를 저장하고, preference에 접근합니다.

Mac OS X 에서 PlayerPrefs는 ~/Library/Preferences 폴더에 unity.[company name].[product name].plist의 파일이름으로 저장되며,

On Mac OS X PlayerPrefs are stored in ~/Library/Preferences folder, in a file named unity.[company name].[product name].plist, where company and product names are the names set up in Project Settings. Windows 독립 플레이어에서 PlayerPrefs는 @@HKCU
Software
[company name]
[product name]@@ 키 아래의 레지스트리에 저장되며 standalone players.

웹 플레이어에서 PlayerPrefs는 Mac OS X에서 ~/Library/Preferences/Unity/WebPlayerPrefs아래에 HKCU\Software\[company name]\[product name] key, where company and product names are 웹 플레이어 URL 당, 한개의 preference 파일이 존재하며, 파일 크기는 1메가 바이트로 제한됩니다. 파일 크기가 이 제한 값을 초과하는 경우,

On Linux, PlayerPrefs can be found in ~/.config/unity3d/[CompanyName]/[ProductName] again using the company and product names specified in the Project Settings.

On Windows Store Apps, Player Prefs can be found in %userprofile%\AppData\Local\Packages\[ProductPackageId]>\LocalState\playerprefs.dat

On Windows Phone 8, Player Prefs can be found in application's local folder, See Also: Windows.Directory.localFolder

On Android data is stored (persisted) on the device. The data is saved in SharerPreferences. C#/JavaScript, Android Java and Native code can all access the PlayerPrefs data. The PlayerPrefs data is physically stored in /data/data/pkg-name/shared_prefs/pkg-name.xml.

WebPlayer

On Web players, PlayerPrefs are stored in binary files in the following locations:

Mac OS X: ~/Library/Preferences/Unity/WebPlayerPrefs

Windows: %APPDATA%\Unity\WebPlayerPrefs

웹 플레이어에서 PlayerPrefs는 Mac OS X에서 ~/Library/Preferences/Unity/WebPlayerPrefs아래에

There is one preference file per Web player URL and the file size is limited to 1 megabyte. If this limit is exceeded, SetInt, SetFloat and SetString will not store the value and throw a PlayerPrefsException.

Static Functions

DeleteAllpreference에서 모든 key와 값들을 제거합니다. 사용 시 경고가 뜹니다.
DeleteKey키와 대응하는 값을 삭제합니다.
GetFloatPreference 파일에 존재하는 /key/에 대응하는 값을 반환합니다.
GetIntPreference 파일에 존재하는 /key/에 대응하는 값을 반환합니다.
GetStringPreference 파일에 존재하는 /key/에 대응하는 값을 반환합니다.
HasKey키가 존재하는지 확인합니다.
Save수정된 모든 preferences를 디스크에 씁니다.
SetFloat/key/로 식별된 Preference의 값을 설정합니다.
SetInt/key/로 식별된 Preference의 값을 설정합니다.
SetString/key/로 식별된 Preference의 값을 설정합니다.


ref : http://moonausosigi.tistory.com/entry/%EC%A0%95%EB%A6%AC-playerprefs

ref : https://docs.unity3d.com/kr/530/ScriptReference/PlayerPrefs.html


반응형
반응형



에러 내용 (유니티에서 페이스북(facebook) SDK 추가 후)


Your  Android setup is not correct. See Settings in Facebook menu.

UnityEngine.Debug:LogError(Object)

Facebook.Unity.Editor.XCodePostProcess:OnPostProcessBuild(BuildTarget, String)

UnityEditor.HostView:OnGUI()



위 오류를 해결하기 위해서는 Open SSL 설치하여야 합니다.

(JavaSDK도 없으시면 설치하고요.)



둘 다 없다고 가정하고 진행하겠습니다.

먼저, Open SSL을 아래 홈페이지 접속하여 받아주세요.


1. https://code.google.com/archive/p/openssl-for-windows/downloads

(최신버전 아니고 0.9.8 버전 - 안정적)


2. http://slproweb.com/products/Win32OpenSSL.html

 (공식페이지 최신 버전 받을 수 있음)


위 두 가지 중 선택하여 받으시면 됩니다.

저는 최신 버전에도 버그가 있다기에 0.9.8버전 받았습니다.


다운로드 받고, 설치하거나, 압축을 풀어줍니다.

(설치 시 설치되는 위치가 어딘지 확인해주세요.)


그리고 운영체제 환경과 맞는 걸로 받아야겠죠?

win 64 - 윈도우64비트 / win 32 - 윈도우32비트

일반적으로 win 64일 것 같습니다.



JavaSDK는 아래 오라클 홈페이지에서 받을 수 있습니다.


http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html


마찬가지로 작업환경과 맞는 파일 받아서 설치해주시고요.




두 파일 모두 설치했다면, 다음 단계로 진행하겠습니다.


이번에 설치한 OpenSSL와 JDK에  관한

환경변수를 새로 등록해줘야 합니다.


차근차근 봐볼까요?

먼저 탐색기를 켠 후,

왼쪽에 있는 '내 PC' 위에서 우측 클릭을 하면 위와 같은 설정창이 나옵니다.

거기서 속성을 선택해주세요.


이렇게 화면이 나올 텐데요.

여기서 좌측에 있는 '고급 시스템 설정'을 마우스 좌클릭해주시면 됩니다.


그러면 이렇게 화면이 나왔나요?

여기서 '환경 변수(N)'를 마우스 좌클릭해주세요.


환경 변수 탭에서는

아래쪽에 있는 시스템 변수 중

변수 Path를 찾으셔서 좌클릭해보면

위 사진처럼 파란줄이 되며 선택이 될 것 입니다.

그리고, 편집(I) 버튼을 눌러주세요.


이런식으로 나올 텐데,

여기에 환경 변수를 등록해줘야 합니다.


조금 전에 설치했던 OpenSSL의 bin 위치를 등록해줘야합니다.

(만약 위와 같이 JavaSDK도 등록 안 되어 있다면 같이 등록해주면 됩니다!)


C드라이브에 설치했던 위치를 찾아 등록하면 됩니다.

현재 저는 OpenSSL의 C드라이브에 설치했고,

C:\OpenSSL\bin 위치를 찾아가

그대로 복사하여 환경 변수에 추가해줬습니다.


이렇게요.


만약, OpenSSL 최신 설치하여 OpenSSL-Win64같은 이름이였다면,

'C:\OpenSSL-Win64\bin' 같은식으로 등록해주면 되겠죠?

(설치하여 저장된 위치 기준으로 등록해주시면 됩니다. - 역시 한글이 들어간 루트는 피해주시는 게 좋겠네요.)


마찬가지로 jdk도 등록이 안 되어있다면,

등록된 위치를 찾아가 등록해주세요.

(위에 제가 등록해둔 게 기본 위치입니다!

일반적으로

C:\Program Files\Java\jdk1.8.0_111\bin 같이 프로그램파일스 하위 자바 하위에 있습니다!)



그렇게 환경변수가까지 등록을 잘 마쳤다면,

컴퓨터를 껐다 켠(재시작) 후

유니티에 접속하여 빌드를 다시 시도해보면.

이렇게 오류 없이 정상적으로 빌드되는 것을 확인할 수 있습니다!


(제가 오류 해결하려고 찾아 해결한 방법 기준으로 했기에,

유사하지만 위 방법으로 처리가 안 되신다면 구글링을 더 거쳐보신다면 좋겠네요!)


위와 같은 오류로 안 되던 몇몇 분들께 도움이 되었으면 좋겠습니다.



ref : http://prosto.tistory.com/255 [Prosto]

반응형
반응형

다중 씬 편집(Multi Scene Editing)


다중 씬 편집을 사용하면 에디터에서 한 번에 여러 씬을 열 수 있으며 런타임 시 더욱 간편하게 씬을 관리할 수 있습니다.

에디터에서 여러 씬을 열면 대규모 스트리밍 월드를 생성할 수 있으며 공동으로 씬을 편집할 때 워크플로가 개선됩니다.

이 페이지는 다음 항목을 설명합니다.

  • 에디터에서 다중 씬 편집 통합
  • 에디터 스크립팅 및 런타임 스크립팅 API
  • 현재 알려진 문제

에디터에서

새 씬을 열어서 계층의 현재 씬 리스트에 추가하려면 씬 에셋의 컨텍스트 메뉴에서 씬 애디티브 열기를 선택하거나 프로젝트 창에서 하나 이상의 씬을 계층 구조 창으로 드래그하는 방법을 쓸 수 있습니다.

씬 애디티브 열기는 선택된 씬 에셋을 계층 구조가 보이는 현재 씬에 추가합니다
씬 애디티브 열기는 선택된 씬 에셋을 계층 구조가 보이는 현재 씬에 추가합니다

에디터에 여러 씬을 열어놓으면 각 씬의 콘텐츠가 계층 구조 창에 개별적으로 나타납니다. 각 씬의 콘텐츠는 씬의 이름과 저장 상태를 보여주는 씬 디바이더 바 아래에 표시됩니다.

여러 씬이 동시에 열려 있음을 보여주는 계층 구조 창
여러 씬이 동시에 열려 있음을 보여주는 계층 구조 창

씬은 계층에서 로드되거나 언로드되어 각 씬에 포함된 게임 오브젝트를 나타내거나 숨길 수 있습니다. 계층 구조 창에서 이를 추가 및 제거하는 것과는 다릅니다.

씬 디바이더는 많은 씬이 로드되어 있을 경우 계층 구조 탐색에 도움을 주는 씬 콘텐츠로 숨길 수 있습니다.

여러 씬을 작업할 때 수정된 각 씬의 변경사항은 추후에 저장되어야 하므로 저장되지 않은 여러 씬이 동시에 열려있는 상황이 발생할 수 있습니다. 저장되지 않은 변경사항이 있는 씬은 씬 디바이더 바에서 이름 옆에 별표가 뜹니다.

씬 디바이더의 별표는 해당 씬에 저장되지 않은 변경사항이 있음을 나타냅니다.
씬 디바이더의 별표는 해당 씬에 저장되지 않은 변경사항이 있음을 나타냅니다.

각 씬은 디바이더 바의 컨텍스트 메뉴를 통해 개별적으로 저장될 수 있습니다. 파일 메뉴에서 “씬 저장”을 선택하거나 Ctrl/Cmd + S를 누르면 열려 있는 모든 씬의 변경사항이 저장됩니다.

씬 디바이더 바의 컨텍스트 메뉴로 선택된 씬의 기타 동작을 수행할 수도 있습니다.

로드된 씬의 씬 디바이더 메뉴

Set Active Scene어떤 씬에 새로운 게임 오브젝트를 생성하거나 인스턴스화할지 지정할 수 있습니다. 항상 하나의 씬을 액티브 씬으로 표시해야 합니다.
Save Scene선택된 씬의 변경사항만 저장합니다.
Save Scene As선택된 씬(과 현재의 수정사항)을 새로운 씬 에셋으로 저장합니다.
Save All모든 씬의 변경사항을 저장합니다.
Unload Scene씬을 언로드하나 해당 씬을 계층 구조 창에 유지합니다.
Remove Scene씬을 계층 구조 창에서 언로드하고 제거합니다.
Select Scene Asset프로젝트 창에서 씬의 에셋을 선택합니다.
GameObject선택된 씬에서 게임 오브젝트를 생성하게 해주는 서브 메뉴를 제공합니다. 메뉴는 Unity의 메인 게임 오브젝트 메뉴에서 생성가능한 아이템을 미러링합니다. (아래 참조)
씬 디바이더 바 메뉴의 게임 오브젝트 서브 메뉴
씬 디바이더 바 메뉴의 게임 오브젝트 서브 메뉴

언로드된 씬의 씬 디바이더 메뉴

Load Scene씬의 콘텐츠를 로드합니다.
Remove Scene계층 구조 창에서 씬을 제거합니다.
Select Scene Asset프로젝트 창에서 씬의 에셋을 선택합니다.

여러 씬에서 라이트맵(Lightmaps) 베이킹

여러 씬의 Lightmap data를 한 번에 베이크하려면 베이크할 씬을 열고 라이팅 창에서 “자동” 모드를 해제한 후 조명을 빌드하기 위해 빌드 버튼을 클릭합니다.

조명 산출의 입력은 모든 씬에서의 정적 지오메트리와 광원입니다. 따라서 섀도우와 GI 광원 바운스는 모든 씬에서 작동합니다. 하지만 라이트맵과 리얼타임 GI 데이터는 각 씬마다 개별적으로 로드/언로드되는 데이터로 분리됩니다. 라이트맵과 리얼타임 GI 데이터 아틀라스는 씬별로 나뉩니다. 이는 씬별 라이트맵이 공유되지 않으며 씬을 언로딩할 때 안전하게 언로드될 수 있음을 의미합니다. 현재 라이트 프로브 데이터는 언제나 공유되며 함께 베이크된 모든 씬에서 라이트 프로브 전체가 동시에 로드됩니다.

아니면 에디터 스크립트의 Lightmapping.BakeMultipleScenes 함수로 여러 씬에서 라이트맵 빌딩을 자동화할 수 있습니다.

여러 씬에서 내비메시(Navmesh) 데이터 베이킹

여러 씬에서 한 번에 Navmesh data를 만들려면 베이크할 씬을 열고 내비게이션 창에서 베이크 버튼을 클릭합니다. 내비메시 데이터는 하나의 에셋으로 베이크되며 로드된 모든 씬에서 공유됩니다. 데이터는 현재 사용 중인 씬의 이름과 일치하는 폴더에 저장됩니다(예를 들어, ActiveSceneName/NavMesh.asset). 로드된 모든 씬은 내비메시 에셋을 공유합니다. 내비메시를 베이크한 후 영향을 받은 씬은 씬에서 내비메시로 참조가 유지되도록 저장해야 합니다.

아니면 에디터 스크립트의 NavMeshBuilder.BuildNavMeshForMultipleScenes 함수로 여러 씬에서 내비메시 데이터 빌딩을 자동화할 수 있습니다.

플레이모드(Playmode)

플레이모드에서 여러 씬이 계층 구조에 있는 상태로 DontDestroyOnLoad라는 추가 씬이 나타납니다.

Unity 5.3 이전에는 “DontDestroyOnLoad”로 표시된 플레이모드에서 인스턴스화하는 모든 오브젝트가 여전히 계층 구조에 표시되어 있습니다. 이러한 오브젝트는 특정 씬의 일부로 간주되진 않지만 Unity가 계속 오브젝트를 보여주고 사용자가 확인할 수 있도록 이제는 DontDestroyOnLoad 씬의 일부로 나타납니다.

DontDestroyOnLoad 씬에 액세스할 필요는 없으며 런타임 시에는 가능하지 않습니다.

씬별 설정

일부 설정은 각 씬에 지정되며, 예시는 다음과 같습니다.

  • RenderSettings 및 LightmapSettings(둘 다 라이팅 창에 있음)
  • 내비메시 설정
  • 오클루전 컬링 창의 씬 설정

각 씬은 자체 설정을 관리하고 해당 씬에 관련된 설정만 씬 파일에 저장되는 방식으로 작동합니다.

여러 씬이 열려 있으면 렌더링과 내비메시에 사용되는 설정은 active scene의 설정입니다. 씬의 설정을 변경하려는 경우 하나의 씬만 열어서 설정을 바꾸거나 해당 씬을 액티브 씬으로 만들어 설정을 변경해야 합니다.

에디터 또는 런타임 시점에 액티브 씬을 전환하면 새로운 씬의 모든 설정이 적용되며 이전 설정을 모두 대신합니다.

스크립팅

에디터 스크립팅(Editor Scripting)

에디터 스크립팅용으로 Scene struct와 EditorSceneManager API, SceneSetup 유틸리티 클래스를 제공합니다.

Scene struct는 에디터와 런타임 모두에서 가능하며 씬 자체에 관련된 이름, 에셋 경로 등 읽기 전용의 프로퍼티 일부를 포함합니다.

EditorSceneManager class는 에디터에서만 가능합니다. SceneManager에서 유래되며 에디터 스크립팅을 통해 위에 설명한 모든 다중 씬 편집 기능을 구현할 수 있는 함수를 보유합니다.

SceneSetup class는 현재 계층 구조에 있는 씬에 대한 정보를 저장하는 소규모 유틸리티 클래스입니다.

Undo와 PrefabUtility 클래스는 여러 씬을 지원하도록 확장됐습니다. 이제는 주어진 씬에서 프리팹을 [PrefabUtility.InstantiatePrefab]으로 인스턴스화할 수 있습니다. 또한 (Undo.MoveGameObjectToScene)[ScriptRef:Undo.MoveGameObjectToScene]를 활용해 실행 취소 가능한 방식으로 오브젝트를 씬의 루트로 옮길 수 있습니다.

참고Undo.MoveGameObjectToScene를 사용하려면 게임 오브젝트가 이미 현재의 씬 루트에 위치하는지를 확인해야 합니다.

런타임 스크립팅(Runtime Scripting)

런타임 시점의 스크립팅과 관련하여 LoadScene과 UnloadScene처럼 여러 씬에 작동하는 함수는 SceneManager 클래스에서 볼 수 있습니다.

참고

파일 메뉴에서 다른 이름으로 저장은 액티브 씬만 저장합니다. 씬 저장은 제목 없는 씬이 있다면 이름을 지정하는 작업을 포함하여 수정된 모든 씬을 저장합니다.

프로젝트 창의 생성 메뉴에서 새로운 씬 에셋 만들기
프로젝트 창의 생성 메뉴에서 새로운 씬 에셋 만들기

팁과 요령

씬을 계층 구조에 추가하는 한편 드래그할 때 Alt 키를 눌러 언로드된 상태를 유지할 수 있습니다. 이러한 경우 나중에 원할 경우 씬을 로딩할 수 있는 옵션이 주어집니다.

새 씬은 프로젝트 창의 생성 메뉴에서 생성됩니다. 새 씬은 게임 오브젝트의 디폴트 설정을 포함합니다.

Unity를 새로 시작할 때마다 계층 구조를 설정해야 하는 상황을 피하거나 서로 다른 설정을 손쉽게 저장할 수 있도록 EditorSceneManager.GetSceneManagerSetup을 활용하여 현재 설정을 기술하는 SceneSetup 오브젝트 리스트를 얻을 수 있습니다. 그리고 이를 씬 설정에 저장할 기타 정보와 더불어 ScriptableObject 등으로 직렬화할 수 있습니다. 계층을 복원하려면 SceneSetups 리스트를 다시 생성하고 EditorSceneManager.RestoreSceneManagerSetup를 활용하십시오.

런타임 동안 로드된 씬의 리스트를 얻으려면 sceneCount를 받은 후 GetSceneAt를 씬에 반복적으로 적용합니다.

게임 오브젝트가 속한 씬을 GameObject.scene으로 얻을 수 있으며 SceneManager.MoveGameObjectToScene을 활용해 게임 오브젝트를 씬의 루트로 옮길 수 있습니다.

씬에서 남겨두기 원하는 게임 오브젝트를 지속적으로 관리하는 데 DontDestroyOnLoad를 사용하는 것은 권장하지 않습니다. 대신 모든 매니저가 있는 manager scene을 생성하고 게임 프로세스를 관리할 때 SceneManager.LoadScene(<path>, LoadSceneMode.Additive)SceneManager.UnloadScene을 활용하십시오.

알려진 사항

  • 크로스씬 레퍼런스는 지원되지 않지만 사용할 수 없는 것은 아닙니다. 씬을 저장할 수 없으므로 편집 모드에서는 크로스씬 레퍼런스를 사용할 수 있습니다.
  • Umbra의 오클루전 컬링 데이터는 추가로 로드되지 않습니다.


ref : https://docs.unity3d.com/kr/current/Manual/MultiSceneEditing.html

반응형
반응형



WaitUntil

Description

Suspends the coroutine execution until the supplied delegate evaluates to true. (이건 조건이 true 면 WaitUntil 종료)

WaitUntil can only be used with a yield statement in coroutines.

Supplied delegate will be executed each frame after script MonoBehaviour.Update and before MonoBehaviour.LateUpdate. When the delegate finally evaluates to true, the coroutine will proceed with its execution.

using UnityEngine;
using System.Collections;

public class WaitUntilExample : MonoBehaviour { public int frame;

void Start() { StartCoroutine(Example()); }

IEnumerator Example() { Debug.Log("Waiting for princess to be rescued..."); yield return new WaitUntil(() => frame >= 10); Debug.Log("Princess was rescued!"); }

void Update() { if (frame <= 10) { Debug.Log("Frame: " + frame); frame++; } } }

Constructors

WaitUntilInitializes a yield instruction with a given delegate to be evaluated.

Inherited Members

Properties

keepWaitingIndicates if coroutine should be kept suspended.





WaitWhile



Description

Suspends the coroutine execution until the supplied delegate evaluates to false(이건 조건이 false 이면 WiatWhile 종료)

WaitWhile can only be used with a yield statement in coroutines.

The supplied delegate will be executed each frame after MonoBehaviour.Update and before MonoBehaviour.LateUpdate. When the delegate finally evaluates to false, the coroutine will proceed with its execution.

using UnityEngine;
using System.Collections;

public class WaitWhileExample : MonoBehaviour { public int frame;

void Start() { StartCoroutine(Example()); }

IEnumerator Example() { Debug.Log("Waiting for prince/princess to rescue me..."); yield return new WaitWhile(() => frame < 10); Debug.Log("Finally I have been rescued!"); }

void Update() { if (frame <= 10) { Debug.Log("Frame: " + frame); frame++; } } }

Constructors

WaitWhileInitializes a yield instruction with a given delegate to be evaluated.

Inherited Members

Properties

keepWaitingIndicates if coroutine should be kept suspended.



ref : https://docs.unity3d.com/ScriptReference/WaitWhile.html

ref : https://docs.unity3d.com/ScriptReference/WaitUntil.html


반응형
반응형

이벤트 함수 실행 순서(Execution Order of Event Functions)

Unity 이벤트 함수는 사전에 정해진 순서대로 실행됩니다. 실행 순서는 다음과 같습니다.

에디터

  • Reset: 오브젝트에 처음 연결하거나 Reset 커맨드를 사용할 때 스크립트의 프로퍼티를 초기화하기 위해 Reset을 호출합니다.

첫 번째 씬 로드

다음 함수는 씬이 시작할 때(씬에서 오브젝트마다 한 번) 호출됩니다.

  • Awake: 이 함수는 항상 Start 함수 전에 호출되며 프리팹이 인스턴스화 된 직후에 호출됩니다. 게임 오브젝트가 시작하는 동안 비활성 상태인 경우 Awake 함수는 활성화될 때까지 호출되지 않습니다.
  • OnEnable: (오브젝트가 활성화된 경우에만): 오브젝트 활성화 직후 이 함수를 호출합니다. 레벨이 로드되거나 스크립트 컴포넌트를 포함한 게임 오브젝트가 인스턴스화될 때와 같이 MonoBehaviour를 생성할 때 이렇게 할 수 있습니다.
  • OnLevelWasLoaded: 이 함수는 세 레벨이 로드된 게임을 통지하기 위해 실행됩니다.

씬에 추가된 모든 오브젝트에 대해 Start, Update 등 이전에 호출된 모든 스크립트를 위한 Awake 및 OnEnable 함수가 호출됩니다. 

원래 오브젝트가 게임플레이 도중 인스턴스화될 때 실행되지 않습니다.


[첨부]

  • (오브젝트 두개 A, B 추가해 놓고 각각 다른 스크립트를 붙여 놓은 후 awake, onenable, start  실행 순서의 관계를 보면 Awake 와 OnEnalbe 의 경우 
    동일한 오브젝트의 Awake 와 OnEnalbe 이 호출되는 순서를 보인다, 
    즉 A 오브젝트에 붙인 스크립트에 Awake ,가 호출된 후 OnEnalbe 이호출 되고
    B 오브젝트에 붙인 스크립트에 Awake ,가 호출된 후 OnEnalbe 이호출 되는 Awake 와 OnEnable 의 세트적인? 경향을 보이고 다음
    Awake 와 OnEnalbe 의 호출이 다른 오브젝트 들에서 모두 완료 된 이후에 각각 한번씩 Start 함수가 호출되기 시작한다


첫 번째 프레임 업데이트 전에

  • Start: 스크립트 인스턴스가 활성화된 경우에만 첫 번째 프레임 업데이트 전에 호출됩니다.

씬에 추가된 모든 오브젝트에 대해 Update 등 이전에 호출된 모든 스크립트를 위한 Start 함수가 호출됩니다. 원래 오브젝트가 게임플레이 도중 인스턴스화될 때 실행되지 않습니다.

프레임 사이

  • OnApplicationPause: 이 함수는 일시 정지가 감지된 프레임의 끝, 실질적으로는 일반 프레임 업데이트 사이에 호출됩니다. 게임에 일시정지 상태를 가리키는 그래픽스를 표시하도록 OnApplicationPause 가 호출된 후에 한 프레임이 추가로 실행됩니다.

업데이트 순서

게임 로직, 상호작용, 애니메이션, 카메라 포지션의 트랙을 유지할 때, 사용 가능한 몇몇 다른 이벤트가 존재합니다. 일반적인 패턴은 Update 함수에 대부분의 작업을 수행하는 것이지만, 사용할 수 있는 다른 함수도 있습니다.

  • FixedUpdate: FixedUpdate 는 종종 Update 보다 더 자주 호출됩니다. 프레임 속도가 낮은 경우 프레임당 여러 번 호출될 수 있으며 프레임 속도가 높은 경우 프레임 사이에 호출되지 않을 수 있습니다. 모든 물리 계산 및 업데이트는 FixedUpdate 후 즉시 발생합니다. FixedUpdate 의 움직임 계산을 적용할 때 Time.deltaTime 만큼 값을 곱할 필요가 없습니다. FixedUpdate 가 프레임 속도와 관계없이 신뢰할 수있는 타이머에서 호출되기 때문입니다.

  • Update: Update 는 프레임당 한 번 호출됩니다. 프레임 업데이트를 위한 주요 작업 함수입니다.

  • LateUpdate: LateUpdate 는 Update 가 끝난 후 프레임당 한 번 호출됩니다. Update 에서 수행된 모든 계산은 LateUpdate 가 시작할 때 완료됩니다. LateUpdate 는 일반적으로 다음의 3인칭 카메라에 사용합니다. 캐릭터를 움직이고 Update 로 방향을 바꾸게 하는 경우 LateUpdate 에서 모든 카메라 움직임과 로테이션 계산을 수행할 수 있습니다. 이렇게 하면 카메라가 포지션을 추적하기 전에 캐릭터가 완전히 움직였는지 확인할 수 있습니다.

렌더링

  • OnPreCull: 카메라가 씬을 컬링하기 전에 호출됩니다. 컬링은 어떤 오브젝트를 카메라에 표시할지 결정합니다. OnPreCull은 컬링 발생 직전에 호출됩니다.
  • OnBecameVisible/OnBecameInvisible: 오브젝트가 카메라에 표시되거나/표시되지 않을 때 호출됩니다.
  • OnWillRenderObject: 오브젝트가 표시되면 각 카메라에 한 번 호출됩니다.
  • OnPreRender: 카메라가 씬 렌더링을 시작하기 전에 호출됩니다.
  • OnRenderObject: 모든 일반 씬 렌더링이 처리된 후 호출됩니다. 이 때 커스텀 지오메트리를 그리는 데에 GL 클래스 또는 Graphics.DrawMeshNow를 사용할 수 있습니다.
  • OnPostRender: 카메라가 씬 렌더링을 마친 후 호출됩니다.
  • OnRenderImage: Called after scene rendering is complete to allow post-processing of the image, see Post-processing Effects.
  • OnGUI: GUI 이벤트에 따라 프레임당 여러 번 호출됩니다. 레이아웃 및 리페인트 이벤트는 우선 처리되며 각 입력 이벤트에 대해 레이아웃 및 키보드/마우스 이벤트가 다음으로 처리됩니다.
  • OnDrawGizmos: 시각화 목적으로 씬 뷰에 기즈모를 그릴 때 사용됩니다.

코루틴

일반적인 코루틴 업데이트는 Update 함수가 반환된 후 실행됩니다. 코루틴은 주어진 YieldInstruction이 완료될 때까지 실행을 중단(양보)할 수 있는 함수입니다. 코루틴의 다른 사용법은 다음과 같습니다.

  • yield 코루틴은 모든 Update 함수가 다음 프레임에 호출된 후 계속됩니다.
  • yield WaitForSeconds 지정한 시간이 지난 후, 모든 Update 함수가 프레임에 호출된 후 계속됩니다.
  • yield WaitForFixedUpdate 모든 FixedUpdate가 모든 스크립트에 호출된 후 계속됩니다.
  • yield WWW WWW 다운로드가 완료된 후 계속됩니다.
  • yield StartCoroutine 코루틴을 연결하고 MyFunc 코루틴이 먼저 완료되기를 기다립니다.

오브젝트를 파괴할 때

  • OnDestroy: 오브젝트 존재의 마지막 프레임에 대해 모든 프레임 업데이트를 마친 후 이 함수가 호출됩니다. 오브젝트는 Object.Destroy 또는 씬 종료에 대한 응답으로 파괴될 수 있습니다.

종료 시

다음 함수는 씬의 활성화된 모든 오브젝트에서 호출됩니다.

  • OnApplicationQuit: 이 함수는 애플리케이션 종료 전 모든 게임 오브젝트에서 호출됩니다. 에디터에서 사용자가 플레이 모드를 중지할 때 호출됩니다.
  • OnDisable: 동작이 비활성화되거나 비활성 상태일 때 이 함수가 호출됩니다.

스크립트 수명 주기 플로우차트

다음 다이어그램은 스크립트의 수명 동안 이벤트 함수의 호출 순서에 대한 요약입니다.





이전까지는 일반 업데이트와 물리 업데이트 이 이후부턴 주로 렌더링 위주의 업데이트




ref : https://docs.unity3d.com/kr/current/Manual/ExecutionOrder.html






MonoBehaviour 실행순서



오브젝트 생성 순서와 상관없이 컴포넌트 추가 시점에서 가장 나중에 추가 된것이 가장 먼저 실행됩니다.


ScriptExcution Order 에서 컴포넌트 종류단위로 조정 가능하지만

동일 컴포넌트 경우에 시간 순서가 결과에 영향을 준다면 나중에 실행되고 있는것을 삭제후 다시 추가하면 최우선으로 실행됩니다.
(그 반대는 으왕)

[복수 선택후 일괄 컴포넌트 추가시] Hierarchy 에 보이는것과 상관 없이

GameObject가 생성된 순서 역순으로 컴포넌트가 추가됩니다 
(가급적이면 이런 시간 의존관계가 없도록 설계하는것이 좋겠지요)



여러 컴포넌트가 추가된경우 별도로 강제 order 변경이 없다면 
이것역시 컴포넌트 종류 상관없이 가장 나중에 추가 된것부터 시간 역순으로 실행


첨부 파일은 

1. GameObject 생성한 순서대로 추가한경우

2. GameObject 생성순서 역순으로 추가한 경우

3. 트리구조 변경후 다수선택후 일괄추가

4. 순서 변경후 다수선택후 일괄추가


ref : http://lab.gamecodi.com/board/zboard.php?id=GAMECODILAB_Lecture&page=1&sn1=&divpage=1&sn=off&ss=on&sc=on&select_arrange=hit&desc=asc&no=411
 


반응형

+ Recent posts