Unity中从目前选择对象创建预设(Prefab)脚本

在Unity中选择一个游戏对象,然后通过这个脚本来快速生成一个Prefab预设.
将脚本放在Editor文件夹中,选择游戏对象,支持多选,然后选择菜单GameObject > Create Prefab From Selection,就会在根目录生成一个预设,名字和选择的游戏对象一样.当已经存在同名的预设,将会提示是否覆盖.

脚本名:CreatePrefabFromSelected.cs

using UnityEditor;
using UnityEngine;
using System.Collections;

class CreatePrefabFromSelected : ScriptableObject
{
    const string menuTitle = "GameObject/Create Prefab From Selected";

    /// <summary>
    /// Creates a prefab from the selected game object.
    /// </summary>
    [MenuItem(menuTitle)]
    static void CreatePrefab()
    {
        GameObject[] obj = Selection.gameObjects;

        foreach (GameObject go in obj)
        {
            string name = go.name;
            string localPath = "Assets/" + name + ".prefab";

            if (AssetDatabase.LoadAssetAtPath(localPath, typeof(GameObject)))
            {
                if (EditorUtility.DisplayDialog("Are you sure?", "The prefab already exists. Do you want to overwrite it?", "Yes", "No"))
                {
                    createNew(go, localPath);
                }
            }
            else
            {
                createNew(go, localPath);
            }

        }
    }

    static void createNew(GameObject obj, string localPath)
    {
        Object prefab = EditorUtility.CreateEmptyPrefab(localPath);
        EditorUtility.ReplacePrefab(obj, prefab);
        AssetDatabase.Refresh();

        DestroyImmediate(obj);
        GameObject clone = EditorUtility.InstantiatePrefab(prefab) as GameObject;
    }

    /// <summary>
    /// Validates the menu.
    /// </summary>
    /// <remarks>The item will be disabled if no game object is selected.</remarks>
    [MenuItem(menuTitle, true)]
    static bool ValidateCreatePrefab()
    {
        return Selection.activeGameObject != null;
    }
}

原文:http://www.unifycommunity.com/wiki/index.php?title=CreatePrefabFromSelected

Unity网格资源导出为*.Obj格式模型脚本

这个脚本可以导出Unity的网格资源为模型文件,是利用bjExporter.MeshToString()创建一个文本字符串构成的Obj文件.或者用ObjExporter.MeshToFile()直接保存为一个文件.

将下面2个脚本保存再Editor文件夹中,然后选择一个网格对象,在Custom菜单中根据需要选择导出为Obj文件.文件将被保存在项目目录的ExportedObj文件夹中.

文件名: ObjExporter.cs


using UnityEngine;
using System.Collections;
using System.IO;
using System.Text;

public class ObjExporter {

    public static string MeshToString(MeshFilter mf) {
        Mesh m = mf.mesh;
        Material[] mats = mf.renderer.sharedMaterials;
        
        StringBuilder sb = new StringBuilder();
        
        sb.Append("g ").Append(mf.name).Append("
");
        foreach(Vector3 v in m.vertices) {
            sb.Append(string.Format("v {0} {1} {2}
",v.x,v.y,v.z));
        }
        sb.Append("
");
        foreach(Vector3 v in m.normals) {
            sb.Append(string.Format("vn {0} {1} {2}
",v.x,v.y,v.z));
        }
        sb.Append("
");
        foreach(Vector3 v in m.uv) {
            sb.Append(string.Format("vt {0} {1}
",v.x,v.y));
        }
        for (int material=0; material < m.subMeshCount; material ++) {
            sb.Append("
");
            sb.Append("usemtl ").Append(mats[material].name).Append("
");
            sb.Append("usemap ").Append(mats[material].name).Append("
");
                
            int[] triangles = m.GetTriangles(material);
            for (int i=0;i<triangles.Length;i+=3) {
                sb.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}
",
                    triangles[i]+1, triangles[i+1]+1, triangles[i+2]+1));
            }
        }
        return sb.ToString();
    }
    
    public static void MeshToFile(MeshFilter mf, string filename) {
        using (StreamWriter sw = new StreamWriter(filename))
        {
            sw.Write(MeshToString(mf));
        }
    }
}

文件名: EditorObjExporter.cs
/*
Based on ObjExporter.cs, this "wrapper" lets you export to .OBJ directly from the editor menu.

This should be put in your "Editor"-folder. Use by selecting the objects you want to export, and select
the appropriate menu item from "Custom->Export". Exported models are put in a folder called
"ExportedObj" in the root of your Unity-project. Textures should also be copied and placed in the
same folder. */

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;

struct ObjMaterial
{
    public string name;
    public string textureName;
}

public class EditorObjExporter : ScriptableObject
{
    private static int vertexOffset = 0;
    private static int normalOffset = 0;
    private static int uvOffset = 0;
    
    
    //User should probably be able to change this. It is currently left as an excercise for
    //the reader.
    private static string targetFolder = "ExportedObj";
    

    private static string MeshToString(MeshFilter mf, Dictionary<string, ObjMaterial> materialList)
    {
        Mesh m = mf.sharedMesh;
        Material[] mats = mf.renderer.sharedMaterials;
        
        StringBuilder sb = new StringBuilder();
        
        sb.Append("g ").Append(mf.name).Append("
");
        foreach(Vector3 lv in m.vertices)
        {
            Vector3 wv = mf.transform.TransformPoint(lv);
        
            //This is sort of ugly - inverting x-component since we're in
            //a different coordinate system than "everyone" is "used to".
            sb.Append(string.Format("v {0} {1} {2}
",-wv.x,wv.y,wv.z));
        }
        sb.Append("
");
        
        foreach(Vector3 lv in m.normals)
        {
            Vector3 wv = mf.transform.TransformDirection(lv);
        
            sb.Append(string.Format("vn {0} {1} {2}
",-wv.x,wv.y,wv.z));
        }
        sb.Append("
");
        
        foreach(Vector3 v in m.uv)
        {
            sb.Append(string.Format("vt {0} {1}
",v.x,v.y));
        }
        
        for (int material=0; material < m.subMeshCount; material ++) {
            sb.Append("
");
            sb.Append("usemtl ").Append(mats[material].name).Append("
");
            sb.Append("usemap ").Append(mats[material].name).Append("
");
                
            //See if this material is already in the materiallist.
            try
         {
              ObjMaterial objMaterial = new ObjMaterial();
              
              objMaterial.name = mats[material].name;
              
              if (mats[material].mainTexture)
                objMaterial.textureName = EditorUtility.GetAssetPath(mats[material].mainTexture);
              else
                objMaterial.textureName = null;
              
              materialList.Add(objMaterial.name, objMaterial);
            }
            catch (ArgumentException)
            {
                //Already in the dictionary
            }

                
            int[] triangles = m.GetTriangles(material);
            for (int i=0;i<triangles.Length;i+=3)
            {
                //Because we inverted the x-component, we also needed to alter the triangle winding.
                sb.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}
",
                    triangles[i]+1 + vertexOffset, triangles[i+1]+1 + normalOffset, triangles[i+2]+1 + uvOffset));
            }
        }
        
        vertexOffset += m.vertices.Length;
        normalOffset += m.normals.Length;
        uvOffset += m.uv.Length;
        
        return sb.ToString();
    }
    
    private static void Clear()
    {
        vertexOffset = 0;
        normalOffset = 0;
        uvOffset = 0;
    }
    
    private static Dictionary<string, ObjMaterial> PrepareFileWrite()
    {
     Clear();
        
        return new Dictionary<string, ObjMaterial>();
    }
    
    private static void MaterialsToFile(Dictionary<string, ObjMaterial> materialList, string folder, string filename)
    {
     using (StreamWriter sw = new StreamWriter(folder + "/" + filename + ".mtl"))
        {
            foreach( KeyValuePair<string, ObjMaterial> kvp in materialList )
            {
                sw.Write("
");
                sw.Write("newmtl {0}
", kvp.Key);
                sw.Write("Ka  0.6 0.6 0.6
");
                sw.Write("Kd  0.6 0.6 0.6
");
                sw.Write("Ks  0.9 0.9 0.9
");
                sw.Write("d  1.0
");
                sw.Write("Ns  0.0
");
                sw.Write("illum 2
");
                
                if (kvp.Value.textureName != null)
                {
                    string destinationFile = kvp.Value.textureName;
                
                
                    int stripIndex = destinationFile.LastIndexOf('/');//FIXME: Should be Path.PathSeparator;
        
           if (stripIndex >= 0)
                        destinationFile = destinationFile.Substring(stripIndex + 1).Trim();
                    
                    
                    string relativeFile = destinationFile;
                    
                    destinationFile = folder + "/" + destinationFile;
                
                    Debug.Log("Copying texture from " + kvp.Value.textureName + " to " + destinationFile);
                
                    try
                    {
                        //Copy the source file
                        File.Copy(kvp.Value.textureName, destinationFile);
                    }
                    catch
                    {
                    
                    }  
                
                
                    sw.Write("map_Kd {0}", relativeFile);
                }
                    
                sw.Write("

");
            }
        }
    }
    
    private static void MeshToFile(MeshFilter mf, string folder, string filename)
    {
        Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();
    
        using (StreamWriter sw = new StreamWriter(folder +"/" + filename + ".obj"))
        {
            sw.Write("mtllib ./" + filename + ".mtl
");
        
            sw.Write(MeshToString(mf, materialList));
        }
        
        MaterialsToFile(materialList, folder, filename);
    }
    
    private static void MeshesToFile(MeshFilter[] mf, string folder, string filename)
    {
        Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();
    
        using (StreamWriter sw = new StreamWriter(folder +"/" + filename + ".obj"))
        {
            sw.Write("mtllib ./" + filename + ".mtl
");
        
            for (int i = 0; i < mf.Length; i++)
            {
                sw.Write(MeshToString(mf[i], materialList));
            }
        }
        
        MaterialsToFile(materialList, folder, filename);
    }
    
    private static bool CreateTargetFolder()
    {
        try
        {
            System.IO.Directory.CreateDirectory(targetFolder);
        }
        catch
        {
            EditorUtility.DisplayDialog("Error!", "Failed to create target folder!", "");
            return false;
        }
        
        return true;
    }
    
    [MenuItem ("Custom/Export/Export all MeshFilters in selection to separate OBJs")]
    static void ExportSelectionToSeparate()
    {
        if (!CreateTargetFolder())
            return;
    
        Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
        
        if (selection.Length == 0)
        {
            EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");
            return;
        }
        
        int exportedObjects = 0;
        
        for (int i = 0; i < selection.Length; i++)
        {
         Component[] meshfilter = selection[i].GetComponentsInChildren(typeof(MeshFilter));
        
         for (int m = 0; m < meshfilter.Length; m++)
         {
          exportedObjects++;
          MeshToFile((MeshFilter)meshfilter[m], targetFolder, selection[i].name + "_" + i + "_" + m);
         }
        }
        
        if (exportedObjects > 0)
         EditorUtility.DisplayDialog("Objects exported", "Exported " + exportedObjects + " objects", "");
        else
         EditorUtility.DisplayDialog("Objects not exported", "Make sure at least some of your selected objects have mesh filters!", "");
    }
    
    [MenuItem ("Custom/Export/Export whole selection to single OBJ")]
    static void ExportWholeSelectionToSingle()
    {
        if (!CreateTargetFolder())
            return;
            
            
        Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
        
        if (selection.Length == 0)
        {
            EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");
            return;
        }
        
        int exportedObjects = 0;
        
        ArrayList mfList = new ArrayList();
        
        for (int i = 0; i < selection.Length; i++)
        {
         Component[] meshfilter = selection[i].GetComponentsInChildren(typeof(MeshFilter));
        
         for (int m = 0; m < meshfilter.Length; m++)
         {
          exportedObjects++;
          mfList.Add(meshfilter[m]);
         }
        }
        
        if (exportedObjects > 0)
        {
         MeshFilter[] mf = new MeshFilter[mfList.Count];
        
         for (int i = 0; i < mfList.Count; i++)
         {
          mf[i] = (MeshFilter)mfList[i];
         }
        
         string filename = EditorApplication.currentScene + "_" + exportedObjects;
        
         int stripIndex = filename.LastIndexOf('/');//FIXME: Should be Path.PathSeparator
        
         if (stripIndex >= 0)
                filename = filename.Substring(stripIndex + 1).Trim();
        
         MeshesToFile(mf, targetFolder, filename);
        
        
         EditorUtility.DisplayDialog("Objects exported", "Exported " + exportedObjects + " objects to " + filename, "");
        }
        else
         EditorUtility.DisplayDialog("Objects not exported", "Make sure at least some of your selected objects have mesh filters!", "");
    }
    
    
    
    [MenuItem ("Custom/Export/Export each selected to single OBJ")]
    static void ExportEachSelectionToSingle()
    {
        if (!CreateTargetFolder())
            return;
    
        Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
        
        if (selection.Length == 0)
        {
            EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");
            return;
        }
        
        int exportedObjects = 0;
        
        
        for (int i = 0; i < selection.Length; i++)
        {
         Component[] meshfilter = selection[i].GetComponentsInChildren(typeof(MeshFilter));
        
         MeshFilter[] mf = new MeshFilter[meshfilter.Length];
        
         for (int m = 0; m < meshfilter.Length; m++)
         {
          exportedObjects++;
          mf[m] = (MeshFilter)meshfilter[m];
         }
        
         MeshesToFile(mf, targetFolder, selection[i].name + "_" + i);
        }
        
        if (exportedObjects > 0)
        {
         EditorUtility.DisplayDialog("Objects exported", "Exported " + exportedObjects + " objects", "");
        }
        else
         EditorUtility.DisplayDialog("Objects not exported", "Make sure at least some of your selected objects have mesh filters!", "");
    }
    
}

原文:http://www.unifycommunity.com/wiki/index.php?title=ObjExporter

奥迪A8l专题天气应用程序-奥迪风云(for iOS)上架

Unity越来越好,越来越火,想必都在努力的让她产生财富.最近忙了这个应用程序.有兴趣的可以下载玩玩.

应用简介:

为风云人物预报万千气象-《奥迪风云》,”奥迪风云”将奥迪的品牌魅力注入天气资讯, 带来耳目一新的使用体验.下载并安装此款应用程序, 即可纵观奥迪风云, 气象万千中, 更可享受保养车提示,洗车指数等实用功能.不仅如此, 您还可以通过奥迪风云应用程序浏览奥迪官方网站, 查询奥迪经销商信息, 查看产品的价格装备, 从而近距离感受奥迪带给您的科技与品牌魅力.
2.0版本说明:
1:修正已知Bug,完善城市添加修改功能.
2:添加整合iPad版本.

全Unity引擎开发,利用Google天气Api接口进行天气获取,XML解析.Unity不只是可以做游戏,做应用软件也是没问题的.呵呵.

视频演示:http://v.youku.com/v_show/id_XMjUzMDc5NjQ0.html

视频2:
http://player.youku.com/player.php/sid/XMjY5MzI5NjAw/v.swf

Appstore下载: http://itunes.apple.com/app/id421807014?mt=8

Unity v3.3发布!Android赶上来了.

Unity刚刚发布了3.3版本更新.距上次3.2版本更新间隔太短了.似乎不是很爽.按照这个速度再更新几次.不是又要掏银子升级了么!

Unity Android(安卓)版现在分为 基础版和专业版.
iOS和Android的Remote(远程调试)已经在免费版本中开放,所以现在你可以测试你的移动平台游戏了.
30天的专业版试用同样包含了iOS专业版和Android专业版的试用.

Android版照比预发布版的变化
Native Activity does not support screen orientation changes during runtime.
Remote refuses to connect to the Editor once the device was disconnected.
Improvement performance of audio handling (mixing) on Tegra based devices.
On-screen keyboard has been completely re-written to support NativeActivity, and handle .hideInput=true;.
Editor detects minimum OS / API version before trying to launch the application.
AndroidJavaObject et al as proper documentation.
Added documentation of the AndroidInput class.
Added correct mapping of CIRCLE button on Xperia Play; must use latest firmware on the device.
Deprecated WWW.oggVorbis property.
Remote: Fixed crash in editor caused by editor side of Android Remote.
Fixed broken detection code for Android SDK API-10 (and API-11).
Fixed problems with threading and finalizers in AndroidJNI et al.
Performance improvements of animation skinning on Tegra based devices.
Support for NativeActivity / SonyEricsson Xperia Play.
Added support for Screen.SetResolution.
Fully dynamic linkage to Mono; Mono is now available from plugins etc.
AndroidManifest.xml attribute minSdkVersion exposed under Player Settings / Other Settings.
Fixed exception when using AndroidJavaObject.Get().
Fixed occasional rendering issues on some Qualcomm based devices (e.g. HTC Vision).
Fixed various network issues (local IP, ping, HavePublicAddress etc).
Fixed various touch input related issues (Input.multiTouchEnabled, virtual touches, stale touch IDs).
Added the Windows registry keys for the JDK lookup on x64 machines.
其他改变
iPhone和Android Remote现在在Unity免费版中也可以用了.
Fixed case 392244: Incorrect handling of tall mode of Game View in Android Remote.
Fixed case 388824: Android Remote flickering.
Fixed case 388828: Android Remote crashes due to buffer overflow.
Fixed case 392869: With Build&Run only remove previous installation when update is not possible (otherwise keep PlayerPrefs etc).
Fixed case 392194: Fixed AndroidJNI lookup of inner (nested) classes.
Fixed case 392099: Touch data reset when resuming application ; fixes stale touches after pause.
Fixed case 392922: Fixed problems when using AndroidJNI and Assembly Stripping.
Fixed case 392847: Flickering rendering problem (mostly seen on GUI elements) or things not being rendered at all.
Fixed case 392831: Input.GetMouseButtonDown(0) and TouchPhase.Began being out of sync.
Fixed case 391064: Changed the message presented to Samsung users when the firmware is outdated.
Fixed case 391739: Text input is now available in NativeActivity mode.
iOS: Fixed VAO cleanup (case 392221: memory leak when using GUI.Label).
iOS: Fixed MSAA+discard support: discard read buffer, not draw; discard stencil too.
Graphics: Improved performance of fixed-function emulation under GLES2.0.
Audio: Correct audio CPU usage displayed in the Profiler.
Audio: Fixed WWW.audioClip (wait for the entire clip to download).
Fixed case 377132: Fixed rare audio bug where one shots are looping.
Fixed case 391171: Better handling of orthographic scene view camera.
Fixed case 383402: Fixed continued bouncing OS X Dock icon when using modal progress bars.
Fixed case 391471: Fixed editor error messages on Windows with some RenderTexture configurations.
Network: Fixed error when reading 32 bit network view IDs size.
Remote: Proper icons for the Android Remote.
Fixed case 388502: AnimationEvents trigger twice when the event pauses animation then starts it again from coroutine.
Fixed case 391106: Font security warnings showing up.
Fixed case 390822: Add implementation for IsDirectoryCreated on iOS.
Fixed case 388828: Various crash fixes for Android Remote.
Fixed case 373197: iPhone Remote prints excessively to the editor console.
Fixed case 388824: Unity Remote white-flickers if you reconnect it to the editor.
Fixed case 389248: Unity Remote refuses to connect to the Editor once the device was disconnected.
iOS: Xcode 4 is now recognized as proper build tool.
iOS: Added soft debugger support.

翻译中.原文http://unity3d.com/unity/whats-new/unity-3.3