3D Text Wrap

Has anyone wrapped text of a 3DText object? would be nice to say limit the width, and have the rest auto-resize.

There isn’t any obvious way to do this automatically. The TextMesh class doesn’t have a method for calculating the width of the string or individual characters, so it is difficult to know where the line breaks should go.

Is there a solid text wrapping solution?

If you mean a plug-in or library, then I’m not aware of one, but you could try the Unify wiki (I wouldn’t get your hopes up, though).

This might not be the best solution, but it worked for me. Maybe someone will find it useful.

I started off with a GUITExt wrapping script, I found somewhere on this forum and then made some adjustments to make it work with my 3D text object.

Simply drag and drop it onto your 3D text object (don’t forget to link textObject with your TextMesh) and it should work. For fine tuning, simply alter the maxLineChars integer.

public var textObject : TextMesh;

private var maxLineChars : int = 35; //maximum number of characters per line...experiment with different values to make it work


private var words : String[]; 
var result = ""; 
private var charCount : int;

function Start () {
	updateText();	//call this function to format your string.
}
 
function updateText () { 
   FormatString(textObject.text); 
}

function FormatString ( text : String ) { 

	currentLine = 1;
	charCount = 0;
	words = text.Split(" "[0]); //Split the string into seperate words 
	result = ""; 

	for (var index = 0; index < words.length; index++) { 

   		var word = words[index].Trim(); 
    
   		if (index == 0) { 
        	result = words[0]; 
        	textObject.text = result; 
   		} 

   		if (index > 0 ) { 
			charCount += word.Length + 1; //+1, because we assume, that there will be a space after every word
			if (charCount <= maxLineChars) {
         		result += " " + word; 
			}
			else {
				charCount = 0;
				result += "\n " + word; 
			}
         	

      		textObject.text = result; 
   		} 
	} 
}

I was down the road of rendering GUI.Labels into textures … it was… mm … not easy.

this is just great, simple efficient.

Thank you !!!

:smile:

I just add a space at the very beginning of the result so the first word is perfectly left aligned with the others:

textObject.text = " "+result;

Glad you found it helpful.

I was pretty amazed myself, that it actually wasn’t that complicated :slight_smile:

Here is a version that is running in the editor.
You can design your layouts without running the game to check your text.

Remove the Update() for the final build or once your layouts are designed - It is only used to refresh your changes made with MaxLineChars.

I’ve added MinLineChars - a very simple limiter to avoid abusive generation of return carriage. otherwise, I did not find a quick and nice way to remove the " " at the beginning of each lines following the first one. So I’ve put a quick hack which adds a " " at the beginning of the first line. That way they are all aligned.

@script ExecuteInEditMode()

public var textObject : TextMesh;

public var maxLineChars : int = 35; //maximum number of characters per line...experiment with different values to make it work
public var minLineChars : int = 10;//a limiter to avoid abusive use of return carriage

private var words : String[];
var result = "";
private var charCount : int;

function Start () {
   updateText();   //call this function to format your string.
}

function Update() {
	FormatString(textObject.text);
}

function updateText () {
   FormatString(textObject.text);
}

function FormatString ( text : String ) {

	currentLine = 1;
	charCount = 0;
	words = text.Split(" "[0]); //Split the string into seperate words
	result = "";

	if (maxLineChars< minLineChars) maxLineChars = minLineChars;
	
	for (var index = 0; index < words.length; index++) {

		var word = words[index].Trim();
   
		if (index == 0) {	
           result = words[0];
           textObject.text = result;
		}

		if (index > 0 ) {
         	charCount += word.Length + 1; //+1, because we assume, that there will be a space after every word
         	if (charCount <= maxLineChars) {
				result +=" "+ word;
         	}
         	else {
            	charCount = 0;
				result += "\n "+word;
         	}
		}
	}
	if (result[0]!=" ") result = " "+result;
    textObject.text = result;
}

@friendlydeveloper: Thanks again for posting this code in the first place

A text wrap function that also takes other separators into account and gets rid of leading or trailing spaces where needed.

This could be done a bit faster if the program would jump to the max line end and search back from there for a separator.

function WrapTxt(text, width) : String {
	var e=text.length;
	var i=0;
	var lineBegin=0;
	var lineLength=0;
	var prevSeparatorPos=0;
	var wrappedText="";
	var separators=" ;:\n\t,.-()@#?";
	var cutOffSeparators=" \n\t";
	var cutOffSeparator=false;
	while(i<e) {
		var c = text.Substring(i,1);
		i++;
		lineLength++;
		if(separators.IndexOf(c)>=0) {
			prevSeparatorPos=i;
			if(cutOffSeparators.IndexOf(c)>=0) cutOffSeparator=true;
			else cutOffSeparator=false;
		}
		if(lineLength>width) {
			if(prevSeparatorPos<=lineBegin) prevSeparatorPos=i-1;  // no separator found on entire line
			if(wrappedText.length>0) wrappedText+="\n";
			if(cutOffSeparator) wrappedText+=text.Substring(lineBegin,prevSeparatorPos-lineBegin-1);
			else wrappedText+=text.Substring(lineBegin,prevSeparatorPos-lineBegin);
			i=prevSeparatorPos;
			lineBegin=i;
			lineLength=0;
			cutOffSeparator=false;
		}
	}
	if(lineBegin<i-1) {
		if(prevSeparatorPos<=lineBegin) prevSeparatorPos=i;  // no separator found on entire line
		if(wrappedText.length>0) wrappedText+="\n";
		wrappedText+=text.Substring(lineBegin,i-lineBegin);
	}
	return wrappedText;
}

Here’s a very simple way to wrap text:

var myText : String;
var lineLength : int;

for ( var i : int = lineLength; i < myText.length; i += lineLength ) {
var returnSpot : int =  myText.IndexOf( " " , i );
myText = myText.Substring( 0, returnSpot ) + "\n" + myText.Substring( returnSpot, myText.length-returnSpot );

Hey,
here is my Word Wrapping, maybe you guys have good ideas for the //OVERFLOW parts, the is the only thing that sucks

    // Methode to do LineWrapping 
    private string formatString(string s){

        GUIContent content = new GUIContent();
        string result = "";
        float fontSize = 0;
        // We have 23 lines
        string[] lines = {"","","","","","","","","","","","","","","","","","","","","","",""};
        int line = 0;
        int lineIndex = 0;
        
        // Replace all \n by ÂŽ, cause this is only 1 char 
        s = s.Replace("\n","ÂŽ");

        for (int index = 0; index < s.Length; index++){

            // if the line is at the end
            if (fontSize >= 1){
                int count = 0;
                
                // if we need to wrap the word
                while (!s[index].ToString().Equals(" ")){

                    lineIndex -= 1;
                    index -= 1;
                    count += 1;

                    // OVERFLOW
                    if (lineIndex == 0){
                        return "\n\n\nOverflow";
                    }
                }

                // delete all chars from the line above
                if ( lineIndex < lines[line].Length ){
                    lines[line] = lines[line].Remove(lineIndex,count);  
                } 

                // new line
                lines[line] += "\n ";
                line += 1;
                lineIndex = 0;
            }

            // new line
            if ( s[index].ToString().Equals("ÂŽ") ){
                lines[line] += "\n";
                line += 1;
                lineIndex = -1;
            }
            lineIndex += 1;

            // the other chars
            if (!s[index].ToString().Equals("ÂŽ")){
                lines[line] += s[index];
            }

            // OVERFLOW
            if (line >= 21){
                return "\n\n\nOverflow";
            }

            // get the size from the text 
            content.text = lines[line];
            fontSize = WbPaletteSystem.instance.textFieldStyle.CalcSize(content).x / 195;
        }
        
        for (int i = 0; i < 23; i++){
            result += lines[i];
        }
        return result;
    }

no one interested !? I like this way, i just have 2 problems,…

Your solution is excellent but has a couple of issues. You should use LastIndexOf if you want to be certain to keep the text less than the lineLength. Also, in C#, you need to check for a negative return value. Finally, set i to returnSpot so that the next check is exactly a lineLength past then when reverse searching for the next " ". Note, this doesn’t address all problems but is pretty nice. Here’s a C# version:

for (var i=lineLength; i < text.Length; i += lineLength) {
int returnSpot = text.LastIndexOf(" " , i);
if (returnSpot >= 0){
text = text.Substring(0, returnSpot) + “\n” + text.Substring(returnSpot, text.Length-returnSpot);
i = returnSpot;
}
}

Line length adjustable in editor:

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class WrapText : MonoBehaviour
{
	public TextMesh textMesh;

	public int maxLineChars = 35;
	private int lastMaxLineChars = 35;

	string wrappedText = "";
	public bool disableWhilePlaying = true;

	void Awake()
	{
		bool shouldDisable = disableWhilePlaying  !(Application.isEditor  !Application.isPlaying);
		this.enabled = !shouldDisable;
	}

	void Update()
	{
		if(textMesh.text != wrappedText || maxLineChars != lastMaxLineChars)
		{
			int charCount = 0;
			wrappedText = "";
			string line = "";

			char[] separators = new char[]{' ', '\n', '\t'};
			string[] words = textMesh.text.Split(separators);

			for(int i = 0; i < words.Length; i++) 
			{
				string word = words[i].Trim();

				if(i == 0)
				{
					line = word;
					charCount = word.Length;
				}
				else
				{
					if((charCount + (charCount > 0 ? 1 : 0) + word.Length) <= maxLineChars)
					{
						if(charCount > 0)
						{
							line += ' ';
							charCount += 1;
						}

						line += word;
						charCount += word.Length;
					}
					else
					{
						if(wrappedText.Length > 0)
							wrappedText += '\n';

						wrappedText += line;

						line = word;
						charCount = word.Length;
					}
				}
			}

			if(charCount > 0)
			{
				if(wrappedText.Length > 0)
					wrappedText += '\n';

				wrappedText += line;
			}

			textMesh.text = wrappedText;
			lastMaxLineChars = maxLineChars;
		}
	}
}

Based of Al Bundy’s script I was able to make a version based off of the principle that TextMesh.renderer.bounds.extents.x*2.0f appears to give the correct width of the TextMesh.

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(TextMesh))]
[ExecuteInEditMode]
public class TextMeshController : MonoBehaviour
{
#region public members.
	public float				m_maxWidth				= 0.0f;
	public bool					m_disableWhilePlaying	= true;
#endregion
	
#region private members.
	private TextMesh			m_textMesh				= null;
	private float				m_lastMaxWidth			= 0.0f;
	private string				m_wrappedText			= "";
#endregion
	
#region getters/setters.
	public float TextWidth
	{
		get{ return m_textMesh.renderer.bounds.extents.x*2.0f; }
	}
	public float TextHeight
	{
		get{ return m_textMesh.renderer.bounds.extents.y*2.0f; }
	}
	public float MaxWidth
	{
		get{ return m_maxWidth; }
	}
#endregion

#region monobehavior methods.
	public void Awake()
	{
		m_textMesh = GetComponent<TextMesh>();
		
		bool shouldDisable = m_disableWhilePlaying  !(Application.isEditor  !Application.isPlaying);
		this.enabled = !shouldDisable;
	}
	
	public void OnDrawGizmos()
	{
		Gizmos.color = Color.blue;
		Gizmos.DrawRay( GetInitPosition() + transform.up*0.05f, transform.right * TextWidth );
		Gizmos.color = Color.red;
		Gizmos.DrawRay( GetInitPosition(), transform.right * MaxWidth );
	}

	public void Update()
	{
		if( m_textMesh.text != m_wrappedText || MaxWidth != m_lastMaxWidth )
		{
			float widthSum = 0.0f;
			m_wrappedText = "";
			string line = "";
			
			char[] separators = new char[]{' ', '\n', '\t'};
			string[] words = m_textMesh.text.Split(separators);
			
			for(int i = 0; i < words.Length; i++) 
			{
				string word = words[i].Trim();
				
				if(i == 0)
				{
					line = word;
					widthSum = GetWordWidth( word );
				}
				else
				{
					// Concatenate the new word if there is still enough space.
					if( widthSum + GetWordWidth( word ) <= MaxWidth )
					{
						if( widthSum > 0.0f )
						{
							line += ' ';
							widthSum += GetSpaceWidth();
						}
						
						line += word;
						widthSum += GetWordWidth( word );
					}
					// New line.
					else
					{
						if( m_wrappedText.Length > 0 )
							m_wrappedText += '\n';
						
						m_wrappedText += line;
						
						line = word;
						widthSum = GetWordWidth( word );
					}
				}
			}
			
			if( widthSum > 0.0f )
			{
				if( m_wrappedText.Length > 0 )
					m_wrappedText += '\n';
				
				m_wrappedText += line;
			}
			
			m_textMesh.text = m_wrappedText;
			m_lastMaxWidth = MaxWidth;
		}
	}
#endregion
	
#region private methods.
	private float GetSpaceWidth()
	{
		m_textMesh.text = "x x";
		float totalWidth = m_textMesh.renderer.bounds.extents.x * 2.0f;
		totalWidth -= GetWordWidth( "xx" );
		return totalWidth;
	}
	
	private float GetWordWidth( string word )
	{
		m_textMesh.text = word;
		return m_textMesh.renderer.bounds.extents.x * 2.0f;
	}
	
	private Vector3 GetInitPosition()
	{
		// Find X.
		float x = 0.0f;
		switch( m_textMesh.anchor )
		{
		case TextAnchor.LowerLeft:
		case TextAnchor.MiddleLeft:
		case TextAnchor.UpperLeft:
			x = transform.position.x;
			break;
		case TextAnchor.LowerRight:
		case TextAnchor.MiddleRight:
		case TextAnchor.UpperRight:
			x = transform.position.x - TextWidth;
			break;
		case TextAnchor.LowerCenter:
		case TextAnchor.MiddleCenter:
		case TextAnchor.UpperCenter:
			x = transform.position.x - TextWidth / 2.0f;
			break;
		}
		
		// Find Y.
		float y = 0.0f;
		switch( m_textMesh.anchor )
		{
		case TextAnchor.LowerLeft:
		case TextAnchor.LowerRight:
		case TextAnchor.LowerCenter:
			y = transform.position.y - TextHeight / 2.0f;
			break;
		case TextAnchor.MiddleRight:
		case TextAnchor.MiddleLeft:
		case TextAnchor.MiddleCenter:
			y = transform.position.y + TextHeight / 2.0f;
			break;
		case TextAnchor.UpperLeft:
		case TextAnchor.UpperRight:
		case TextAnchor.UpperCenter:
			y = transform.position.y;
			break;
		}
		return new Vector3( x, y, transform.position.z );
	}
#endregion
}

This way you can modify the m_maxWidth value in the editor and use the Gizmos to exactly calculate which max width you want for your TextMesh.

… I just hope this hacky solution works on mobile and Unity Engineers don’t change how renderer.bounds.extents works :slight_smile:

I’d like to propose my solution. This is a quick and rough implementation for TextMesh objects and can be set to run on start or dynamically by applying the component to the object and then calling the Wrap() function. The differences in my implementation are that I’m using actual kerning data to determine width, rather than plain character count.

using UnityEngine;

public class WrapTextMesh : MonoBehaviour
{
    public bool WrapOnStart;
    public float WrapWidth;

    public void Wrap(float MaxWidth)
    {
        TextMesh tm = GetComponent<TextMesh>();
        if (tm == null)
        {
            Debug.LogError("TextMesh component not found.");
            return;
        }

        Font f = tm.font;
        string str = tm.text;
        int nLastWordInd = 0;
        int nIter = 0;
        float fCurWidth = 0.0f;
        while (nIter < str.Length)
        {
            // get char info
            char c = str[nIter];
            CharacterInfo charInfo;
            if (!f.GetCharacterInfo(c, out charInfo))
            {
                Debug.LogError("Unrecognized character encountered (" + (int) c + "): " + c);
                return;
            }

            if (c == ' ')
            {
                nLastWordInd = nIter; // replace this character with '/n' if breaking here
            }

            fCurWidth += charInfo.width;

            if (fCurWidth >= MaxWidth)
            {
                str = str.Remove(nLastWordInd, 1);
                str = str.Insert(nLastWordInd, "\n");
                fCurWidth = 0.0f;
            }

            ++nIter;
        }

        tm.text = str;
    }

    // Use this for initialization
    void Start()
    {
        if (WrapOnStart)
            Wrap(WrapWidth);
    }
}

Just a few notes:

  • This doesn’t work with “Dynamic” fonts. I tested this only on Uniform, but I imagine it works on other non-dynamic forms just as well.
  • Also, I’m not entirely sure what the number you’d use to determine width by actually translates to in scale. I just threw this together because I couldn’t find anything that was accurate enough, and I was just inspired to do it. I think it’s in pixels, but in the scale of the font. So if you upsample it a lot, like I normally do, your width wrapping numbers would be rather high as well.
  • Lastly, you can probably make an editor version of this as well, but my concern is that I can’t really discern between manual linebreaks and wrapping linebreaks, so I just let it run the one time after I assign the text and leave it at that.

Really like you version with the ability to set an actual width (and see it live in the editor). Works like a charm for me so far.

Thanks rrsimon, this is excellent! :slight_smile:

Line 39 → Missing logical operators

I modified the rrsimon’s code to ‘perfect’ what happens when you change the angling of the parent objects or modify the text. What you do is, attach this script to any cube, and since there is no “Font.texture” property (unfortunately), you have to put the texture on a separate object and assign that object to textObj.

direction can either be “Front”, “Right”, “Back”, “Left”, “Up” or “Down” to tell what side of the cube to put text on. offset tells how far off the cube to put the text and should be a small number. A negative value places the text inside the cube. message tells what message to put on the cube. fontName is where in the Resource folder your font name is. Do not use extensions. shaderName is where in the Resource folder your shader name is. matName is where in the Resource folder your font material’s name is. characterSize and fontSize controls the numbers in the newly created object called object_name+“_sheet”'s TextMesh. The new object makes itself a child object under the cube with the script attached. The ‘sheet’ object is what contains the text (written on the cube). MaxWidth (by default) should always be 1, (which is 1 times the size of the cube).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Writing : MonoBehaviour {

    public GameObject textObj;

    public string direction;
    public float offset = 0.001f;

    public string message;
    public string fontName = "Fonts/magnificent/Magnificent";
    public string shaderName = "Shaders/TextOneSided";
    public string matName = "Materials/Font Materials/FontMaterial";

    public float characterSize = 0.01f;
    public int fontSize = 1;

    public Color color;

    private GameObject sheetObj;

    #region public members.
    public float m_maxWidth = 1.0f;
    public bool m_disableWhilePlaying = true;
    #endregion

    #region private members.
    private TextMesh m_textMesh = null;
    private float m_lastMaxWidth = 0.0f;
    private string m_wrappedText = "";
    #endregion

    #region getters/setters.
    public float TextWidth
    {
        get {
            if (m_textMesh != null)
            {
                return m_textMesh.GetComponent<Renderer>().bounds.extents.x * 2.0f;
            } else
            {
                return -1;
            }
        }
    }
    public float TextHeight
    {
        get {
            if (m_textMesh != null)
            {
                return m_textMesh.GetComponent<Renderer>().bounds.extents.y * 2.0f;
            } else
            {
                return -1;
            }
        }
    }
    public float MaxWidth
    {
        get { return m_maxWidth * 2; }
    }
    #endregion

    #region monobehavior methods.
    public void Awake()
    {
        if (m_textMesh == null && sheetObj != null)
        {
            m_textMesh = sheetObj.GetComponent<TextMesh>();
        }
        //bool shouldDisable = m_disableWhilePlaying && !(Application.isEditor && !Application.isPlaying);
        //this.enabled = !shouldDisable;
    }

    public void OnDrawGizmos()
    {
        Gizmos.color = Color.blue;
        Gizmos.DrawRay(GetInitPosition() + transform.up * 0.05f, transform.right * TextWidth);
        Gizmos.color = Color.red;
        Gizmos.DrawRay(GetInitPosition(), transform.right * MaxWidth);
    }

    #endregion

    #region private methods.
    private float GetSpaceWidth()
    {
        float totalWidth = -1;
        if (m_textMesh != null)
        {
            string textTemp = m_textMesh.text;
            m_textMesh.text = "x x";
            totalWidth = m_textMesh.GetComponent<Renderer>().bounds.extents.x * 2.0f;
            totalWidth -= GetWordWidth("xx");
            m_textMesh.text = textTemp;
        }
        return totalWidth;
    }

    private float GetWordWidth(string word)
    {
        float totalWidth = -1;
        if (m_textMesh != null)
        {
            string textTemp = m_textMesh.text;
            m_textMesh.text = word;
            totalWidth = m_textMesh.GetComponent<Renderer>().bounds.extents.x * 2.0f;
            m_textMesh.text = textTemp;
        }
        return totalWidth;
    }

    private Vector3 GetInitPosition()
    {
        if (m_textMesh == null)
        {
            return new Vector3(-1, -1, -1);
        }

        // Find X.
        float x = 0.0f;
        switch (m_textMesh.anchor)
        {
            case TextAnchor.LowerLeft:
            case TextAnchor.MiddleLeft:
            case TextAnchor.UpperLeft:
                x = transform.position.x;
                break;
            case TextAnchor.LowerRight:
            case TextAnchor.MiddleRight:
            case TextAnchor.UpperRight:
                x = transform.position.x - TextWidth;
                break;
            case TextAnchor.LowerCenter:
            case TextAnchor.MiddleCenter:
            case TextAnchor.UpperCenter:
                x = transform.position.x - TextWidth / 2.0f;
                break;
        }

        // Find Y.
        float y = 0.0f;
        switch (m_textMesh.anchor)
        {
            case TextAnchor.LowerLeft:
            case TextAnchor.LowerRight:
            case TextAnchor.LowerCenter:
                y = transform.position.y - TextHeight / 2.0f;
                break;
            case TextAnchor.MiddleRight:
            case TextAnchor.MiddleLeft:
            case TextAnchor.MiddleCenter:
                y = transform.position.y + TextHeight / 2.0f;
                break;
            case TextAnchor.UpperLeft:
            case TextAnchor.UpperRight:
            case TextAnchor.UpperCenter:
                y = transform.position.y;
                break;
        }

        GameObject g = new GameObject();
        g.transform.position = new Vector3(x, y, transform.position.z);
        g.transform.eulerAngles = transform.eulerAngles;
        g.transform.Translate(transform.localScale.x * -0.5f, 0, transform.localScale.z * 0.5f);

        Vector3 pos = g.transform.position;

        Destroy(g);

        return pos;
    }
    #endregion

    // Update is called once per frame
    void Update () {

        Vector3 rotation = transform.eulerAngles;

        transform.eulerAngles = new Vector3(0, 0, 0);

        if (m_textMesh == null && sheetObj != null)
        {
            m_textMesh = sheetObj.GetComponent<TextMesh>();
        }

        GameObject obj = null;

        int cnt = 0;

        foreach (Transform child in transform)
        {
            cnt++;
        }

        if (cnt == 0)
        {
            obj = new GameObject();
            obj.transform.parent = transform;

            obj.name = obj.transform.parent.name + "_writing";

            obj.AddComponent<MeshRenderer>();

            TextMesh objMesh = obj.AddComponent<TextMesh>();

            sheetObj = obj;
        }

        if (cnt != 0 && sheetObj == null)
        {
            sheetObj = transform.Find(name+"_writing").gameObject;
        }

        if (direction == "Front")
        {
            if (obj != null)
            {
                obj.transform.localPosition = new Vector3(0, 0, 0.5f + (offset * (1.0f / transform.localScale.y)));
            }
        }
        if (direction == "Right")
        {
            if (obj != null)
            {
                obj.transform.localPosition = new Vector3(-0.5f - (offset * (1.0f / transform.localScale.y)), 0, 0);
            }
        }
        if (direction == "Back")
        {
            if (obj != null)
            {
                obj.transform.localPosition = new Vector3(0, 0, -0.5f - (offset * (1.0f / transform.localScale.y)));
            }
        }
        if (direction == "Left")
        {
            if (obj != null)
            {
                obj.transform.localPosition = new Vector3(0.5f + (offset * (1.0f / transform.localScale.y)), 0, 0);
            }
        }
        if (direction == "Up")
        {
            if (obj != null)
            {
                obj.transform.localPosition = new Vector3(0, 0.5f + (offset * (1.0f / transform.localScale.y)), 0);
            }
        }
        if (direction == "Down")
        {
            if (obj != null)
            {
                obj.transform.localPosition = new Vector3(0, -0.5f - (offset * (1.0f / transform.localScale.y)), 0);
            }
        }

        if (obj != null) {
     
            obj.transform.LookAt(transform.position);

            if (direction == "Front")
            {
                obj.transform.localPosition = new Vector3(0.5f, 0.5f, obj.transform.localPosition.z);
            }

            if (direction == "Right")
            {
                obj.transform.localPosition = new Vector3(obj.transform.localPosition.x, 0.5f, 0.5f);
            }

            if (direction == "Back")
            {
                obj.transform.localPosition = new Vector3(-0.5f, 0.5f, obj.transform.localPosition.z);
            }

            if (direction == "Left")
            {
                obj.transform.localPosition = new Vector3(obj.transform.localPosition.x, 0.5f, -0.5f);
            }

            if (direction == "Up")
            {
                obj.transform.localPosition = new Vector3(-0.5f, obj.transform.localPosition.y, 0.5f);
            }

            if (direction == "Down")
            {
                obj.transform.localPosition = new Vector3(-0.5f, obj.transform.localPosition.y, -0.5f);
            }

            obj.transform.localScale = new Vector3(1, 1, 0.0001f);

            //obj.transform.Translate(-new Vector3(0.5f, -0.5f, 0));

            Material mat = Resources.Load(matName) as Material;

            mat.SetColor("_Color", color);

            mat.shader = Resources.Load(shaderName) as Shader;

            Font font = Resources.Load(fontName) as Font;

            mat.SetTexture("_MainTex", textObj.GetComponent<MeshRenderer>().material.GetTexture("_MainTex"));

            obj.GetComponent<TextMesh>().font = font;

            obj.GetComponent<TextMesh>().text = message;

            obj.GetComponent<TextMesh>().color = color;

            obj.GetComponent<TextMesh>().characterSize = characterSize;
            obj.GetComponent<TextMesh>().fontSize = fontSize;

            obj.GetComponent<MeshRenderer>().material = mat;

        }

        if (sheetObj != null)
        {
            sheetObj.GetComponent<TextMesh>().characterSize = characterSize;
            sheetObj.GetComponent<TextMesh>().fontSize = fontSize;
            sheetObj.GetComponent<TextMesh>().text = message;
        }

        if (m_textMesh != null && (m_textMesh.text != m_wrappedText || MaxWidth != m_lastMaxWidth))
        {
            float widthSum = 0.0f;
            m_wrappedText = "";
            string line = "";

            char[] separators = new char[] { ' ', '\n', '\t' };
            string[] words = message.Split(separators);

            for (int i = 0; i < words.Length; i++)
            {
                string word = words[i].Trim();

                if (i == 0)
                {
                    line = word;
                    widthSum = GetWordWidth(word);
                }
                else
                {
                    // Concatenate the new word if there is still enough space.
                    if (widthSum + GetWordWidth(word) <= MaxWidth)
                    {
                        if (widthSum > 0.0f)
                        {
                            line += ' ';
                            widthSum += GetSpaceWidth();
                        }

                        line += word;
                        widthSum += GetWordWidth(word);
                    }
                    // New line.
                    else
                    {
                        if (m_wrappedText.Length > 0)
                            m_wrappedText += '\n';

                        m_wrappedText += line;

                        line = word;
                        widthSum = GetWordWidth(word);
                    }
                }
            }

            if (widthSum > 0.0f)
            {
                if (m_wrappedText.Length > 0)
                    m_wrappedText += '\n';

                m_wrappedText += line;
            }

            m_textMesh.text = m_wrappedText;
            m_lastMaxWidth = MaxWidth;
        }

        transform.eulerAngles = rotation;

    }
}