I’ve got a scene where the user needs to find a few items, and as they find them the original list of items highlights to show which ones have been found and which are still missing. However rather than a bullet list it’s done in a sentence format because it’s presented as a riddle.
How can I make certain parts of the text highlight, whilst ignoring others? I’m currently using OnGUI, so a solution working with that would be ideal but if necessary I can use 3D Text.
Update: Here’s what I’m currently using to display the text, as well as some of the text that’s going in to it:
GUI.Box(Rect(50,riddleBoxTop,693,riddleBoxHeight),riddleText,riddleGuiStyle);
riddleText = "Three bees, ACT changed to CAT, A ball through a maze, a fox with a hat;
The red flame on its candle, a tree in its space, A tack, two snakes, and four wheels in place.";
The simplest way to change the GUI color is like this:
function OnGUI ()
{
var oldColor : Color = GUI.color;
GUI.color = Color.green;
/* do some stuff */
GUI.color = oldColor;
}
I recommend breaking your sentence up into an array of strings. It sounds like it's already broken up logically based on the fact that you want to highlight different portions.
Once you've broken it up into an array, you can draw each piece of text with a separate box (changing the GUI.color as you go). Like Ray_Wilson has suggested, you can use GUIStyle.CalcSize() to figure out the width and height of each piece. This will allow you to lay the boxes out next to each other.
This really won't be that complicated at all (not as bad as it sounds)...
Ok... I'm bored. Here's some simple, un-tested example code that uses a very simple custom class namedTextItem:
var stringList : TextItem [];
var startRect : Rect = Rect(0, 0, 0, 60);
function OnGUI ()
{
var theRect : Rect = startRect;
var theStyle : GUIStyle = GUI.skin.box;
/* store this for later */
var oldColor : Color = GUI.color;
for ( var thisItem : TextItem in stringList ) {
/* create a GUIContent and calculate its size */
var theContent : GUIContent = GUIContent(thisItem.text);
var theSize : Vector2 = theStyle.CalcSize(theContent);
GUI.color = thisItem.color;
theRect.width = theSize.x;
GUI.Box(theRect, theContent, theStyle);
/* set the x-value of the next box to the end of the last box */
theRect.x += theSize.width;
}
/* restore original gui color */
GUI.color = oldColor;
}
class TextItem
{
var text : String;
var color : Color;
function TextItem ()
{
text = "";
color = Color.white;
}
}
It would really depend on how you are intending to highlight your text and also how you are composing your sentence?
For example you could highlight text by making it a different colour. To do this you would have two different styles (one for normal text and one for highlighted text) with each being a different colour. This would necessitate composing your sentence of multiple text objects (e.g. GUI.Label) and the issue would then be how do you join them together to form the sentence? The following code is in C#
// Instance two GUIStyle objects
GUIStyle TextNormal = new GUIStyle();
GUIStyle TextHighlight = new GUIStyle();
// Change the colors in the styles accordingly
TextNormal.normal.textColor = Color.white;
TextHighlight.normal.textColor = Color.yellow;
// Sentence fragments
string strNormal = "You have item: ";
string strItem = "Test Item";
// Output sentence (composition?)
GUI.Label(new Rect(10, 10, 100, 20), strNormal, TextNormal);
GUI.Label(new Rect(110, 10, 100, 20), strItem, TextHighlight);
I would not recommend using inheritence to inherit GUI style information. The reason being every time you wanted to add a new style you would need to create a new base class and update or create multiple new sub-classes. As we are only talking about a different font colour you would be much better using GUIStyle in object composition and passing in the constructor.
You could overload the ‘+’ operator to get the functionality you mention though this necessitates knowing the pixel width of a piece of text. Fortunately, GUIStyle() can calculate this for you.
Take the following class as an example and perhaps something to work on (I haven’t had time to test this btw, but should hopefully just work):
public class RiddlePart
{
// A reference to the GUI style of this text
protected GUIStyle m_GUIStyle;
// The riddle fragment of text
protected string m_RiddleText;
// The text width (calculated from GUIStyle)
protected float m_TextWidth;
// The text height (calculated from GUIStyle)
protected float m_TextHeight;
// The X position of the text (screen space)
protected float m_XPos;
// The Y position of the text (screen space)
protected float m_YPos;
// ----------------
// ** Properties **
// ----------------
public float TextWidth
{
get { return m_TextWidth; }
}
public float TextHeight
{
get { return m_TextHeight; }
}
public float XPos
{
get { return m_XPos; }
}
public float YPos
{
get { return m_YPos; }
}
// ----------------
// ** Methods **
// ----------------
public RiddlePart(string RiddleText, GUIStyle Style)
{
// Store the style reference
m_GUIStyle = Style;
// Store the riddle text
m_RiddleText = RiddleText;
// Calculate text dimensions
CalculateTextDimensions();
// Default position
m_XPos = 0.0f;
m_YPos = 0.0f;
}
private void CalculateTextDimensions()
{
// We can use GUIStyle to calculate the text dimensions
m_TextWidth = m_GUIStyle.CalcSize(new GUIContent(m_RiddleText)).x;
m_TextHeight = m_GUIStyle.CalcSize(new GUIContent(m_RiddleText)).y;
}
public void SetPosition(float XPos, float YPos)
{
m_XPos = XPos;
m_YPos = YPos;
}
public void ChangeText(string NewRiddleText)
{
m_RiddleText = NewRiddleText;
CalculateTextDimensions();
}
public void RenderText()
{
// Output the text as a GUI label
GUI.Label(new Rect(m_XPos, m_YPos, m_TextWidth, m_TextHeight), m_RiddleText, m_GUIStyle);
}
// Overload the '+' operator
public static RiddlePart operator +(RiddlePart lhs, RiddlePart rhs)
{
// Update the right hand side riddle part based on the position and width/height of
// the left hand side riddle part
RiddlePart Temp = rhs;
Temp.SetPosition((lhs.XPos + lhs.TextWidth + 10.0f), lhs.YPos);
return Temp;
}
}
Adding these objects together should position them in a straight line beginning at the position of the first RiddlePart. You could create another class called ‘RiddleParagraph’ which is composed of ‘RiddleParts’ and is responsible for keeping track of line width and starting new lines and also doing the rendering of all these parts in OnGUI();