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

카테고리

분류 전체보기 (2794)
Unity3D (852)
Script (91)
Extensions (16)
Effect (3)
NGUI (81)
UGUI (9)
Physics (2)
Shader (37)
Math (1)
Design Pattern (2)
Xml (1)
Tips (201)
Link (23)
World (1)
AssetBundle (25)
Mecanim (2)
Plugins (78)
Trouble Shooting (70)
Encrypt (7)
LightMap (4)
Shadow (4)
Editor (12)
Crash Report (3)
Utility (9)
UnityVS (2)
Facebook SDK (2)
iTween (3)
Font (13)
Ad (14)
Photon (2)
IAP (1)
Google (8)
Android (51)
iOS (44)
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

[링크] https://drehzr.tistory.com/2194

 

Unity) Search Extension (검색 기능 확장하기)

Search Extension (검색 기능 확장하기)   프로젝트의 리소스의 종속성도 꽤나 잘 검색이 되는것으로 판단 된다.좀더 참고해서 작업할수 있지 않을까 고민하다가 간략하게 사용해보고 후기에 대

drehzr.tistory.com

 

반응형
Posted by blueasa
, |

Unity 2021.3.40f1

I2 Localization v2.8.22 f4

----

I2 Localization의 AppName 로컬라이징을 사용하고 있는데,

PostProcessBuild_iOS.cs를 약간 개조(추가)해서 iOS Privacy도 로컬라이징 하도록 추가함.

(현재는 ATT 관련 Description인 NSUserTrackingUsageDescription Privacy를 추가함)

 

아래 소스를 I2 Localization 하위에 있는 PostProcessBuild_iOS.cs가 있는 폴더에 넣거나,

원하는 곳 Editor 폴더 아래에 넣으면 된다.

 

난 에셋 삭제 시 함께 사라지는 걸 방지하기 위해 아래 위치에 추가해 뒀다.

[소스 위치] ../Assets/I2_Extentions/Localization/Scripts/Editor/PostProcessBuild_iOS_Privacy.cs

 

#if UNITY_IOS || UNITY_IPHONE
using UnityEditor.Callbacks;
using System.Collections;
using UnityEditor.iOS_I2Loc.Xcode;
using System.IO;
using UnityEditor;
using UnityEngine;
using System.Linq;


namespace I2.Loc
{
    public class PostProcessBuild_IOS_Privacy
    {
        // PostProcessBuild_IOS(10000) 다음에 실행 되도록 10001로 지정함.
        [PostProcessBuild(10001)]
        public static void ChangeXcodePlist(BuildTarget buildTarget, string pathToBuiltProject)
        {
            if (buildTarget != BuildTarget.iOS)
                return;

			if (LocalizationManager.Sources.Count <= 0)
				LocalizationManager.UpdateSources();
            var langCodes = LocalizationManager.GetAllLanguagesCode(false).Concat(LocalizationManager.GetAllLanguagesCode(true)).Distinct().ToList();
            if (langCodes.Count <= 0)
				return;
				
            try
            {
			//----[ Export localized languages to the info.plist ]---------

                string plistPath = pathToBuiltProject + "/Info.plist";
                PlistDocument plist = new PlistDocument();
                plist.ReadFromString(File.ReadAllText(plistPath));

				PlistElementDict rootDict = plist.root;

                // Get Language root
                var langArray = rootDict.CreateArray("CFBundleLocalizations");

                // Set the Language Codes
                foreach (var code in langCodes)
                {
                    if (code == null || code.Length < 2)
                        continue;
                    langArray.AddString(code);
                }

				rootDict.SetString("CFBundleDevelopmentRegion", langCodes[0]);

                // Write to file
                File.WriteAllText(plistPath, plist.WriteToString());

			//--[ Localize Privacy ]----------

				string LocalizationRoot = pathToBuiltProject + "/I2Localization";
				if (!Directory.Exists(LocalizationRoot))
					Directory.CreateDirectory(LocalizationRoot);
				
				var project = new PBXProject();
				string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
				//if (!projPath.EndsWith("xcodeproj"))
					//projPath = projPath.Substring(0, projPath.LastIndexOfAny("/\\".ToCharArray()));

				project.ReadFromFile(projPath);
				//var targetName = PBXProject.GetUnityTargetName();
				//string projBuild = project.TargetGuidByName( targetName );

                // 상위(PostProcessBuild_IOS.cs)에서 이미 지우고 생성했기 때문에 주석처리.
				//project.RemoveLocalizationVariantGroup("I2 Localization");
				
                // Set the Language Overrides
				foreach (var code in langCodes)
				{
					if (code == null || code.Length < 2)
						continue;

					var LanguageDirRoot = LocalizationRoot + "/" + code + ".lproj";
					if (!Directory.Exists(LanguageDirRoot))
						Directory.CreateDirectory(LanguageDirRoot);

					var infoPlistPath = LanguageDirRoot + "/InfoPlist.strings";
                    
                    // AppName
                    //var InfoPlist = string.Format("CFBundleDisplayName = \"{0}\";", LocalizationManager.GetAppName(code));
                    //File.WriteAllText(infoPlistPath, InfoPlist);
                    
                    // Privacy - NSUserTrackingUsageDescription
                    // 다른 Privacy 필요하면 아래 추가하면 됨.
                    var InfoPlist = string.Format("\n{0} = \"{1}\";", "NSUserTrackingUsageDescription", Get_NSUserTrackingUsageDescription(code));
                    File.AppendAllText(infoPlistPath, InfoPlist);


                    //var langProjectRoot = "I2Localization/"+code+".lproj";

                    // InfoPlist.strings만 수정할거라 Localizable.strings는 주석처리.
                    //var stringPaths = LanguageDirRoot + "/Localizable.strings";
                    //File.WriteAllText(stringPaths, string.Empty);

                    // AddLocalization은 PostProcessBuild_IOS.cs에서 했기 때문에 주석처리 함.
                    //project.AddLocalization(langProjectRoot + "/Localizable.strings", langProjectRoot + "/Localizable.strings", "I2 Localization");
                    //project.AddLocalization(langProjectRoot + "/InfoPlist.strings", langProjectRoot + "/InfoPlist.strings", "I2 Localization");
                }

                project.WriteToFile(projPath);
				
            }
            catch (System.Exception e)
            { 
				Debug.Log (e);
			}
        }

        /// <summary>
        /// NSUserTrackingUsageDescription(IDFA/ATT)
        /// </summary>
        /// <param name="_code">국가코드</param>
        /// <returns>로컬라이징 된 Description</returns>
		private static string Get_NSUserTrackingUsageDescription(string _code)
		{
			string strDescription = string.Empty;

			switch(_code)
			{
								case "en":
					strDescription = "This identifier will be used to deliver personalized ads to you.";
					break;

                case "ko":
                    strDescription = "이 식별자는 맞춤형 광고를 제공하는 데 사용됩니다.";
                    break;

                case "zh":      // zh도 zh-CN(중국본토)으로 보도록 함
                case "zh-CN":
                    strDescription = "该标识符将用于向您投放个性化广告。";
                    break;

                case "zh-TW":
                    strDescription = "該標識符將用於向您投放個人化廣告。";
                    break;

                case "ja":
                    strDescription = "この識別子は、パーソナライズされた広告を配信するために使用されます。";
                    break;

                case "vi":
                    strDescription = "Mã nhận dạng này sẽ được sử dụng để phân phối quảng cáo được cá nhân hóa cho bạn.";
                    break;

                case "es":
                    strDescription = "Este identificador se utilizará para enviarle anuncios personalizados.";
                    break;

                case "it":
                    strDescription = "Questo identificatore verrà utilizzato per fornirti annunci personalizzati.";
                    break;

                case "id":
                    strDescription = "Pengenal ini akan digunakan untuk menayangkan iklan yang dipersonalisasi kepada Anda.";
                    break;

                case "th":
                    strDescription = "ตัวระบุนี้จะใช้ในการส่งโฆษณาส่วนบุคคลให้กับคุณ";
                    break;

                case "pt":
                    strDescription = "Este identificador será utilizado para lhe entregar anúncios personalizados.";
                    break;

                case "hi":
                    strDescription = "इस पहचानकर्ता का उपयोग आपको वैयक्तिकृत विज्ञापन देने के लिए किया जाएगा.";
                    break;

                default:
                    strDescription = "This identifier will be used to deliver personalized ads to you.";
                    break;
			}

			return strDescription;

        }
    }
}
#endif
반응형
Posted by blueasa
, |

[링크] https://hanamoni.tistory.com/31

 

Unity - Dictionary 를 Inspector 에 간단하게..

유니티에서 사용하는 Dictionary 는 Inspector 에서 보이지 않아서 데이터 확인해야 할때 불편하다. 그래서 이미 사용하고 있는 Dictionary 데이터들을 간단하게 인스펙터에 표시하기 위해서 만든 클래

hanamoni.tistory.com

 

 

반응형
Posted by blueasa
, |

In Unity there is a cross-platform way to copy a string to Clipboard. Using the GUIUtility class I’m going to show you how to copy a string into the user’s Clipboard. This should work in Unity 2017 and beyond.

By using the GUIUtility class, from UnityEngine, we can fit any C# object with a ToString() function into the Clipboard!

Clipboard Extension

To make it easily accessible I made the function as a string extension. By doing it this way we can use the function on any string anywhere in the code.

using UnityEngine;

public static class ClipboardExtension
{
    /// <summary>
    /// Puts the string into the Clipboard.
    /// </summary>
    public static void CopyToClipboard(this string str)
    {
        GUIUtility.systemCopyBuffer = str;
    }
}

 

Example

Here is an example on how to copy different elements into the Clipboard using the ClipboardExtension:

public string GetSomeString()
{
    return "This is a string coming from a function!";
}

public void TestCopyToClipboard()
{
    // + Using a standard string
    string testString = "Am I in the Clipboard?";
    testString.CopyToClipboard();
    // The content of test1 is in the Clipboard now!

    // + Using a method to get a string
    GetSomeString().CopyToClipboard();
    // The content returned by GetSomeString() is in the Clipboard now!

    // + Using a C# object with a ToString() method
    Color colorTest = Color.red;
    colorTest.ToString().CopyToClipboard();
    // The string version of the object colorTest is in the clipboard now!
}

You can try out this code for yourself! Run it, then try pasting your Clipboard into a notepad. It has been tested and works on PC, Android and iOS!

 

 

[출처] https://thatfrenchgamedev.com/785/unity-2018-how-to-copy-string-to-clipboard/

 

Unity - How to copy a string to Clipboard – That French Game Dev

Cross-platform way to copy a string to Clipboard in Unity. Using the GUIUtility class I'm going to show you how to copy a string into the user's Clipboard. This should work in Unity 2017 and beyond.

thatfrenchgamedev.com

 

반응형
Posted by blueasa
, |

The saved objects are handled on the native side, and there is no way I know of to hook into that side of Unity.


As an aside, here's an example of using an extension to track such a quality:

I would create a an extension for Object which stores all saved objects, something like this:

  1. public static class ObjectExtension {
  2.  
  3. private static List<Object> savedObjects = new List<Object>();
  4.  
  5. public static void DontDestroyOnLoad(this Object obj){
  6. savedObjects.Add(obj);
  7. Object.DontDestroyOnLoad(obj);
  8. }
  9.  
  10. public static void Destory(this Object obj){
  11. savedObjects.Remove(obj);
  12. Destory(obj);
  13. }
  14.  
  15. public static List<Objects> GetSavedObjects(){
  16. return new List<Objects>(savedObjects);
  17. }
  18. }
  19.  

Now, to save the object you'll have to use this.DontDestroyOnLoad(); instead of the normal DontDestroyOnLoad(this);

EDIT:

I started looking into this and found that setting a GameObject's hideflags to HideFlags.DontSave means (as far as I can tell) the same thing as DontDestroyOnLoad, except that none of Unity's functions (Update, etc.) are called. The one with hideflags might also leak if not destroyed manually...

Finding GameObjects with its hideFlags set to DontSave is trivial.

 

 

 

[출처] https://answers.unity.com/questions/544886/find-objects-with-dontdestroyonload.html

 

Find objects with DontDestroyOnLoad - Unity Answers

 

answers.unity.com

 

반응형
Posted by blueasa
, |

유니티에서 스트리밍 방식으로 미리듣기를 재생하기 위해 처리.


[Engine] Unity v5.6.5f1


IEnumerator LoadPreListening_Streaming_Server()
{
    AudioSource asPreListening = new AudioSource();
    WWW www = new WWW("URL");
    while (www.progress < 0.01)
    {
        Debug.Log(www.progress);
        yield return null;
    }
    
    if (!string.IsNullOrEmpty(www.error))
    {
        Debug.Log(www.error);
        yield break;
    }
    else
    {
        yield return null;
        //asPreListening.clip = WWWAudioExtensions.GetAudioClip(www, false, true, AudioType.MPEG); // MP3
        asPreListening.clip = WWWAudioExtensions.GetAudioClip(www, false, true, AudioType.OGGVORBIS); // OGG

        while (asPreListening.clip.loadState == AudioDataLoadState.Failed
                || asPreListening.clip.loadState == AudioDataLoadState.Unloaded
                || asPreListening.clip.loadState == AudioDataLoadState.Loading)
        {
            yield return null;
        }

        if (asPreListening.clip.loadState == AudioDataLoadState.Loaded)
        {
            // Play PreListening
            asPreListening.time = 0f;
            asPreListening.volume = 0f;
            asPreListening.loop = true;
            asPreListening.Play();
        }
    }
}



[참조]

https://answers.unity.com/questions/1395471/how-do-i-properly-stream-music-with-wwwaudioextens.html?childToView=1398578#answer-1398578

반응형
Posted by blueasa
, |

Have you ever found yourself wishing a built-in Unity class had some functionality that isn’t there? C#extension methods are the answer!

In this article, I’ll teach you how to use extension methods to add functionality to existing classes, no matter if they’re built-in Unity types, types defined in a third-party plugin, or even types defined in an Asset Store package which you could edit but you’re (rightly) worried about later package updates stomping your “patch”.

Seemingly obvious API omissions can be frustrating, but extension methods let you “fix” just about any API to your liking.

Hit the jump for all the details!

When Extension Methods Are Useful

Imagine you need a way to set the layer of a GameObject and all its children, but there’s no GameObject.SetLayerRecursively() available. You could embed a loop in your code:

// Do some work.

    // Set the layer of this GameObject and all its children.
    gameObject.layer = someLayer;
    foreach(Transform t in transform)
        t.gameObject.layer = someLayer;

    // Do some more work.

This will work fine, although it’s not the cleanest thing in the world, and you’ll need to copy these lines of code around to every place where you want to do this operation. It would be better to encapsulate that code in a function, and make that function available to everyone via a “helper” class:

public class GameObjectHelper
    {
        public static void SetLayerRecursively(GameObject gameObject, int layer)
        {
            gameObject.layer = someLayer;
            foreach(Transform t in transform)
                t.gameObject.layer = someLayer;
        }
    }

    public class Test : MonoBehaviour
    {
        void Start()
        {
            GameObjectHelper.SetLayerRecursively(gameObject, someLayer);
        }
    }

This works fine too, but it can be easy to forget to use the helper class to invoke a function that feels like it belongs in GameObject itself. Wouldn’t it be nicer if you could just do this?

gameObject.SetLayerRecursively(someLayer);

As it turns out, C# lets you make this happen!

Declaring An Extension Method

Extension methods are declared just like regular functions, except that a) they must be static, b) they must be declared inside a non-generic, non-nested, static class, and c) they include a special syntax for their first argument, which is a reference to the calling object:

public static class GameObjectExtensions
    {
        public static void SetLayerRecursively(this GameObject gameObject, int layer)
        {
            // Implementation goes here
        }
    }

Though declared as static, this is invoked as if it were an instance method:

myGameObject.SetLayerRecursively(someLayer);

Note that when we call the method we actually omit the first argument and skip straight to the second. Take another look at the method declaration above. See how the first argument is declared using the “this” keyword? That’s what tells the compiler to infer that argument as the calling object; in this case, myGameObject.

That’s actually all there is to it. Extension methods are easy!

For what it’s worth, I like to organize my extension methods into classes named ClassNameExtensions. So I have GameObjectExtensions, TransformExtensions, ColorExtensions, and so on. There’s nothing that says you have to do this; I just like the organization. You could pack them all together into a single Extensions class if you prefer, or any other kind of organization you want. Just remember that extensions methods must be declared inside a non-generic, non-nested, static class; the compiler will complain otherwise.

Limitations of Extension Methods

Extension methods can add to an existing class, but they cannot override existing methods. For example, if you declared this:

public static class GameObjectExtensions
    {
        public static Component GetComponent(this GameObject gameObject, Type type)
        {
            Debug.LogError(LOL, you got trolled);
        }
    }

…the compiler would basically ignore you. The rule for multiple method declarations using the same signature is: instance methods always take precedence over extension methods.

To extend a type, you’ll need make sure it’s in scope with the “using” directive. If you’re extending any built-in Unity type, you’re covered by virtue of the “using UnityEngine” that’s a standard entry in most Unity scripts. If you’re extending an editor type, you’ll need to add “using UnityEditor”, just like you would if you were calling that type. If you’re extending a type from a third-party plugin, you may need to import a namespace; check the plugin’s documentation (or source code, if you have it) for details.

I’ve already mentioned that extension methods must be declared inside a non-generic, non-nested, static class, which means you can’t just drop them in willy-nilly wherever you want. In practice, this “limitation” turns out to be a useful organizing device. You can certainly argue that this is virtually identical to the “helper class” example at the top of this article, and in terms of implementation effort that’s probably true; the difference is that with extension methods you get a cleaner, more normalized calling syntax. This really comes down to personal preference.

Some Useful Extension Methods

For the rest of this article, I’ll share some useful extension methods I’ve written over the past few months. Feel free to incorporate these into your own codebase and modify them at-will. (But don’t just copy-paste them into a text file and try to sell it on the Asset Store; that would make you a horrible person.)

Set Layer Recursively

I use the excellent 2D Toolkit for UI, and I use a two-camera setup: one camera for the scene, one camera for the UI. In order to make the UI camera render only UI objects, all the UI objects need to be on a UI layer. When I create UI objects from script I need to set that layer, and often I’m creating objects with children (like a button with a child sprite and a child text label).

It’d be nice to have a way to set the layer for this entire hierarchy with a single function call (you’ll recognize this as the example at the top of this article). Here’s what the call looks like:

myButton.gameObject.SetLayerRecursively(LayerMask.NameToLayer(UI));

And here’s that extension method:

// Set the layer of this GameObject and all of its children.
    public static void SetLayerRecursively(this GameObject gameObject, int layer)
    {
        gameObject.layer = layer;
        foreach(Transform t in gameObject.transform)
            t.gameObject.SetLayerRecursively(layer);
    }

Set Visual/Collision Recursively

While we’re doing things recursively, wouldn’t it be nice if we could enable/disable just the renderers, or just the colliders, for an entire hierarchy? This can be useful for UI, but it can also be useful in the scene. Imagine a complex hierarchy that defines a really fancy animated force field, and a game mechanic whereby you can switch your avatar’s polarity, allowing passage through force fields of a particular color. When you switch polarity, you’d loop through the matching force fields and disable their colliders, like this:

foreach(ForceField forceField in forceFields)
        forceField.gameObject.SetCollisionRecursively(false);

Here’s that extension method:

public static void SetCollisionRecursively(this GameObject gameObject, bool tf)
    {
        Collider[] colliders = gameObject.GetComponentsInChildren<Collider>();
        foreach(Collider collider in colliders)
            collider.enabled = tf;
    }

And the same principle applies for renderers:

public static void SetVisualRecursively(this GameObject gameObject, bool tf)
    {
        Renderer[] renderers = gameObject.GetComponentsInChildren<Renderer>();
        foreach(Renderer renderer in renderers)
            renderer.enabled = tf;
    }

Filter Child Components By Tag

It’s easy to search for child components using GameObject.GetComponentsInChildren(), but what if you have a have hierarchy in which you have lots of instances of a type, and you only want those instances which have a particular tag? In my case, I had a compound object with numerous renderers, and I needed to drive a material color on a subset of those renderers tagged as “Shield”.

This proved convenient:

m_renderers = gameObject.GetComponentsInChildrenWithTag<Renderer>("Shield");

Here’s that extension method:

public static T[] GetComponentsInChildrenWithTag<T>(this GameObject gameObject, string tag)
        where T: Component
    {
        List<T> results = new List<T>();

        if(gameObject.CompareTag(tag))
            results.Add(gameObject.GetComponent<T>());

        foreach(Transform t in gameObject.transform)
            results.AddRange(t.gameObject.GetComponentsInChildrenWithTag<T>(tag));

        return results.ToArray();
    }

I noted earlier that extension methods must be declared inside non-generic classes. That doesn’t mean the extension method itself can’t be generic, however! When we call this method we replace T with the type we’re interested in — in the preceding call example, it was Renderer — and that type is used for each occurrence of T in the method implementation. The “where” keyword specifies that T must be of type Component or a type derived from Component (the compiler will throw an error otherwise).

See this MSDN article for more information about generics.

Get Components In Parents

It’s all well and good to get components in children, but sometimes you need to search up. A common case I run into is when figuring out what to do with a collision result. I have a Player type, and its hierarchy is made up of several GameObjects which represent visuals, colliders, equipped items, and so on. Typically when I get a collision result on a player, the collider is bound to a child GameObject, so I can’t just do GetComponent() and then player.TakeDamage() or whatever, because there’s no Player component on the GameObject I actually hit. In this case I need to search up the hierarchy and find the Player to which this collider is parented; also the Player may not necessarily be this collider’s immediate parent.

So now I do this:

Player player = collider.gameObject.GetComponentInParents<Player>();

Here’s that extension method:

public static T GetComponentInParents<T>(this GameObject gameObject)
        where T : Component
    {
        for(Transform t = gameObject.transform; t != null; t = t.parent)
        {
            T result = t.GetComponent<T>();
            if(result != null)
                return result;
        }

        return null;
    }

Just like Unity has both GameObject.GetComponentInChildren (singular) and GameObject.GetComponentsInChildren (plural), I also created a version that gets all components in parents:

public static T[] GetComponentsInParents<T>(this GameObject gameObject)
        where T: Component
    {
        List<T> results = new List<T>();
        for(Transform t = gameObject.transform; t != null; t = t.parent)
        {
            T result = t.GetComponent<T>();
            if(result != null)
                results.Add(result);
        }

        return results.ToArray();
    }

Note: it would be trivial to create a GetComponentsInParentsWithTag, but I haven’t run into a need for it yet. If you’d like to exercise your newfound knowledge of extension methods, this might be a good exercise. :)

Get An Object’s Collision Mask

Here’s one whose omission is particularly perplexing. You can get the layer a GameObject is on, which is useful for both rendering and collision purposes, but there’s no easy way to figure out the set of layers that GameObject can collide against.

I ran into this when implementing weapons. Projectile-based weapons are simple: they get a Rigidbody and a Collider of some sort, and the collision system handles everything for me. But a rail gun-like weapon is a different story: there’s no Rigidbody, just a script-invoked raytest. You can pass a collision mask — a bitfield — into a raytest, but what if you want the collision mask to be based on the weapon’s layer? It’d be nice to set some weapons to “Team1” and others to “Team2”, perhaps, and also to ensure your code doesn’t break if you change the collision matrix in the project’s Physics Settings.

Really, I wanted to just do this:

if(Physics.Raycast(startPosition, direction, out hitInfo, distance,
        weapon.gameObject.GetCollisionMask())
    )
    {
        // Handle a hit
    }

That raycast will only hit objects which the calling weapon is allowed to collide with, based on its layer and the project’s collision matrix.

Here’s that extension method:

public static int GetCollisionMask(this GameObject gameObject, int layer = -1)
    {
        if(layer == -1)
            layer = gameObject.layer;

        int mask = 0;
        for(int i = 0; i < 32; i++)
            mask |= (Physics.GetIgnoreLayerCollision(layer, i) ? 0 : 1) << i;

        return mask;
    }

Note the optional “layer” argument. If omitted, it uses the layer of the calling GameObject, which is the most common/intuitive case (for me, at least). But you can specify a layer and it’ll hand you the collision mask for that layer instead.

Easily Change A Color’s Alpha

I often find myself wanting to modulate the alpha value of a color without changing the color itself, for blinking/pulsing effects. Because Color is a struct, and structs in C# are immutable, you can’t simply assign color.a; you’ll get a compiler error. Fortunately, extension methods can extend structs as well as classes:

public static Color WithAlpha(this Color color, float alpha)
    {
        return new Color(color.r, color.g, color.b, alpha);
    }

This method makes modulating a color’s alpha clean and simple:

GUI.color = desiredColor.WithAlpha(currentAlpha);

Performance Considerations

There really aren’t any. Extension methods are a compile-time device; once you reach runtime, they look and act just like any other method call. So it doesn’t matter whether you write an extension method or an explicit helper class; as long as the guts of the method are identical, both implementations should perform identically. You could theoretically squeeze a vanishingly tiny bit of performance out of simply inlining all the code, avoiding the overhead of any function call at all, but in this day and age that’s completely pointless to worry about unless you’re calling the function millions of times.

Extension methods are mainly useful as a way of cleaning up and normalizing your code. They have little or no effect on the behavior of that code.

Conclusion

I hope this article has been clear and useful. Extension methods are one of my favorite features of C#, because I’m a bit obsessive about having clean, easy-to-read code and they can really help make that happen. Of course, there’s more than one way to skin a cat, and I’m by no means suggesting that extension methods are the right or only way to do things. You can certainly argue that making an explicit helper class containing regular static functions — like GameObjectHelper.SetActiveRecursively() in the example at the top of this article — is just as good as an extension method-based implementation of the same; they’re six of one, half-dozen of another. I prefer the extension method approach because it feels like a natural and intuitive API extension, rather than a “bolt-on”, but that’s strictly a matter of personal preference.

Like every coding practice, extension methods are just one tool in the toolbox. But I encourage you to give them a shot!

(Oh and by the way: I'm available for contract work doing the sort of things you just read about. Hit me up if you're interested!)



[출처] http://www.third-helix.com/2013/09/30/adding-to-unitys-builtin-classes-using-extension-methods.html

반응형

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

[펌] Find objects with DontDestroyOnLoad  (0) 2021.11.26
[Unity] Play Streaming Music From Server  (0) 2018.02.06
일괄적으로 Texture Import Setting 변경  (0) 2015.01.30
Extension Methods  (0) 2014.08.18
Nullable Types  (0) 2014.08.18
Posted by blueasa
, |

[파일]

SetTexture.cs



작업을 하다보니..

 

새로 등록한 이미지들의 Import Setting 바꿔주는 부분이 귀찮아서...

기존 작업방식은 추가한것들 한꺼번에 클릭후 Inspector 에서 동일하게 바꿔주는 방법이였는데..

 

정말 귀찮아서..만든 클래스.

 

사용법은

 

Assets 폴더 안에 Editor 폴더를 만들고 혹은 거기에 넣고

 

텍스쳐들이 들어있는 폴더나 바꾸고자 하는텍스쳐에 마우스 오른버튼을 클릭하면.

 

생성되어있는 MySpriteSet  이라는 메뉴를 클릭하면 사용자가 기본설정해논 텍스쳐 옵션대로 모든 텍스쳐가 셋팅된다.

 

스크립트 속 기본이 되는 텍스쳐 옵션은 사용자에 맞춰 변경하면 됨.



출처 : http://hanamoni.tistory.com/20

반응형

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

[Unity] Play Streaming Music From Server  (0) 2018.02.06
[펌] ADDING TO UNITY'S BUILT-IN CLASSES USING EXTENSION METHODS  (0) 2016.10.20
Extension Methods  (0) 2014.08.18
Nullable Types  (0) 2014.08.18
ObjectPool  (0) 2014.04.22
Posted by blueasa
, |

Extension Methods

Unity3D/Extensions / 2014. 8. 18. 02:30

Extension Methods

Posted by  on December 6th, 2013

Oftentimes you’ll find yourself using classes you can’t modify. Whether they’re basic data types or part of an existing framework, you’re stuck with the functions that are provided. That being said, C# provides a nifty trick to appending functions to classes! These are known as Extension Methods.

Extension methods are fairly simple to create and are frequently used as syntactic sugar. A practical example can be seen with Unity’s Transform class. Let’s say you want to set only the xvariable of Transform.position.

using UnityEngine;
using System.Collections;
 
public class Player : MonoBehaviour
{
    void Update ()
    {
        //Set new x position to 5
        transform.position = new Vector3(5f, transform.position.y, transform.position.z);
    }
}

In this case Transform.position gives you an error if you only try to assign its x member variable, so you have to assign the entire Vector3. An extension method such as SetPositionX() could be appended to the Transform class and help make this code more readable.

In order to create extension methods you have to create a static class. In addition, an extension method declaration must be declared static and have the first parameter be of the type that you’re writing the method for, preceded by the this keyword.

using UnityEngine;
using System.Collections;
 
//Must be in a static class
public static class Extensions
{
    //Function must be static
    //First parameter has "this" in front of type
    public static void SetPositionX(this Transform t, float newX)
    {
        t.position = new Vector3(newX, t.position.y, t.position.z);
    }
}

Now you can go back to your other script and replace our old code with the new extension method.

using UnityEngine;
using System.Collections;
 
public class Player : MonoBehaviour
{
    void Update ()
    {
        //Set new x position to 5
        transform.SetPositionX(5f);
    }
}
NOTE: Extension methods can only be called on an instance of a class, not on the class itself.

Here are a few more extension methods to get you started, as well as an example script that utilizes a few of them.

Extensions:

using UnityEngine;
using System.Collections;
 
public static class Extensions
{
    public static void SetPositionX(this Transform t, float newX)
    {
        t.position = new Vector3(newX, t.position.y, t.position.z);
    }
 
    public static void SetPositionY(this Transform t, float newY)
    {
        t.position = new Vector3(t.position.x, newY, t.position.z);
    }
 
    public static void SetPositionZ(this Transform t, float newZ)
    {
        t.position = new Vector3(t.position.x, t.position.y, newZ);
    }
 
    public static float GetPositionX(this Transform t)
    {
        return t.position.x;
    }
 
    public static float GetPositionY(this Transform t)
    {
        return t.position.y;
    }
 
    public static float GetPositionZ(this Transform t)
    {
        return t.position.z;
    }
 
    public static bool HasRigidbody(this GameObject gobj)
    {
        return (gobj.rigidbody != null);
    }
 
    public static bool HasAnimation(this GameObject gobj)
    {
        return (gobj.animation != null);
    }
 
    public static void SetSpeed(this Animation anim, float newSpeed)
    {
        anim[anim.clip.name].speed = newSpeed;
    }
}

Example Script:

using UnityEngine;
using System.Collections;
 
public class Player : MonoBehaviour
{
    void Update ()
    {
        //move x position 5 units
        float currentX = transform.GetPositionX();
        transform.SetPositionX(currentX + 5f);
 
        if(gameObject.HasRigidbody())
        {
            //Do something with physics!
        }
 
        if(gameObject.HasAnimation())
        {
            //Double the animation speed!
            gameObject.animation.SetSpeed(2f);
        }
    }
}
NOTE: Static classes do NOT extend MonoBehaviour.
ANOTHER NOTE: If you define your extension methods inside of a namespace, you have to declare the use of that namespace in order to bring them into scope.


출처 : http://unitypatterns.com/extension-methods/

반응형
Posted by blueasa
, |

Nullable Types

Unity3D/Extensions / 2014. 8. 18. 02:29

Nullable Types

Posted by  on January 14th, 2014

Sometimes you have variables that have important information but only after certain game events occur. For example: A character in your game may be idle until they’re told to go to an assigned destination.

public class Character : MonoBehaviour
{
    Vector3 targetPosition;
 
    void MoveTowardsTargetPosition()
    {
        if(targetPosition != Vector3.zero)
        {
            //Move towards the target position!
        }
    }
 
    public void SetTargetPosition(Vector3 newPosition)
    {
        targetPosition = newPosition;
    }
}

In this case, we want the character to move towards the target position only if it’s been assigned. In the code above, we do this by just checking if targetPosition is not equal to its default value (0, 0, 0).  But now we have an issue: what if you want your character to move to (0, 0, 0)? You don’t want to discredit the possibility of that value being used because it might come up sometime during the game!

Luckily, there’s a trick to help avoid comparing arbitrary values for confirming that a variable has been initialized: Nullable Types.

Using Nullable Types

To make a nullable type, just add a “?” after the type declaration of any variable that is a Value Type (eg. Vector3, Rect, int, float).

public class Character : MonoBehaviour
{
    //Notice the added "?"
    Vector3? targetPosition;
 
    void MoveTowardsTargetPosition()
    {
        if (targetPosition.HasValue)
        {
            //Move towards the target position!
            //use targetPosition.Value for the actual value
        }
    }
 
    public void SetTargetPosition(Vector3 newPosition)
    {
        targetPosition = newPosition;
    }
}

Seen here, nullable types have two properties we can use: HasValue (true if the variable has been assigned, false otherwise), and Value (the actual assigned value of the variable).

//First, check if the variable has been assigned a value
if (targetPosition.HasValue)
{
    //move towards targetPosition.Value
}
else
{
    //targetPosition.Value is invalid! Don't use it!
}

Usage Notes

  • To revert a nullable type to having “no value”, set it to null
  • You can NOT create nullable types from classes, or reference types (they can already be set to null)

As usual, if you have any questions or tips to add, do so in the comments below!



출처 : http://unitypatterns.com/nullable-types/

반응형

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

일괄적으로 Texture Import Setting 변경  (0) 2015.01.30
Extension Methods  (0) 2014.08.18
ObjectPool  (0) 2014.04.22
인스펙터 상의 GUI를 비활성화 시키고 싶을 때..  (0) 2014.04.02
Save Scene while on play mode  (0) 2014.01.12
Posted by blueasa
, |