Problem with centering text

Hi,

Here’s the problem I’ve run into. I am doing an iOS card based 2D game. Since it’s card-based it has a number of cards in it. Each card has about 3 to 6 lines of text.

I am using GUI.Label to show the text, and it’s centering using the alignment setting in my GUIStyle. So far so good, everything is working fine, the text is presented as it should, and it’s centered. HOWEVER… this happens with the text on many of my cards.

   "This is a centered text meant 
  to show my problem regarding 
  centering of text. The problem 
   is that sometimes it looks like
               this."

Last line? Not so good… just one word appears on the last line. Sometimes it’s two, sometimes it’s three, sometimes it ends up looking good. All lines are filled with as many words that fit, and the last line will simply hold as many words that are left to show, no matter if it looks good or not. This isnt exactly wrong, thats how word processors do it. But… its not very nice looking. I want it to look like this:

  "This is a centered text meant 
   to show my problem regarding 
  centering of text. This is how
  I would like it to look. Good!"

EVENLY centered text.

I store each card tex in a string, one big line of text, I could manually add a bunch of newlines in every string of course, but that would be painfully slow to do since there’s a lot of cards, and if I wanted to change some text later I’d need to manually align it again.

So anyone has a suggestion how to automatically align a centered text evenly?

Thanks

This is actually quite a bit harder than I thought but here is my stab at it. First some disclaimers:

Disclaimers

  • This code is more of a ‘proof of
    concept’ and probably could be
    optimized / improved quite a bit and
    isn’t the type of thing you should
    really run every frame.

  • There are scenarios in which this code generates similar bad looking text as unity depending on the length of the words in the text / etc. It might be possible to improve this by allowing words to be broken into pieces but for readability I suggest keeping words intact.


Full Test Code

The following code draws two text boxes - the one on the left uses Unity3D standard label the other one uses some code to format the text before drawing. I added a button so that you can toggle between growing / shrinking the labels to see how the word wrap works at various sizes.

![alt text][1]

using UnityEngine;
using System.Collections;

public class TestDraw : MonoBehaviour 
{
	Vector2 area = new Vector2(275.0f, 200.0f);
	bool grow = false;
	
	void OnGUI()
	{
		// Common content
		string testContent = "This is a centered text meant to show my problem regarding centering of text. The problem is that sometimes it looks like this.";
		if(!grow) { area.x -= 0.05f; } else { area.x += 0.05f; }

		// Bad text alignment
		Rect badDisplayArea = new Rect(5.0f, 5.0f, area.x, area.y);
		GUI.skin.label.alignment = TextAnchor.MiddleCenter;
		GUI.Box(badDisplayArea, "");
		GUI.Label(badDisplayArea, testContent);
		
		// Good text alignment
		Rect goodDisplayArea = new Rect(area.x + 10.0f, 5.0f, area.x, area.y);
		GUI.skin.label.alignment = TextAnchor.MiddleCenter;
		GUI.Box(goodDisplayArea, "");
		DrawCenteredText(testContent, goodDisplayArea);
		
		// Toggle shrinking / grow
		if( GUI.Button(new Rect( 5.0f, area.y + 50.0f, 50.0f, 50.0f), "Toggle

Grow")) { grow = !grow; }
}

	// Note this function will only be work inside an OnGUI method or inside of another method used by OnGUI
	private void DrawCenteredText(string textToDraw, Rect textArea)
	{
		// Get the style we are using for the text
		GUIStyle getStyle = GUI.skin.GetStyle("Label");
		
		// Store text alignment
		TextAnchor storeAlignment = getStyle.alignment;
		getStyle.alignment = TextAnchor.MiddleCenter;
		
		// Create the content object to prevent duplicate 'new GUIContent(textToDraw)' calls
		GUIContent textContent = new GUIContent(textToDraw);
		
		// Figure out the width of the text without clipping it
		float textWidth = getStyle.CalcSize(textContent).x;
		
		// Figure out the height of the text with clipping
		float textHeight = getStyle.CalcHeight(textContent, textArea.width);
		
		// Figure out the average line width
		float lineCount = (textHeight / getStyle.lineHeight) - 0.25f; // Modify 0.25f for fine tuning
		float averageLineWidth = textWidth / lineCount;
		
		// Go through and construct the centered text
		string resultText = "";
		string centeredLine = "";
		float currentLineWidth = 0.0f;
		string[] wordsInText = textToDraw.Split(' ');
		for(int i = 0; i < wordsInText.Length; i++)
		{
			float wordSize = getStyle.CalcSize(new GUIContent(wordsInText*)).x;*
  •  	// Add the line if the word will make it go over*
    
  •  	if(currentLineWidth + wordSize > averageLineWidth)*
    
  •  	{*
    
  •  		// Add the line to the result*
    
  •  		resultText += centeredLine + "
    

";*

  •  		// Reset line and width*
    
  •  		centeredLine = "";*
    
  •  		currentLineWidth = 0.0f;*
    
  •  	}*
    
  •  	currentLineWidth += wordSize;*
    

_ centeredLine += wordsInText + " ";_
* }*

* // Add the line to the result*
* resultText += centeredLine;*

* // Draw the text*
* GUI.Label(textArea, resultText);*

* // Restore alignment*
* getStyle.alignment = storeAlignment;*
* }*
}
----------
## What Does The Code Do? ##
My approach was to find out how wide text being displayed is along with how many lines the text is being displayed over and then figure out an average line width and add a new line to any line that will be larger than the average line width.
Knowing that the code should be somewhat self explanatory (I hope).
_*[1]: https://dl.dropboxusercontent.com/u/56331222/Comparision.png*_