青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

l

成都手游碼農(nóng)一枚
隨筆 - 32, 文章 - 0, 評(píng)論 - 117, 引用 - 0
數(shù)據(jù)加載中……

[Unity3D] 5.0 圖集合并擴(kuò)展工具,用于解決UGUI與AssetBundle打包造成資源包過大的問題

UGUI Image已Sprite為主,而簡單的合并圖集可以使用自帶的SpritePacker。
而當(dāng)在使用AssetBundle的時(shí)候情況有些不同,會(huì)造成每個(gè)AB都會(huì)引入完整的Sprite圖集,顯然就增加了AB的大小,重復(fù)資源。
為了解決這個(gè)問題我們可以手動(dòng)合并圖集,那么方案也有多種,這里我們可以編輯器自帶的API來實(shí)現(xiàn)一個(gè)小的圖集合并工具。
 private static bool CombineSpritesHelper(string path, string dpath, string name, int padding)
    
{
        
string[] paths = AssetDatabase.FindAssets("t:sprite"new string[] { path });
        List
<Sprite> spriteList = new List<Sprite>();
        List
<Texture2D> texList = new List<Texture2D>();

        
foreach (var o in paths)
        
{
            Sprite s 
= AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(o), typeof(Sprite)) as Sprite;
            
if (null != s)
            
{
                spriteList.Add(s);
                texList.Add(s.texture);
            }

        }


        
if (texList.Count > 0)
        
{
            Texture2D tex 
= new Texture2D(10241024, TextureFormat.ARGB32, true);
            Rect[] uvs 
= UITexturePacker.PackTextures(tex, texList.ToArray(), 44, padding, 1024);
            
if (null == uvs)
            
{
                EditorUtility.DisplayDialog(path, 
"圖集超過1024,需要分組成多張圖集""點(diǎn)擊退出");
                Object.DestroyImmediate(tex);
                tex 
= null;
                
return false;
            }

            
else
            
{
                List
<SpriteMetaData> metaList = new List<SpriteMetaData>();
                
for (int i = 0; i < uvs.Length; ++i)
                
{
                    SpriteMetaData data 
= new SpriteMetaData();
                    data.alignment 
= (int)SpriteAlignment.Center;
                    data.border 
= spriteList[i].border;
                    data.name 
= spriteList[i].name;
                    data.pivot 
= spriteList[i].pivot;
                    data.rect 
= new Rect(uvs[i].x * tex.width, uvs[i].y * tex.height, uvs[i].width * tex.width, uvs[i].height * tex.height);
                    metaList.Add(data);
                }


                
//string dpath = path.Substring(0, path.Length - obj.name.Length) + "SpriteSet";
                if (!System.IO.Directory.Exists(dpath))
                
{
                    System.IO.Directory.CreateDirectory(dpath);
                }


                
string file = dpath + "/" + name + ".png";
                
if (System.IO.File.Exists(file))
                
{
                    System.IO.File.Delete(file);
                }

                System.IO.File.WriteAllBytes(file, tex.EncodeToPNG());

                AssetDatabase.ImportAsset(file, ImportAssetOptions.ForceUpdate);
                TextureImporter importer 
= AssetImporter.GetAtPath(file) as TextureImporter;
                importer.spritesheet 
= metaList.ToArray();
                importer.spriteImportMode 
= SpriteImportMode.Multiple;
                importer.textureType 
= TextureImporterType.Sprite;
                importer.textureFormat 
= TextureImporterFormat.ARGB32;
                importer.mipmapEnabled 
= true;
                importer.mipmapFilter 
= TextureImporterMipFilter.BoxFilter;
                importer.assetBundleName 
= "ui_image/" + name.ToLower();
                AssetDatabase.ImportAsset(file);
                AssetDatabase.Refresh();
            }

        }

        
return true;
    }


    [MenuItem(
"Tool/Combine Sprites")]
    [MenuItem(
"Assets/Tool/Combine Sprites")]
    
public static void CombineSprites()
    
{
        EditorUtility.DisplayProgressBar(
"Combine Sprites""Initializing "0);
        
try
        
{
            Object obj 
= Selection.activeObject;
            
string path = AssetDatabase.GetAssetPath(obj.GetInstanceID());
            
string dpath = path.Substring(0, path.Length - obj.name.Length) + "SpriteSet";

            
if (System.IO.Directory.Exists(path))
            
{
                
string[] directories = System.IO.Directory.GetDirectories(path);
                
int count = 0;
                
if (directories.Length > 0)
                
{
                    
foreach (var directory in directories)
                    
{
                        count
++;
                        EditorUtility.DisplayProgressBar(
"Combine Sprites"string.Format("combing {0}", count), (float)(count) / (directories.Length));
                        
if (!CombineSpritesHelper(directory, dpath, string.Concat(obj.name, "_", count.ToString()), 1))
                        
{
                            
break;
                        }

                    }

                }

                
else
                
{
                    EditorUtility.DisplayProgressBar(
"Combine Sprites""combing 0"1);
                    CombineSpritesHelper(path, dpath, obj.name, 
1);
                }

            }

        }

        
catch (System.Exception e)
        
{
            Debug.LogError(e);
        }

        EditorUtility.ClearProgressBar();
    }

使用方法很簡單,可以修改源碼中的路徑,可以將多個(gè)Single Sprite合成一個(gè)Multi Sprite。然后在供,UGUI使用,注意最好保存好合并前的源文件,不然可能造成新增圖片打圖集后對(duì)應(yīng)不上從而造成引用丟失。

補(bǔ)充UITextPacker.cs :引用自NGUI
/*
    Based on the Public Domain MaxRectsBinPack.cpp source by Jukka Jylänki
    
https://github.com/juj/RectangleBinPack/

    Ported to C# by Sven Magnus
    This version is also public domain - do whatever you want with it.
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class UITexturePacker
{
    public int binWidth = 0;
    public int binHeight = 0;
    public bool allowRotations;

    public List<Rect> usedRectangles = new List<Rect>();
    public List<Rect> freeRectangles = new List<Rect>();

    public enum FreeRectChoiceHeuristic
    {
        RectBestShortSideFit, ///< -BSSF: Positions the rectangle against the short side of a free rectangle into which it fits the best.
        RectBestLongSideFit, ///< -BLSF: Positions the rectangle against the long side of a free rectangle into which it fits the best.
        RectBestAreaFit, ///< -BAF: Positions the rectangle into the smallest free rect into which it fits.
        RectBottomLeftRule, ///< -BL: Does the Tetris placement.
        RectContactPointRule ///< -CP: Choosest the placement where the rectangle touches other rects as much as possible.
    };

    public UITexturePacker (int width, int height, bool rotations)
    {
        Init(width, height, rotations);
    }

    public void Init (int width, int height, bool rotations)
    {
        binWidth = width;
        binHeight = height;
        allowRotations = rotations;

        Rect n = new Rect();
        n.x = 0;
        n.y = 0;
        n.width = width;
        n.height = height;

        usedRectangles.Clear();

        freeRectangles.Clear();
        freeRectangles.Add(n);
    }

    private struct Storage
    {
        public Rect rect;
        public bool paddingX;
        public bool paddingY;
    }

    public static Rect[] PackTextures (Texture2D texture, Texture2D[] textures, int width, int height, int padding, int maxSize)
    {
        if (width > maxSize || height > maxSize) return null;
        if (width > maxSize || height > maxSize) { int temp = width; width = height; height = temp; }
        
        // Force square by sizing up
        /*
        if (NGUISettings.forceSquareAtlas)
        {
            if (width > height)
                height = width;
            else if (height > width)
                width = height;
        }
        
*/
        UITexturePacker bp = new UITexturePacker(width, height, false);
        Storage[] storage = new Storage[textures.Length];

        for (int i = 0; i < textures.Length; i++)
        {
            Texture2D tex = textures[i];
            if (!tex) continue;

            Rect rect = new Rect();

            int xPadding = 1;
            int yPadding = 1;

            for (xPadding = 1; xPadding >= 0; --xPadding)
            {
                for (yPadding = 1; yPadding >= 0; --yPadding)
                {
                    rect = bp.Insert(tex.width + (xPadding * padding), tex.height + (yPadding * padding),
                        UITexturePacker.FreeRectChoiceHeuristic.RectBestAreaFit);
                    if (rect.width != 0 && rect.height != 0) break;

                    // After having no padding if it still doesn't fit -- increase texture size.
                    else if (xPadding == 0 && yPadding == 0)
                    {
                        return PackTextures(texture, textures, width * (width <= height ? 2 : 1),
                            height * (height < width ? 2 : 1), padding, maxSize);
                    }
                }
                if (rect.width != 0 && rect.height != 0) break;
            }

            storage[i] = new Storage();
            storage[i].rect = rect;
            storage[i].paddingX = (xPadding != 0);
            storage[i].paddingY = (yPadding != 0);
        }

        texture.Resize(width, height);
        texture.SetPixels(new Color[width * height]);

        // The returned rects
        Rect[] rects = new Rect[textures.Length];

        for (int i = 0; i < textures.Length; i++)
        {
            Texture2D tex = textures[i];
            if (!tex) continue;

            Rect rect = storage[i].rect;
            int xPadding = (storage[i].paddingX ? padding : 0);
            int yPadding = (storage[i].paddingY ? padding : 0);
            Color[] colors = tex.GetPixels();

            // Would be used to rotate the texture if need be.
            if (rect.width != tex.width + xPadding)
            {
                Color[] newColors = tex.GetPixels();

                for (int x = 0; x < rect.width; x++)
                {
                    for (int y = 0; y < rect.height; y++)
                    {
                        int prevIndex = ((int)rect.height - (y + 1)) + x * (int)tex.width;
                        newColors[x + y * (int)rect.width] = colors[prevIndex];
                    }
                }

                colors = newColors;
            }

            texture.SetPixels((int)rect.x, (int)rect.y, (int)rect.width - xPadding, (int)rect.height - yPadding, colors);
            rect.x /= width;
            rect.y /= height;
            rect.width = (rect.width - xPadding) / width;
            rect.height = (rect.height - yPadding) / height;
            rects[i] = rect;
        }
        texture.Apply();
        return rects;
    }

    public Rect Insert (int width, int height, FreeRectChoiceHeuristic method)
    {
        Rect newNode = new Rect();
        int score1 = 0; // Unused in this function. We don't need to know the score after finding the position.
        int score2 = 0;
        switch (method)
        {
            case FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break;
            case FreeRectChoiceHeuristic.RectBottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break;
            case FreeRectChoiceHeuristic.RectContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1); break;
            case FreeRectChoiceHeuristic.RectBestLongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score2, ref score1); break;
            case FreeRectChoiceHeuristic.RectBestAreaFit: newNode = FindPositionForNewNodeBestAreaFit(width, height, ref score1, ref score2); break;
        }

        if (newNode.height == 0)
            return newNode;

        int numRectanglesToProcess = freeRectangles.Count;
        for (int i = 0; i < numRectanglesToProcess; ++i)
        {
            if (SplitFreeNode(freeRectangles[i], ref newNode))
            {
                freeRectangles.RemoveAt(i);
                --i;
                --numRectanglesToProcess;
            }
        }

        PruneFreeList();

        usedRectangles.Add(newNode);
        return newNode;
    }

    public void Insert (List<Rect> rects, List<Rect> dst, FreeRectChoiceHeuristic method)
    {
        dst.Clear();

        while (rects.Count > 0)
        {
            int bestScore1 = int.MaxValue;
            int bestScore2 = int.MaxValue;
            int bestRectIndex = -1;
            Rect bestNode = new Rect();

            for (int i = 0; i < rects.Count; ++i)
            {
                int score1 = 0;
                int score2 = 0;
                Rect newNode = ScoreRect((int)rects[i].width, (int)rects[i].height, method, ref score1, ref score2);

                if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2))
                {
                    bestScore1 = score1;
                    bestScore2 = score2;
                    bestNode = newNode;
                    bestRectIndex = i;
                }
            }

            if (bestRectIndex == -1)
                return;

            PlaceRect(bestNode);
            rects.RemoveAt(bestRectIndex);
        }
    }

    void PlaceRect (Rect node)
    {
        int numRectanglesToProcess = freeRectangles.Count;
        for (int i = 0; i < numRectanglesToProcess; ++i)
        {
            if (SplitFreeNode(freeRectangles[i], ref node))
            {
                freeRectangles.RemoveAt(i);
                --i;
                --numRectanglesToProcess;
            }
        }

        PruneFreeList();

        usedRectangles.Add(node);
    }

    Rect ScoreRect (int width, int height, FreeRectChoiceHeuristic method, ref int score1, ref int score2)
    {
        Rect newNode = new Rect();
        score1 = int.MaxValue;
        score2 = int.MaxValue;
        switch (method)
        {
            case FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break;
            case FreeRectChoiceHeuristic.RectBottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break;
            case FreeRectChoiceHeuristic.RectContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1);
            score1 = -score1; // Reverse since we are minimizing, but for contact point score bigger is better.
            break;
            case FreeRectChoiceHeuristic.RectBestLongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score2, ref score1); break;
            case FreeRectChoiceHeuristic.RectBestAreaFit: newNode = FindPositionForNewNodeBestAreaFit(width, height, ref score1, ref score2); break;
        }

        // Cannot fit the current rectangle.
        if (newNode.height == 0)
        {
            score1 = int.MaxValue;
            score2 = int.MaxValue;
        }

        return newNode;
    }

    /// Computes the ratio of used surface area.
    public float Occupancy ()
    {
        ulong usedSurfaceArea = 0;
        for (int i = 0; i < usedRectangles.Count; ++i)
            usedSurfaceArea += (uint)usedRectangles[i].width * (uint)usedRectangles[i].height;

        return (float)usedSurfaceArea / (binWidth * binHeight);
    }

    Rect FindPositionForNewNodeBottomLeft (int width, int height, ref int bestY, ref int bestX)
    {
        Rect bestNode = new Rect();
        //memset(bestNode, 0, sizeof(Rect));

        bestY = int.MaxValue;

        for (int i = 0; i < freeRectangles.Count; ++i)
        {
            // Try to place the rectangle in upright (non-flipped) orientation.
            if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
            {
                int topSideY = (int)freeRectangles[i].y + height;
                if (topSideY < bestY || (topSideY == bestY && freeRectangles[i].x < bestX))
                {
                    bestNode.x = freeRectangles[i].x;
                    bestNode.y = freeRectangles[i].y;
                    bestNode.width = width;
                    bestNode.height = height;
                    bestY = topSideY;
                    bestX = (int)freeRectangles[i].x;
                }
            }
            if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
            {
                int topSideY = (int)freeRectangles[i].y + width;
                if (topSideY < bestY || (topSideY == bestY && freeRectangles[i].x < bestX))
                {
                    bestNode.x = freeRectangles[i].x;
                    bestNode.y = freeRectangles[i].y;
                    bestNode.width = height;
                    bestNode.height = width;
                    bestY = topSideY;
                    bestX = (int)freeRectangles[i].x;
                }
            }
        }
        return bestNode;
    }

    Rect FindPositionForNewNodeBestShortSideFit (int width, int height, ref int bestShortSideFit, ref int bestLongSideFit)
    {
        Rect bestNode = new Rect();
        //memset(&bestNode, 0, sizeof(Rect));

        bestShortSideFit = int.MaxValue;

        for (int i = 0; i < freeRectangles.Count; ++i)
        {
            // Try to place the rectangle in upright (non-flipped) orientation.
            if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
            {
                int leftoverHoriz = Mathf.Abs((int)freeRectangles[i].width - width);
                int leftoverVert = Mathf.Abs((int)freeRectangles[i].height - height);
                int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
                int longSideFit = Mathf.Max(leftoverHoriz, leftoverVert);

                if (shortSideFit < bestShortSideFit || (shortSideFit == bestShortSideFit && longSideFit < bestLongSideFit))
                {
                    bestNode.x = freeRectangles[i].x;
                    bestNode.y = freeRectangles[i].y;
                    bestNode.width = width;
                    bestNode.height = height;
                    bestShortSideFit = shortSideFit;
                    bestLongSideFit = longSideFit;
                }
            }

            if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
            {
                int flippedLeftoverHoriz = Mathf.Abs((int)freeRectangles[i].width - height);
                int flippedLeftoverVert = Mathf.Abs((int)freeRectangles[i].height - width);
                int flippedShortSideFit = Mathf.Min(flippedLeftoverHoriz, flippedLeftoverVert);
                int flippedLongSideFit = Mathf.Max(flippedLeftoverHoriz, flippedLeftoverVert);

                if (flippedShortSideFit < bestShortSideFit || (flippedShortSideFit == bestShortSideFit && flippedLongSideFit < bestLongSideFit))
                {
                    bestNode.x = freeRectangles[i].x;
                    bestNode.y = freeRectangles[i].y;
                    bestNode.width = height;
                    bestNode.height = width;
                    bestShortSideFit = flippedShortSideFit;
                    bestLongSideFit = flippedLongSideFit;
                }
            }
        }
        return bestNode;
    }

    Rect FindPositionForNewNodeBestLongSideFit (int width, int height, ref int bestShortSideFit, ref int bestLongSideFit)
    {
        Rect bestNode = new Rect();
        //memset(&bestNode, 0, sizeof(Rect));

        bestLongSideFit = int.MaxValue;

        for (int i = 0; i < freeRectangles.Count; ++i)
        {
            // Try to place the rectangle in upright (non-flipped) orientation.
            if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
            {
                int leftoverHoriz = Mathf.Abs((int)freeRectangles[i].width - width);
                int leftoverVert = Mathf.Abs((int)freeRectangles[i].height - height);
                int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
                int longSideFit = Mathf.Max(leftoverHoriz, leftoverVert);

                if (longSideFit < bestLongSideFit || (longSideFit == bestLongSideFit && shortSideFit < bestShortSideFit))
                {
                    bestNode.x = freeRectangles[i].x;
                    bestNode.y = freeRectangles[i].y;
                    bestNode.width = width;
                    bestNode.height = height;
                    bestShortSideFit = shortSideFit;
                    bestLongSideFit = longSideFit;
                }
            }

            if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
            {
                int leftoverHoriz = Mathf.Abs((int)freeRectangles[i].width - height);
                int leftoverVert = Mathf.Abs((int)freeRectangles[i].height - width);
                int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
                int longSideFit = Mathf.Max(leftoverHoriz, leftoverVert);

                if (longSideFit < bestLongSideFit || (longSideFit == bestLongSideFit && shortSideFit < bestShortSideFit))
                {
                    bestNode.x = freeRectangles[i].x;
                    bestNode.y = freeRectangles[i].y;
                    bestNode.width = height;
                    bestNode.height = width;
                    bestShortSideFit = shortSideFit;
                    bestLongSideFit = longSideFit;
                }
            }
        }
        return bestNode;
    }

    Rect FindPositionForNewNodeBestAreaFit (int width, int height, ref int bestAreaFit, ref int bestShortSideFit)
    {
        Rect bestNode = new Rect();
        //memset(&bestNode, 0, sizeof(Rect));

        bestAreaFit = int.MaxValue;

        for (int i = 0; i < freeRectangles.Count; ++i)
        {
            int areaFit = (int)freeRectangles[i].width * (int)freeRectangles[i].height - width * height;

            // Try to place the rectangle in upright (non-flipped) orientation.
            if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
            {
                int leftoverHoriz = Mathf.Abs((int)freeRectangles[i].width - width);
                int leftoverVert = Mathf.Abs((int)freeRectangles[i].height - height);
                int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);

                if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit))
                {
                    bestNode.x = freeRectangles[i].x;
                    bestNode.y = freeRectangles[i].y;
                    bestNode.width = width;
                    bestNode.height = height;
                    bestShortSideFit = shortSideFit;
                    bestAreaFit = areaFit;
                }
            }

            if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
            {
                int leftoverHoriz = Mathf.Abs((int)freeRectangles[i].width - height);
                int leftoverVert = Mathf.Abs((int)freeRectangles[i].height - width);
                int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);

                if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit))
                {
                    bestNode.x = freeRectangles[i].x;
                    bestNode.y = freeRectangles[i].y;
                    bestNode.width = height;
                    bestNode.height = width;
                    bestShortSideFit = shortSideFit;
                    bestAreaFit = areaFit;
                }
            }
        }
        return bestNode;
    }

    /// Returns 0 if the two intervals i1 and i2 are disjoint, or the length of their overlap otherwise.
    int CommonIntervalLength (int i1start, int i1end, int i2start, int i2end)
    {
        if (i1end < i2start || i2end < i1start)
            return 0;
        return Mathf.Min(i1end, i2end) - Mathf.Max(i1start, i2start);
    }

    int ContactPointScoreNode (int x, int y, int width, int height)
    {
        int score = 0;

        if (x == 0 || x + width == binWidth)
            score += height;
        if (y == 0 || y + height == binHeight)
            score += width;

        for (int i = 0; i < usedRectangles.Count; ++i)
        {
            if (usedRectangles[i].x == x + width || usedRectangles[i].x + usedRectangles[i].width == x)
                score += CommonIntervalLength((int)usedRectangles[i].y, (int)usedRectangles[i].y + (int)usedRectangles[i].height, y, y + height);
            if (usedRectangles[i].y == y + height || usedRectangles[i].y + usedRectangles[i].height == y)
                score += CommonIntervalLength((int)usedRectangles[i].x, (int)usedRectangles[i].x + (int)usedRectangles[i].width, x, x + width);
        }
        return score;
    }

    Rect FindPositionForNewNodeContactPoint (int width, int height, ref int bestContactScore)
    {
        Rect bestNode = new Rect();
        //memset(&bestNode, 0, sizeof(Rect));

        bestContactScore = -1;

        for (int i = 0; i < freeRectangles.Count; ++i)
        {
            // Try to place the rectangle in upright (non-flipped) orientation.
            if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
            {
                int score = ContactPointScoreNode((int)freeRectangles[i].x, (int)freeRectangles[i].y, width, height);
                if (score > bestContactScore)
                {
                    bestNode.x = (int)freeRectangles[i].x;
                    bestNode.y = (int)freeRectangles[i].y;
                    bestNode.width = width;
                    bestNode.height = height;
                    bestContactScore = score;
                }
            }
            if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
            {
                int score = ContactPointScoreNode((int)freeRectangles[i].x, (int)freeRectangles[i].y, height, width);
                if (score > bestContactScore)
                {
                    bestNode.x = (int)freeRectangles[i].x;
                    bestNode.y = (int)freeRectangles[i].y;
                    bestNode.width = height;
                    bestNode.height = width;
                    bestContactScore = score;
                }
            }
        }
        return bestNode;
    }

    bool SplitFreeNode (Rect freeNode, ref Rect usedNode)
    {
        // Test with SAT if the rectangles even intersect.
        if (usedNode.x >= freeNode.x + freeNode.width || usedNode.x + usedNode.width <= freeNode.x ||
            usedNode.y >= freeNode.y + freeNode.height || usedNode.y + usedNode.height <= freeNode.y)
            return false;

        if (usedNode.x < freeNode.x + freeNode.width && usedNode.x + usedNode.width > freeNode.x)
        {
            // New node at the top side of the used node.
            if (usedNode.y > freeNode.y && usedNode.y < freeNode.y + freeNode.height)
            {
                Rect newNode = freeNode;
                newNode.height = usedNode.y - newNode.y;
                freeRectangles.Add(newNode);
            }

            // New node at the bottom side of the used node.
            if (usedNode.y + usedNode.height < freeNode.y + freeNode.height)
            {
                Rect newNode = freeNode;
                newNode.y = usedNode.y + usedNode.height;
                newNode.height = freeNode.y + freeNode.height - (usedNode.y + usedNode.height);
                freeRectangles.Add(newNode);
            }
        }

        if (usedNode.y < freeNode.y + freeNode.height && usedNode.y + usedNode.height > freeNode.y)
        {
            // New node at the left side of the used node.
            if (usedNode.x > freeNode.x && usedNode.x < freeNode.x + freeNode.width)
            {
                Rect newNode = freeNode;
                newNode.width = usedNode.x - newNode.x;
                freeRectangles.Add(newNode);
            }

            // New node at the right side of the used node.
            if (usedNode.x + usedNode.width < freeNode.x + freeNode.width)
            {
                Rect newNode = freeNode;
                newNode.x = usedNode.x + usedNode.width;
                newNode.width = freeNode.x + freeNode.width - (usedNode.x + usedNode.width);
                freeRectangles.Add(newNode);
            }
        }

        return true;
    }

    void PruneFreeList ()
    {
        for (int i = 0; i < freeRectangles.Count; ++i)
            for (int j = i + 1; j < freeRectangles.Count; ++j)
            {
                if (IsContainedIn(freeRectangles[i], freeRectangles[j]))
                {
                    freeRectangles.RemoveAt(i);
                    --i;
                    break;
                }
                if (IsContainedIn(freeRectangles[j], freeRectangles[i]))
                {
                    freeRectangles.RemoveAt(j);
                    --j;
                }
            }
    }

    bool IsContainedIn (Rect a, Rect b)
    {
        return a.x >= b.x && a.y >= b.y
            && a.x + a.width <= b.x + b.width
            && a.y + a.height <= b.y + b.height;
    }
}

posted on 2015-12-09 17:19 l1989 閱讀(5449) 評(píng)論(2)  編輯 收藏 引用 所屬分類: 游戲

評(píng)論

# re: [Unity3D] 5.0 圖集合并擴(kuò)展工具,用于解決UGUI與AssetBundle打包造成資源包過大的問題  回復(fù)  更多評(píng)論   

UITexturePacker沒有這個(gè)API
2016-03-24 18:16 | mishimumu

# re: [Unity3D] 5.0 圖集合并擴(kuò)展工具,用于解決UGUI與AssetBundle打包造成資源包過大的問題  回復(fù)  更多評(píng)論   

已經(jīng)補(bǔ)上了
2016-05-17 13:37 | l1989
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            黄色成人av网站| 国产精品毛片在线看| 国产手机视频一区二区| 亚洲一区二区三区在线观看视频 | 欧美日韩国产a| 亚洲黄色高清| 亚洲精品色婷婷福利天堂| 欧美精品免费在线观看| 亚洲最黄网站| 亚洲欧美日本另类| 狠狠久久亚洲欧美专区| 理论片一区二区在线| 免费久久精品视频| 亚洲天堂男人| 亚洲欧美日韩第一区| 影音先锋日韩精品| 亚洲精品免费在线| 国产精品久久久久aaaa| 久久影院午夜论| 欧美不卡视频一区| 亚洲欧美日本日韩| 久久久精品久久久久| 一区二区三区久久网| 午夜精品久久久久久久99热浪潮 | 亚洲福利电影| 91久久国产综合久久| 国产精品二区在线观看| 久久免费的精品国产v∧| 农村妇女精品| 亚洲欧美日韩国产一区二区三区| 欧美亚洲免费电影| 亚洲狼人精品一区二区三区| 亚洲欧美日韩综合国产aⅴ| 在线日韩av片| 午夜欧美大尺度福利影院在线看 | 国产精品成人一区二区网站软件| 久久久久久国产精品mv| 欧美激情一区二区| 久久久伊人欧美| 国产精品久久久久毛片大屁完整版 | 日韩图片一区| 久久国产主播| 新67194成人永久网站| 免费成人小视频| 久久九九国产精品| 欧美午夜电影一区| 亚洲第一色在线| 国内精品视频在线播放| 一本一道久久综合狠狠老精东影业| 狠狠入ady亚洲精品| 中文在线资源观看网站视频免费不卡| 亚洲国产精品999| 欧美一区二区三区视频在线| 亚洲自拍偷拍色片视频| 欧美日本在线一区| 亚洲福利视频一区| 在线视频国内自拍亚洲视频| 亚洲欧美日本精品| 亚洲女性裸体视频| 欧美日韩在线播放| 亚洲精品日韩在线观看| 亚洲精品一区在线观看香蕉| 久久青青草原一区二区| 快射av在线播放一区| 国产亚洲精品aa午夜观看| 这里只有视频精品| 亚洲欧美日韩精品久久亚洲区| 欧美精品久久久久久久久久| 欧美激情亚洲激情| 亚洲国产综合视频在线观看| 久久一区精品| 亚洲第一精品夜夜躁人人爽 | 欧美视频久久| 一本一本久久a久久精品综合麻豆| 日韩一级视频免费观看在线| 欧美激情一区二区三区蜜桃视频| 亚洲国产精品久久久久秋霞蜜臀 | 久久精品国产久精国产一老狼| 一本色道综合亚洲| 欧美精品一区二区三区蜜桃 | 亚洲乱码精品一二三四区日韩在线| 亚洲美女区一区| 欧美日韩亚洲高清一区二区| 国产精品99久久99久久久二8| 欧美一区二区三区在线观看 | 欧美日本高清视频| aⅴ色国产欧美| 午夜久久福利| 一区二区三区自拍| 欧美大尺度在线| 亚洲午夜精品久久久久久浪潮| 欧美亚洲三区| 一区二区三区在线观看欧美| 亚洲一区三区视频在线观看| 亚洲精品激情| 欧美黄色小视频| 亚洲免费成人av电影| 亚洲在线视频网站| 国产亚洲视频在线| 免费观看日韩av| 亚洲一区二区在线| 久久综合影音| 国产精品99久久久久久久久久久久| 国产精品久久久久久久久免费樱桃 | 欧美在线免费看| 亚洲国产精彩中文乱码av在线播放| 欧美国产第一页| 亚洲国产婷婷香蕉久久久久久| 一区二区精品在线| 国产亚洲一级高清| 欧美精品导航| 久久精品99国产精品日本| 亚洲精品久久7777| 久久亚洲一区二区三区四区| 亚洲视频福利| 在线免费精品视频| 国产精品亚洲第一区在线暖暖韩国| 久久一二三国产| 亚洲一区二区三区在线视频| 亚洲国产成人不卡| 久久精品噜噜噜成人av农村| 亚洲午夜性刺激影院| 亚洲国产一二三| 国产无一区二区| 国产精品草草| 欧美激情综合五月色丁香| 久久久久.com| 久久成人免费日本黄色| 亚洲自拍偷拍一区| 99精品黄色片免费大全| 亚洲国产日韩欧美一区二区三区| 久久精品在线播放| 欧美在线网站| 亚洲欧美日韩中文在线制服| 老色鬼久久亚洲一区二区 | 国产精品成av人在线视午夜片| 久久久久综合网| 午夜精品国产更新| 亚洲一区国产| 亚洲午夜伦理| 中文在线不卡| 亚洲一区二区三区乱码aⅴ蜜桃女| 亚洲区一区二区三区| 亚洲第一视频网站| 欧美激情一级片一区二区| 免费国产自线拍一欧美视频| 久久九九全国免费精品观看| 久久精品国产一区二区三区免费看 | 亚洲精品网址在线观看| 亚洲精品久久久久久久久久久 | 欧美国产日韩免费| 免费欧美网站| 欧美精品入口| 欧美性大战久久久久| 欧美性猛交xxxx免费看久久久 | 久久国产精品亚洲77777| 欧美中文字幕视频| 久久精品中文字幕一区二区三区 | 亚洲国产三级在线| 91久久精品国产| 一本色道久久| 午夜精品视频在线观看一区二区| 午夜精品视频一区| 久久免费观看视频| 美国十次成人| 欧美三级电影大全| 国产一区二区久久久| 在线视频观看日韩| 亚洲理论电影网| 亚洲在线一区| 久久亚洲视频| 亚洲欧洲日本专区| 亚洲一区二区三区乱码aⅴ| 久久国产乱子精品免费女| 久久综合精品国产一区二区三区| 欧美国产一区二区| 国产精品视频网址| 136国产福利精品导航网址应用| 亚洲美女视频在线观看| 欧美与欧洲交xxxx免费观看| 男男成人高潮片免费网站| 99国内精品| 久久精品亚洲一区二区| 欧美片在线观看| 国产一区二区高清不卡| 99re热这里只有精品视频| 久久国产精品电影| 亚洲精选在线| 久久在精品线影院精品国产| 欧美日韩一区二区在线| 在线观看欧美亚洲| 欧美亚洲综合久久| 亚洲国产成人在线| 香蕉久久国产| 欧美视频在线视频| 亚洲高清不卡| 久久狠狠一本精品综合网| 亚洲美女视频网| 欧美超级免费视 在线| 国产日韩欧美中文|