Placing a chat bubble above a character's head in a 3d environment

Okay, in my case that's not actually what I need, but it's similar so i've phrased the question that way since others are more likely to being doing chat bubbles. In my case I want to create an animated speech bubble for a sound effect. An example of exactly the kind of thing i'm trying to create can be found here.

Reading around, it seems I have two options: Either use guiTextures (or guiText if I was doing labels, in which case Eric has already done the work) and use camera.WorldToViewportPoint() to position it relative to an object in the scene. Or use onGUI() to create a GUI.Box and position it using camera.WorldToScreenPoint().

I'm keen on the first method because i've been using guiTextures throughout my project and I think this will be easier to create an animated effect like the video. However, in practice i've found it to be difficult to align the speech bubble with the object correctly since the bubble moves around as the player moves. It's important that the 'tail' of the bubble points to the object consistently. Also a duplicate bubble seems to show when you are looking directly away from the object?

As for the onGUI method, i'm not that comfortable with the onGUI stuff yet. I've found quite a few posts on the forums with similar methods but i'm still getting my head around the basics.

If there's a better way to implement this i'd be glad to hear it, or if someone could explain how to set up the guiTexture correctly.

Many thanks.

After playing around with a billboarded guiTexture a bit more I decided that it wasn't really the effect I was going for. While I need my bubble to always face the camera if in view, I think really the bubble has to exist in the world if it's going to remain as fixed to an object as i'd like.

So I made a simple plane in 3ds Max and set the pivot point to the lower left corner to help avoid the rotation problems I had with the guiTexture. Then I rewrote Neil Carter's 'LookAtCameraYOnly' script from the wiki in Javascript, which I used to make the plane always rotate to face the camera:

var m_camera : Camera;

function Update () {

    var v : Vector3 = m_camera.transform.position - transform.position;
    v.x = 0.0;
    v.z = 0.0;
    transform.LookAt(m_camera.transform.position - v);  

After that it was a simply matter of copy n' pasting parts of my other two visual systems (HUD animations and captions) to call the relevant functions to play sounds, show the animation, and hide it if the player moves out of range. My finished function for the bubble animation looks like this:

function showAnimated () {
// This function is responsible for showing the animated graphic for the audio

        // store a reference to the array of textures on the billboard object
        var texCycle = billboardObj.GetComponent(guiTextureSetup).myTextures;

        var waitTime = 1.0/framesPerSecond;
        for (i = 0; i < texCycle.Length; i++) {
            billboardObj.renderer.material.mainTexture = texCycle*;*
 *billboardObj.renderer.enabled = true;*
 *yield WaitForSeconds(waitTime);*
 *billboardObj.renderer.enabled = false;*
*// these lines control the billboarding of the animated object,*
*// turning it to face the selected camera*
 *var v : Vector3 = m_camera.transform.position - transform.position;*
 *v.x = 0.0;*
 *v.z = 0.0;*
 *billboardObj.transform.LookAt(m_camera.transform.position - v);*

For the duplicate bubble it sounds like you are still drawing the bubble even when the object is offscreen.

The documentation doesnt say anything about this but you may want to check the Z value returned from WorldToViewport and WorldToScreen. I'd expect if the Z was negative then the object is behind the camera and not in front. In which case, you don not want to draw the bubble.