Some magical points about the AssetDatabase and using LoadAssetFromPath():

  • AssetDatabase is ONLY for loading files in the editor.
  • For loading files when your program is running, use Resource.Load() or AssetBundles.
  • Your path must look like Asset/Subdirectory/filename.extension.
  • Path does not include leading forward slash.
  • Use only forward slashes for directory separation.
  • All paths are relative to your project directory. Don’t include C:/ etc.
  • Remember to include the correct extension.
  • If your script isn’t picking up newly-created assets, call AssetDatabase.Refresh();

Random numbers are at the core of many gameplay mechanics. The amount of damage a character does when attacking is often random in RPGs. However often as a designer you want to make numbers in the middle of you range come up more often than numbers at the extreme ends. The way numbers come up is called the probability distribution.

You can use an AnimationCurve to define the probability distribution, by treating it as a cumulative probability distribution.

Anyway, here’s a simple way of using it in Unity.

using UnityEngine;
using System.Collections;

public class ProbabilisticDamage : MonoBehaviour {
    public AnimationCurve distribution;
    public float maxDamage;
    public float minDamage;

    public float randomDamage {
        get {
            // Get a random number between 0 and 1
            float x = Random.value;

            // Find that value on your distribution curve
            float y = distribution.Evaluate(x);

            // Scale it to be between your max and min
            return minDamage + (y * (maxDamage - minDamage));
        }
    }
}

What do you think? Is this useful?

So you have a prefab with some lights attached to it. You’re creating it in two different scenes and for some reason the lighting is different. You’ve checked everything and you’re tearing your hair out. Try the following checklist.

  • Take a screenshot of each scene, check with the eyedropper tool to make sure you’re not imagining things.
  • Check you don’t have any extra lights in each scene. Duh.
  • If you do have other lights, check their distances, culling masks, disable them temporarily and check again.
  • Check the render settings of the scene. Ambient lighting is a per-scene setting and needs to be the same between scenes for your lighting to look the same. Also check fog.
  • Check the global (lossy) scale of your lighting setup. If its a child of something with a non-1,1,1 scale, the lighting will look different. Lights don’t scale with scale.

That should cover it. Good luck, princesses and princes of lightingland.

Using vertex colors to change a model’s appearance is well documented in other tutorials, but often debugging them can be a pain. Here’s a very short script and shader that let you play with the appearance of your mesh in real time, changing the color of individual vertices. Make sure to create a material and assign the shader to it, and then assign the material to your mesh.

VertexColorTester.cs

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class VertexColorTester : MonoBehaviour {
    Mesh mesh;

    public Color[] colors;

    void Awake() {
        mesh = GetComponent().mesh;
        colors = mesh.colors;
    }

    void Update() {
        mesh.colors = colors;
    }
}

VertexColorUnlit.shader

Shader "Custom/Vertex Color Unlit" {
    Properties {
    }
    SubShader {
        Pass {
      Lighting Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            struct vertexInput {
                half4 vertex : POSITION;
                half4 color : COLOR;
            };

            struct vertexOutput{
                half4 pos : SV_POSITION;
                half4 color : COLOR;
            };
            
            vertexOutput vert(vertexInput input) {
                vertexOutput output;

        output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
        output.color = input.color;

                return output;
            }
            
            float4 frag(vertexOutput input) : COLOR {
                return input.color;
            }
            
            ENDCG
        }
    }
}

There’s a great in-depth article on motion planning for games posted on Gamasutra today. It goes into depth on various algorithms from A* to Flow Fields and beyond.

Unity is pretty stable these days, but there are two things that have been causing crashes for me recently.

The first is obvious and entirely my fault – infinite loops. If Unity is crashing when you run your game, the most likely cause is an infinite loop somewhere. Step through your code with the debugger to find what’s causing it.

The second was new to me recently. Some of my prefabs had somehow become corrupt and were causing Unity to crash. Trying to load them with Resources.Load caused Unity to crash. It’s possible to tell if any prefabs are corrupt by trying to drag them into a scene. If the usual shortcut cursor doesn’t appear when dragging your prefab into the scene, your prefab is corrupt, and you’ll have to recreate them from scratch.

Sometimes printing the name of a GameObject isn’t enough to identify it for debugging. Here’s a snippet to print out the full path of a GameObject in the scene.

public static class Extensions {
    public static string GetPath(this GameObject go) {
        List path = new List();

        Transform current = go.transform;
        path.Add(current.name);

        while (current.parent != null) {
            path.Insert(0, current.parent.name);
            current = current.parent;
        }

        return string.Join("/", path.ToArray());
    }
}

It’s a slow day, so here’s an editor-specific tip. If you use Vim, Snipmate can save you a lot of time. Type in the keyword and hit tab for it to expand out.

snippet find
    GameObject.Find("${1}")${2}
snippet gc
    GetComponent()
snippet ac
    AddComponent()
snippet sar
    SetActiveRecursively(${1:true})
snippet rc
    [RequireComponent (typeof(${1:AudioSource}))]
snippet ee
    [ExecuteInEditMode]
snippet log
    Debug.Log("${1:msg}");
snippet warn
    Debug.LogWarning("${1:msg}");
snippet err
    Debug.LogError("${1:msg}");
snippet inst
    (${2:GameObject}) GameObject.Instantiate(${1:thing}, Vector3.zero, Quaternion.identity);
snippet go
    GameObject ${1:go} = new GameObject(${2:name});
snippet s2i
    Convert.ToInt32(${1:string})
snippet s2f
    float.Parse(${1:string}, CultureInfo.InvariantCulture.NumberFormat)
snippet load
    (${2:GameObject}) Resources.Load("${1:path}")
snippet wait
    yield return new WaitForSeconds(${1:time})
snippet sm
    SendMessage("${1:message}", ${2:null}, ${3:SendMessageOptions.DontRequireReceiver})
snippet forl
    foreach (${1:int} ${2:var} in ${3:list}) {
        ${4}
    }
snippet ford
    foreach (KeyValuePair pair in ${3:dict}) {
        ${4}
    }
snippet list
    List ${2:var} = new List();
snippet dict
    Dictionary ${3:var} = new Dictionary();
snippet sort
    filtered.Sort(
        delegate(${1:int} a, $1 b) {
            return a.CompareTo(b);
        }
    );
snippet tryget
    ${1:int} ${2:value};
    if (${3:dict}.TryGetValue("${4:key}", out $2)) {
        ${5}
    }

By default Resources.Load() returns null when it cannot find the resource. This can be frustrating as not finding a resource usually means you have a typo somewhere, so dying early is usually the best plan.

The following snippet allows you to die on not finding the resource (assuming you have Error Pause selected).

static class Helper {
    public static T Load<T>(string path) where T : Object {
        T thing = (T) Resources.Load(path);
        if (thing == null)
            Debug.LogError("Couldn't load resource '"+typeof(T)+"' with path '"+path+"'");
        return thing;
    }
}

Example Usage:

GameObject itemPrefab = Helper.Load<GameObject>("Prefabs/MenuItem");

If you have a nicer version of this, post it in the comments!

If you are seeing pink-coloured objects when building release versions of your project, it might be because of this:

When building a player, a shader will only be included if it is assigned to a material that is used in any scene or if the shader is placed in a “Resources” folder. See Also: Material class.

From the Shader.Find() documentation page

If you’re setting up shaders through scripts, it’s possible that those shaders are not directly used in any scenes. In that case, make sure that the .shader file itself is underneath Resources. Even if you’re loading it through Shader.Find()