Harry the Fairy will arrive on an app store near you on march 15th.
You don't have to wait to get your fairy fix though, we just released the trailer.
If you want to know more we did an interview for iFanzine.com http://ifanzine.com/interview-with-zaxis-games/
Tuesday, February 28, 2012
Wednesday, February 15, 2012
Automatically locate all unused unity assets
Did you ever work on a unity project where either you or a co-worker did not uphold complete and total order with regards to cleaning up the project folder. If you're one of those rare specimens that has never experienced a touch of kaos, don't read on!
On the other hand if you, as I, from time to time postpones the cleanup to another day, I've made a handy little editorwindow that should make the cleanup process a lot less tedious.
Basically it reads from the editor log after you have build a project, and then compares the included assets with all assets in your project. If an asset exist that is not used in the final build it is listed. It is also clickable so you can easily find it.
The unused assets are organized in 3 folders. "editor", "plugins" and "some other folder". This is helpful for me, as there is a lot in the "editor" folder that I use, but that is not used in final build.
It also lists which .dll's are included in build. If you need it, fine. If not, just delete that part.
DISCLAIMER: It does not locate unused assets in the "Ressources" folder, since everything in there should by default be included in the build. It's a tool to help locate the unused, but should be used with a bit of common sense.
[***UPDATE 2014***] By popular demand a GREATLY improved version of this tool has been released on the Unity Asset Store for 10 bucks. This old version is not stable as of Unity 4.6b20 and will not be updated
Place the following in the "editor" folder:
Here's an example: Unity Package
On the other hand if you, as I, from time to time postpones the cleanup to another day, I've made a handy little editorwindow that should make the cleanup process a lot less tedious.
Basically it reads from the editor log after you have build a project, and then compares the included assets with all assets in your project. If an asset exist that is not used in the final build it is listed. It is also clickable so you can easily find it.
The unused assets are organized in 3 folders. "editor", "plugins" and "some other folder". This is helpful for me, as there is a lot in the "editor" folder that I use, but that is not used in final build.
It also lists which .dll's are included in build. If you need it, fine. If not, just delete that part.
DISCLAIMER: It does not locate unused assets in the "Ressources" folder, since everything in there should by default be included in the build. It's a tool to help locate the unused, but should be used with a bit of common sense.
[***UPDATE 2014***] By popular demand a GREATLY improved version of this tool has been released on the Unity Asset Store for 10 bucks. This old version is not stable as of Unity 4.6b20 and will not be updated
Place the following in the "editor" folder:
using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; public class CleanUpWindow : EditorWindow { bool groupEnabled = false; List<string> usedAssets = new List<string>(); List<string> includedDependencies = new List<string>(); private Vector2 scrollPos; private List<Object> unUsed; private Dictionary<string, List<Object>> unUsedArranged; private bool needToBuild = false; // Add menu named "CleanUpWindow" to the Window menu [MenuItem("Window/CleanUpWindow")] static void Init() { // Get existing open window or if none, make a new one: CleanUpWindow window = (CleanUpWindow)EditorWindow.GetWindow(typeof(CleanUpWindow)); window.Show(); } void OnGUI() { if (needToBuild) { GUI.color = Color.red; GUILayout.Label("Are you sure you remembered to build project? Because you really need to...", EditorStyles.boldLabel); } GUI.color = Color.white; if (GUILayout.Button("Load EditorLog")) { loadEditorLog(); } if(!needToBuild) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginVertical(); if (groupEnabled) { GUILayout.Label("DEPENDENCIES"); for (int i = 0; i < includedDependencies.Count; i++) { EditorGUILayout.LabelField(i.ToString(), includedDependencies[i]); } } EditorGUILayout.EndVertical(); scrollPos = EditorGUILayout.BeginScrollView(scrollPos); EditorGUILayout.BeginVertical(); if (groupEnabled) { if (unUsedArranged != null) { foreach (KeyValuePair<string, List<Object>> objList in unUsedArranged) { if (objList.Value.Count >= 1) { GUILayout.Label(objList.Key.ToUpper()); for (int i = 0; i < objList.Value.Count; i++) { EditorGUILayout.ObjectField(objList.Value[i], typeof(Object), false); } } } } } EditorGUILayout.EndVertical(); EditorGUILayout.EndScrollView(); EditorGUILayout.EndHorizontal(); } } private void loadEditorLog() { UsedAssets.GetLists(ref usedAssets, ref includedDependencies); if (usedAssets.Count == 0) { needToBuild = true; } else { compareAssetList(UsedAssets.GetAllAssets()); groupEnabled = true; needToBuild = false; } } private void compareAssetList(string[] assetList) { unUsed = new List<Object>(); unUsedArranged = new Dictionary<string, List<Object>>(); unUsedArranged.Add("plugins", new List<Object>()); unUsedArranged.Add("editor", new List<Object>()); unUsedArranged.Add("some other folder", new List<Object>()); for (int i = 0; i < assetList.Length; i++) { if(!usedAssets.Contains(assetList[i])) { Object objToFind = AssetDatabase.LoadAssetAtPath(assetList[i], typeof(Object)); unUsed.Add(objToFind); if (objToFind != null) { unUsedArranged[getArrangedPos(objToFind)].Add(objToFind); } } } } private string getArrangedPos(Object value) { string path = AssetDatabase.GetAssetPath(value).ToLower(); if (path.Contains("/plugins/")) { return "plugins"; } else if (path.Contains("/editor/")) { return "editor"; } else { return "some other folder"; } } }You,ll need this too:
using UnityEngine; using UnityEditor; using System; using System.IO; using System.Collections; using System.Collections.Generic; public class UsedAssets { public static string[] GetAllAssets() { string[] tmpAssets1 = Directory.GetFiles(Application.dataPath, "*.*", SearchOption.AllDirectories); string[] tmpAssets2 = Array.FindAll(tmpAssets1, name => !name.EndsWith(".meta")); string[] allAssets; allAssets = Array.FindAll(tmpAssets2, name => !name.EndsWith(".unity")); for (int i = 0; i < allAssets.Length; i++) { allAssets[i] = allAssets[i].Substring(allAssets[i].IndexOf("/Assets") + 1); allAssets[i] = allAssets[i].Replace(@"\", "/"); } return allAssets; } public static void GetLists(ref List<string> assetResult, ref List<string> dependencyResult) { assetResult.Clear(); dependencyResult.Clear(); string LocalAppData = string.Empty; string UnityEditorLogfile = string.Empty; if (Application.platform == RuntimePlatform.WindowsEditor) { LocalAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); UnityEditorLogfile = LocalAppData + "\\Unity\\Editor\\Editor.log"; } else if (Application.platform == RuntimePlatform.OSXEditor) { LocalAppData = Environment.GetFolderPath(Environment.SpecialFolder.Personal); UnityEditorLogfile = LocalAppData + "/Library/Logs/Unity/Editor.log"; } try { // Have to use FileStream to get around sharing violations! FileStream FS = new FileStream(UnityEditorLogfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); StreamReader SR = new StreamReader(FS); string line; while (!SR.EndOfStream && !(line = SR.ReadLine()).Contains("Mono dependencies included in the build")); while (!SR.EndOfStream && (line = SR.ReadLine()) != "") { dependencyResult.Add(line); } while (!SR.EndOfStream && !(line = SR.ReadLine()).Contains("Used Assets,")); while (!SR.EndOfStream && (line = SR.ReadLine()) != "") { line = line.Substring(line.IndexOf("% ") + 2); assetResult.Add(line); } } catch (Exception E) { Debug.LogError("Error: " + E); } } }Note that script files might not be shown as unused since the unity build includes then.
Here's an example: Unity Package
Wednesday, February 8, 2012
Evolution of a fairy!
When we started development of “Harry
The Fairy”, the game was called “You Got Snail” - yeah what a
title, right.
The first ideas of the game was to make
rather complicated puzzle game with a snail.
The idea was that the snail could
swallow objects and take on the objects abilities, or spit the object
out and make them stick together.
What we hadn't figured out, when
designing the game, was the controls. We were pretty new at designing
games for handheld devices, we had only done one title before Angry
Viking, which was a joystick and button game.
Our controls were way to complicated to
implement on iPhone, and when we had a working prototype, no one
could figure out how to play the game.
So we went back, way back, and started
with the basic design. Move controls, making the snail fly gave us a
lot of freedom. We could use the phones accelerometer to control the
snail, so when you tilt the device the snail moves in the direction
you tilt.
This proved to work great. We still
wanted the snail to be able to pick up objects and interact with the
environment.
But after playing the game with only
the move control touching the screen to pickup objects seamed some
how unnatural. It was more fun to push things around.
So we kept what worked and killed what
didn't, the snail.
The reason for having a snail as
protagonist were gone, so we changed setting and hero.
Introducing Harry The Fairy.
Harry is a small forrest fairy, his
friends gets kidnapped by some evil machines and dragged under ground.
Harry went through several passes,
from a simple ball with wings, through a real hero with a hat, till
the final Harry, a happy slightly scared green fairy with butterfly
wings.
It was important for us to keep Harry a
bit nervous - he is travelling the some pretty scary caves.
First we removed the small wings to
give him more room to move. But it was weird to see a green "ball" fly
around, and the character didn't really make any sense, so we gave
him big butterfly wings. The butterfly wings help Harry stand out
from the surrounding environment, and give him a nice silhouette you
can recognize even when he is scaled way down.
Harry uses his wand to free his friends
from the cages they are trapped in at the end of each level
So how does Harry interact with the
environment?
The first element we added was the
Barrel and the Breakable Door.
The hero can push the barrel around, if
the barrel hits a breakable door the weight of the barrel forces the
door open.
This gives way to the first few
puzzles, really simple once.
Find barrel push on to door, escape and
save friends.
To add even more complexity to the
puzzles we added the Hatch.
The hatch works like a door, you can
push it from underneath. This way we close off certain parts of the
level.
The hatch can also be used to guide the
barrels towards a breakable door.
We now added the first real enemy, the
Drill. The
drill can destroy barrels.
That's all for now, the next post will go even deeper into these game elements and tell how we used them to create puzzles.
And show more elements of the game.
Thanks for reading.
/Bo
Saturday, February 4, 2012
Batch replace gameobjects in Unity
When creating Harry the Fairy, we often found ourselves having to replace hundreds of prefab instances so I created this little script.
It replaces a number of gameobjects with another and gives you the possibility to save all the transform values i.e. position, rotation and scale.
C# Script must be placed in "editor" folder.
Here's a visual walkthrough:
Go into Custom ->Replace Gameobjects
Select any number of gameobjects and drag them into "Old Objects".
Then, from the project pane, drag the gameobject that you want to replace with into "New Type".
Press "Replace"
Enjoy :)
/Kristian
And credits to Michael L. Croswell
C# Script must be placed in "editor" folder.
using UnityEngine; using UnityEditor; using System.Collections; public class ReplaceGameObjects : ScriptableWizard { public bool copyValues = true; public GameObject NewType; public GameObject[] OldObjects; [MenuItem("Custom/Replace GameObjects")] static void CreateWizard() { ScriptableWizard.DisplayWizard("Replace GameObjects", typeof(ReplaceGameObjects), "Replace"); } void OnWizardCreate() { foreach (GameObject go in OldObjects) { GameObject newObject; newObject = (GameObject)EditorUtility.InstantiatePrefab(NewType); newObject.transform.position = go.transform.position; newObject.transform.rotation = go.transform.rotation; newObject.transform.parent = go.transform.parent; DestroyImmediate(go); } } }
Here's a visual walkthrough:
Go into Custom ->Replace Gameobjects
Select any number of gameobjects and drag them into "Old Objects".
Then, from the project pane, drag the gameobject that you want to replace with into "New Type".
Press "Replace"
Enjoy :)
/Kristian
And credits to Michael L. Croswell
Subscribe to:
Posts (Atom)