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

카테고리

분류 전체보기 (2857)
Unity3D (897)
Programming (479)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (191)
협업 (64)
3DS Max (3)
Game (12)
Utility (142)
Etc (99)
Link (34)
Portfolio (19)
Subject (90)
iOS,OSX (53)
Android (16)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (19)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

다른 오브젝트의 함수를 써야할 때 메시지 호출방법을 쓰는 것이 좋다고 합니다.


이득우 님의 발표자료에 따르면, (아래 화면 참조)

  • 메시지 호출은 클래스 간 의존성을 줄일 수 있고,
  • 이는 코드를 간단하게 만들 수 있는데,
  • 성능의 저하가 있다고 생각하지만 그렇게 느리지 않고 장점이 더 크니 적극적으로 쓰자.
는 결론입니다.

<컴포넌트>.SendMessage 또는 <게임오브젝트>.SendMessage 와 같은 방식으로 쓸 수 있습니다.

구문 형식:
void SendMessage(string methodName, object value = null, SendMessageOptions options = SendMessageOptions.RequireReceiver); 


유니티 레퍼런스 홈페이지 예제를 보면,


using UnityEngine;

using System.Collections;


public class Example : MonoBehaviour {

    void ApplyDamage(float damage) {

        print(damage);

    }

    void Example() {

        SendMessage("ApplyDamage", 5.0F);

    }

}


위와 같은 방식으로 사용하고 있습니다. 파라미터 중 마지막 SendMessageOptions 은 말 그대로 옵션인데, SendMessageOptions.DontRequireReceiver 라고 쓸 경우에는 호출한 함수가 제대로 호출되었는지 여부는 신경쓰지 않고 호출한 것으로 역할이 끝납니다.


C# 에서는 콜백의 기능을 위해 delegate 를 사용할 수도 있습니다. 이와 관련해서 아래의 링크를 참고하세요.


http://unityindepth.tistory.com/entry/유니티-개발자로써-내가-배웠던-최고의-5가지





[출처] http://unitygame.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-SendMessage-%EC%82%AC%EC%9A%A9





[첨부]


  
빕스

덧붙이자면 
SendMessage 도 생각보다 느리지 않다고 알고있습니다.

실시간으로 리플랙션을 통해 함수를 호출하는것이 아니라
엔진에서 맵형태로 관리하기때문에
스트링 비교하는 부하정도만 있는걸로 알고있습니다.


[출처] http://www.gamecodi.com/board/zboard.php?id=GAMECODI_Talkdev&no=2070

반응형
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
, |

유니티3D_Android dll파일 난독화 가이드

(사용툴 : Spices.Net)



[파일]

BS_Unity3D_Obfuscate_Guide_20131220_v0.1.odt



1. 난독화할 dll파일

  • APK파일을 디컴파일or압축해제를 하면 Asset폴더 내부에 dll파일이 들어있다.

    (유니티 프로젝트의 경우 \assets\bin\Data\Managed\)


  • 난독화할 파일은 Assembly-CSharp.dll


2. Spices.Net 툴을 사용하여 난독화하기




  • 최상위 경로에서 마우스 오른클릭을 하면 메뉴들이 나오는데 Obfuscation Options에서 난독화 설정을 해줄 수 있다.




  • Members 내부에 있는 설정들이 가장 큰 비중을 차지하는것으로 보인다.

  • Members 설정으로 전체적으로 내부설정들을 한번에 바꿀수도 있고

    하나하나 바꿔줄 수도 있다.

  • Methods와 public옵션이 클래스명과 메소드명을 바꿔주는 설정인데 난독화시 가장 효과가 좋은 설정중 하나이다.

    (해당설정 적용시 짜여진 소스 구조에 따라서 작동이 안되는 경우가 있다.

  • Controll Flow 라는 함수 내부 구조를 바꿔주는 난독화부분은 이 툴에서 아직 찾지 못하였음





  • Obfuscation Options 설정이 끝났으면 다시 메뉴를 열어서 Obfuscate!를 선택하면 .iloprj 라는 확장명의 파일 저장경로 확인창이 뜨는데 바로 저장을 해주면 dll파일 경로로 저장된다.

    (툴관련 정보 저장파일인듯 하다)

  • 경로설정이 완료되면 난독화가 진행되고 정상적으로 난독화가 완료되면 “dll파일 경로\Output\”안에 난독화된 Assembly-CSharp.dll 파일이 생성된다.

  • 난독화된 파일을 기존 dll파일 경로에 덮어씌워준후 다시 컴파일 해주면 작업이 완료된다.





*난독화 적용전 .dll 디컴파일 결과





*난독화 적용후 .dll 디컴파일 결과(Members Full옵션 적용)




[출처]

http://theemeraldtablet.tistory.com/entry/Unity3D-Android-dll-%EB%82%9C%EB%8F%85%ED%99%94-%EA%B0%80%EC%9D%B4%EB%93%9C-SpicesNet

반응형

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

[Asset] Obfuscator  (2) 2017.11.17
[펌] 기본 변수 저장시 암호화  (0) 2016.05.23
[펌] Playerprefs 암호화  (0) 2016.05.23
C# AES 암복호화 알고리즘  (0) 2014.03.29
안드로이드에서 암호화 팁 - 에셋번들 암호화  (0) 2014.02.28
Posted by blueasa
, |

首先原帖子在这里:
http://game.ceeger.com/forum/read.php?tid=1383
 
这楼主做得非常好了,我都不知道怎么优化才好,但是本人是厌恶OnGUI主义者,所以决定要把一切OnGUI的东西根除...
 
然后附加了镜面效果,看着还行,不说那么多先来个图:
1
 
2
 
3
 
下面是NGUI的排布
5
 
4
 
主要代码,红色为修改的部分
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class NGUICoverFlow : MonoBehaviour {
    private List<GameObject> photos = new List<GameObject>();
    private int photosCount = 5;
 
    private int currentIndex = 0;
    private float MARGIN_X = 3f;  //plane 之间的间隔
    private float ITEM_W = 10f;   //plane长宽为10M(10个单位长度)
 
    private float sliderValue = 4f;
    public UISlider uiSlider;
    void Start()
    {
        loadImages();
       //uiSlider.numberOfSteps = photosCount; //这里可设成Steps模式  随个人喜好
    }
 
    void loadImages()
    {
        for (int i = 0; i < photosCount; i++)
        {
            GameObject photo = GameObject.CreatePrimitive(PrimitiveType.Plane);
            photos.Add(photo);
            photo.layer = 14; //我的相片全部作为一个单独的层  这样镜面渲染就好办了
            photo.transform.eulerAngles = new Vector3(-90f, 0f, 0f);
            photo.transform.localScale = new Vector3(1.5f, 1f, -1f);   //根据图片设定长宽比,z:-1,使图正向
            photo.renderer.material.mainTexture = Resources.Load("photo" + i.ToString(), typeof(Texture2D)) as Texture2D;
            photo.transform.parent = gameObject.transform;
        }
        moveSlider(photos.Count / 2);
    }
 
    void moveSlider(int id)
    {
        if (currentIndex == id)
            return;
        currentIndex = id;
 
        for (int i = 0; i < photosCount; i++)
        {
            float targetX = 0f;
            float targetZ = 0f;
            float targetRot = 0f;
 
            targetX = MARGIN_X * (i - id);
            //left slides
            if (i < id)
            {
                targetX -= ITEM_W * 0.6f;
                targetZ = ITEM_W * 3f / 4;
                targetRot = -60f;
 
            }
            //right slides
            else if (i > id)
            {
                targetX += ITEM_W * 0.6f;
                targetZ = ITEM_W * 3f / 4;
                targetRot = 60f;
            }
            else
            {
                targetX += 0f;
                targetZ = 0f;
                targetRot = 0f;
            }
 
            GameObject photo = photos;
            float ys = photo.transform.position.y;
            Vector3 ea = photo.transform.eulerAngles;

            iTween.MoveTo(photo, new Vector3(targetX, ys, targetZ), 1f);
            iTween.RotateTo(photo, new Vector3(ea.x, targetRot, targetZ), 1f);
        }
    }
   public void OnSliderChange(float value)

   {
       Debug.Log(value);
       moveSlider((int)(value * photosCount));
   }
}
下面是uiSlider的设置

 
镜面效果是我从某个网页找到的,请点击看:
http://blog.163.com/lnwanggang@yeah/blog/static/165332162201010611107883/
这个效果写得很好,我就不复制黏贴了,
主要是搞一个shader和一个调用的文件MirrorReflection.cs:
其实这两个东西到底什么意思我也没看懂,我会吐槽么

反正我是拿来用了
其实感觉不写shader也可以  直接拿FX/Mirror Reflection那个来用 
但是那个MirrorReflection.cs是一定要写的
几个参数默认就好了,只有m_ReflectLayers这个设置为picture的层就行了 


不过我对比过好像这个多了一句shader语句好像是image效果的意义不明
 
再自己用ps新建一个64*64的图片
rgb为106,107,106, 整个图片的透明度为40%,然后保存成png放入场景中,作为镜面的材质色

一定要
最后调整一下各个方向的位置和角度,
搞定!~ 自己动手丰衣足食   项目我就不放出来了



[출처] http://www.ceeger.com/forum/read.php?tid=1411

반응형
Posted by blueasa
, |



[Link] https://github.com/kimsama/Unity-NGUIExtension

반응형
Posted by blueasa
, |

Optimization Technique :

Let’s take an example, and see why and where we can optimise. Below  Coroutine just waits for the 0.5 sec and then call your desired method.

1
2
3
4
5
6
7
8
9
IEnumerator WaitCoroutine()
 
{
 
yield return new WaitForSeconds(0.5f);
 
// Call your Method here
 
}

 

But every time you call this method “new WaitForSeconds(0.5f)” will allocate memory for the new object, which is not good.

Instead, we should save its reference in Start, and use it when it is required, In this way, we will not allocate memory on every call.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
WaitForSeconds wait;
 
void Start()
{
  wait = new WaitForSeconds(0.5f);
}
  
IEnumerator WaitCoroutine()
{
 
    yield return wait;
 
// Call your Method here
 
}

Never use “yield return 0“, instead of that use “yield return null



[출처] http://www.unitygeek.com/coroutines-in-unity3d/

반응형
Posted by blueasa
, |

UNITY가 Play도중에 죽는 경우가 자주 발생하기 때문에 아래와 같이 Play를 감지하여 Assets을 저장하도록 하면 저장을 하지 못해서 편집한 내용이 유실되는 상황을 방지 할 수 있다.

using System.Collections;
using UnityEditor;
using UnityEngine;
 
[InitializeOnLoad]
public class SaveAssets
{
	static SaveAssets()
	{
		EditorApplication.playmodeStateChanged = () =>
		{
			if (EditorApplication.isPlayingOrWillChangePlaymode)
			{
				EditorApplication.SaveAssets();
			}
		};
	}
}
 



[출처]

http://www.antegg.com/wiki/doku.php?id=note:unity_3d:%EC%97%90%EB%94%94%ED%84%B0%EC%97%90%EC%84%9C_%EA%B2%8C%EC%9E%84_%ED%94%8C%EB%A0%88%EC%9D%B4%EB%A5%BC_%ED%95%A0_%EB%95%8C_%EC%A0%80%EC%9E%A5%EB%90%98%EC%A7%80_%EC%95%8A%EC%9D%80_assets_%EC%A0%80%EC%9E%A5%ED%95%98%EA%B8%B0


[참조]

https://docs.unity3d.com/ScriptReference/EditorApplication.SaveAssets.html

반응형
Posted by blueasa
, |

Apologies for the delay, I hit a brick wall dealing with WWW - as this is my first time I use this class, I didn't know that I had to provide the FULL path to a file for it to load it successfully.

The code is taken from here, with some modifications.

Just attach this to some gameObject, and have your music files in your Asset folder (at edit-time) or the game folder (when you build).

It's in C#, if you have trouble translating to JS let me know.

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. public class MusicPlayer : MonoBehaviour
  7. {
  8. public enum SeekDirection { Forward, Backward }
  9. public AudioSource source;
  10. public List<AudioClip> clips = new List<AudioClip>();
  11. [SerializeField] [HideInInspector] private int currentIndex = 0;
  12. private FileInfo[] soundFiles;
  13. private List<string> validExtensions = new List<string> { ".ogg", ".wav" }; // Don't forget the "." i.e. "ogg" won't work - cause Path.GetExtension(filePath) will return .ext, not just ext.
  14. private string absolutePath = "./"; // relative path to where the app is running - change this to "./music" in your case
  15. void Start()
  16. {
  17. //being able to test in unity
  18. if (Application.isEditor) absolutePath = "Assets/";
  19. if (source == null) source = gameObject.AddComponent<AudioSource>();
  20. ReloadSounds();
  21. }
  22. void OnGUI()
  23. {
  24. if (GUILayout.Button("Previous")) {
  25. Seek(SeekDirection.Backward);
  26. PlayCurrent();
  27. }
  28. if (GUILayout.Button("Play current")) {
  29. PlayCurrent();
  30. }
  31. if (GUILayout.Button("Next")) {
  32. Seek(SeekDirection.Forward);
  33. PlayCurrent();
  34. }
  35. if (GUILayout.Button("Reload")) {
  36. ReloadSounds();
  37. }
  38. }
  39. void Seek(SeekDirection d)
  40. {
  41. if (d == SeekDirection.Forward)
  42. currentIndex = (currentIndex + 1) % clips.Count;
  43. else {
  44. currentIndex--;
  45. if (currentIndex < 0) currentIndex = clips.Count - 1;
  46. }
  47. }
  48. void PlayCurrent()
  49. {
  50. source.clip = clips[currentIndex];
  51. source.Play();
  52. }
  53. void ReloadSounds()
  54. {
  55. clips.Clear();
  56. // get all valid files
  57. var info = new DirectoryInfo(absolutePath);
  58. soundFiles = info.GetFiles()
  59. .Where(f => IsValidFileType(f.Name))
  60. .ToArray();
  61. // and load them
  62. foreach (var s in soundFiles)
  63. StartCoroutine(LoadFile(s.FullName));
  64. }
  65. bool IsValidFileType(string fileName)
  66. {
  67. return validExtensions.Contains(Path.GetExtension(fileName));
  68. // Alternatively, you could go fileName.SubString(fileName.LastIndexOf('.') + 1); that way you don't need the '.' when you add your extensions
  69. }
  70. IEnumerator LoadFile(string path)
  71. {
  72. WWW www = new WWW("file://" + path);
  73. print("loading " + path);
  74. AudioClip clip = www.GetAudioClip(false);
  75. while(!clip.isReadyToPlay)
  76. yield return www;
  77. print("done loading");
  78. clip.name = Path.GetFileName(path);
  79. clips.Add(clip);
  80. }
  81. }

Couple of notes:

  1. You might ask, why use create a DirectoryInfo and then call GetFiles on that, instead of just directly go Directory.GetFiles(path)? Well, the latter one will return the paths of the files in pathrelative to path and NOT the full path (which is what you'll need to pass into WWW). i.e. if you do Directory.GetFiles("Assets"); it will return, (for example) a string array of { "Assets/soundFile1.wav", "Assets/soundFile2.ogg", etc } - these paths are relative to "Assets" while the full path would be "E:\Dropbox\UnityStuff\MyProject...\soundFile.wav"

  2. MP3s won't work in a PC build (haven't tried wav, but it should work) see this for more info. If you want MP3s, you have to go for something more complex, like MP3Sharp,NAudio and others.

  3. If you want to search recursively, change your GetFiles() call to GetFiles("*.*", SearchOption.AllDirectories)

EDIT:

JS, as per your request

  1. import UnityEngine;
  2. import System.Collections.Generic;
  3. import System.IO;
  4. import System.Linq;
  5. public enum SeekDirection { Forward, Backward }
  6. public var source : AudioSource;
  7. public var clips : List.<AudioClip> = new List.<AudioClip>();
  8. @HideInInspector @SerializeField private var currentIndex : int = 0;
  9. private var soundFiles : FileInfo[];
  10. private var validExtensions : List.<String> = new List.<String> ([ ".ogg", ".wav" ]);
  11. private var absolutePath : String = "./"; // relative path to where the app is running
  12. function Start()
  13. {
  14. //being able to test in unity
  15. if (Application.isEditor)
  16. absolutePath = "Assets/";
  17. if (source == null)
  18. source = gameObject.AddComponent.<AudioSource>();
  19. ReloadSounds();
  20. }
  21. function OnGUI()
  22. {
  23. if (GUILayout.Button("Previous")) {
  24. Seek(SeekDirection.Backward);
  25. PlayCurrent();
  26. }
  27. if (GUILayout.Button("Play current")) {
  28. PlayCurrent();
  29. }
  30. if (GUILayout.Button("Next")) {
  31. Seek(SeekDirection.Forward);
  32. PlayCurrent();
  33. }
  34. if (GUILayout.Button("Reload")) {
  35. ReloadSounds();
  36. }
  37. }
  38. function Seek(d : SeekDirection)
  39. {
  40. if (d == SeekDirection.Forward)
  41. currentIndex = (currentIndex + 1) % clips.Count;
  42. else {
  43. currentIndex--;
  44. if (currentIndex < 0) currentIndex = clips.Count - 1;
  45. }
  46. }
  47. function PlayCurrent()
  48. {
  49. source.clip = clips[currentIndex];
  50. source.Play();
  51. }
  52. function ReloadSounds()
  53. {
  54. clips.Clear();
  55. // get all valid files
  56. var info = new DirectoryInfo(absolutePath);
  57. soundFiles = info.GetFiles()
  58. .Where(function (f) { return IsValidFileType(f.Name); } )
  59. .ToArray();
  60. // and load them
  61. for(var s in soundFiles)
  62. StartCoroutine(LoadFile(s.FullName));
  63. }
  64. function IsValidFileType(fileName : String) : boolean
  65. {
  66. return validExtensions.Contains(Path.GetExtension(fileName));
  67. }
  68. function LoadFile(path : String)
  69. {
  70. var www = new WWW("file://" + path);
  71. print("loading " + path);
  72. var clip = www.GetAudioClip(false);
  73. while(!clip.isReadyToPlay)
  74. yield www;
  75. print("done loading");
  76. clip.name = Path.GetFileName(path);
  77. clips.Add(clip);
  78. }




[출처] http://answers.unity3d.com/questions/652919/music-player-get-songs-from-directory.html

반응형
Posted by blueasa
, |
Hey guys,

Just wanted to post a snippet in case it turns out to be helpful for anyone using an alternate localization solution with NGUI.

I'm currently using Smart Localization which can be found here: http://forum.unity3d.com/threads/173837-RELEASED-Smart-Localization-for-Unity3D

It's really good, it's free and has some neat features such as Microsoft Translate integration.

In order to use it with NGUI, simply type your string key into the label field and drag this script on.

Cheers!

Code (csharp):
  1.  
  2. using UnityEngine;
  3. using System.Collections;
  4. using System.Globalization;
  5.  
  6. [RequireComponent(typeof(UIWidget))]
  7. [AddComponentMenu("NGUI/UI/LocalizeWidget")]
  8. public class LocalizeWidget : MonoBehaviour
  9. {
  10.     // No public variables, we'll get the key from the widget field
  11.     private string key;
  12.     private string mLanguage;
  13.     private LanguageManager loc;
  14.  
  15.     // Localize the widget on start.
  16.     private void Start()
  17.     {
  18.         // Reference the language manager
  19.         loc = LanguageManager.Instance;
  20.        
  21.         // Hook up a delegate to run the localize script whenever a language was changed
  22.         loc.OnChangeLanguage += new ChangeLanguageEventHandler(Localize);
  23.        
  24.         // Initial localize run
  25.         Localize();
  26.     }
  27.    
  28.     // Incase the script didn't get the message from being inactive
  29.     private void OnEnable()
  30.     {
  31.         if(mLanguage != loc.language)
  32.             Localize();
  33.     }
  34.    
  35.     // Force-localize the widget.
  36.     private void Localize(LanguageManager thisLanguage=null)
  37.     {
  38.         UIWidget w = GetComponent<UIWidget>();
  39.         UILabel lbl = w as UILabel;
  40.         UISprite sp = w as UISprite;
  41.  
  42.         // If no localization key has been specified, use the label's text as the key
  43.         if (lbl != null)
  44.             key = lbl.text;
  45.        
  46.         string val = loc.GetTextValue(key);
  47.        
  48.         if(string.IsNullOrEmpty(val))
  49.             val = "Missing String";
  50.  
  51.         if (lbl != null)
  52.         {
  53.             // If this is a label used by input, we should localize its default value instead
  54.             UIInput input = NGUITools.FindInParents<UIInput>(lbl.gameObject);
  55.            
  56.             if (input != null  input.label == lbl)
  57.                 input.defaultText = val;
  58.             else
  59.                 lbl.text = val;
  60.         }
  61.         else if (sp != null)
  62.         {
  63.             sp.spriteName = val;
  64.             sp.MakePixelPerfect();
  65.         }
  66.        
  67.         // Set this widget's current language
  68.         mLanguage = loc.language;
  69.     }
  70. }
  71.  
 



출처 : http://forum.unity3d.com/threads/smart-localization-with-ngui.189253/


참조 : http://forum.unity3d.com/threads/released-smart-localization-for-unity3d.173837/

반응형
Posted by blueasa
, |

Unity로 안드로이드 앱을 개발하다보면 스크롤 안에 버튼이 들어갈 경우가 종종 있다.

PC에서 테스트 할 때는 마우스로 잘 눌리던 버튼이 스마트 폰에 넣어서 테스트 해보면 간혹 잘 눌리지 않는 경우가 있다. 이럴때 EventSystem 설정을 바꿔줘야하는데 다음과 같이 세팅 하면 적당하다.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private const float inchToCm = 2.54f;
     
[SerializeField]
private EventSystem eventSystem = null;
     
[SerializeField]
private float dragThresholdCM = 0.5f;
//For drag Threshold
     
private void SetDragThreshold()
{
    if (eventSystem != null)
    {
        eventSystem.pixelDragThreshold = (int)(dragThresholdCM * Screen.dpi / inchToCm);
    }
}
  
  
void Awake()
{
    SetDragThreshold();
}



출처 : http://knightk.tistory.com/12

반응형
Posted by blueasa
, |