Text and Image Wrapping

Hey, I am attempting to wrap textures around text but I am unable to do it. Each time I try to do it, the textures are always out of place.

How can I successfully wrap the textures in their place like so:

Here is the code to the whole system: pastebin.com/kmQeDg8R

Did you add special chars to your font so MeasureString can find them ? (\n and ’ ') And is it a monospaced font ?

For that specific notification (and others) what I did is make a switch for it to remove the indicators when to take away text and put an image. (“Use ~PS4.LS~ to rappel.\nJump by pressing ~PS4.X~ to descend faster. Hold ~PS4.X~ after jumping for a longer jump.”).

How would I add special chars so MeasureString could find them?

Edit: The font is not monospaced.

IMHO you’d have to split the string into:

"Use "
“to rappel.”
"Jump by pressing "
“to descend faster. Hold”
“after jumping for a longer jump.”

, measure those independently and stitch them together + the images in their respective positions.
Don’t think that there’s any other generic way.

edit:
OK. After reviewing your code I have to add several, maybe unrelated, things.

  • Save your notifications using a dictionary. Your doesNotificationExist-method performs badly when dealing with large numbers of notifications compared to a dictionary.TryGet().
  • Your NotificationItem.imgPosition list is never used.
  • when doing weigh = new Vector2(font.MeasureString(words[i]).X + 16, font.MeasureString(words[i]).Y);, MeasureString is VERY expensive. Be sure to call it only when necessary. In that case once, memorize the Vector2 and use that later on.
  • You place spaces where the image will go; That depends heavily on the size/type of the font and doesn’t work any longer if someone changes the line-spacing or enters a bigger image. Like I said before, I wouldn’t do that. But it should work somehow. I get your point now…

Take a look at your HandleIMG code. You’re iterating over the word-array just to get the weigh and pos from the right dword. But you KNOW that words[s] is dword. No use iterating that. Just take the dword.
You then multiply the size of that word and the height of it in order to get a position.
That won’t work. ‘ans’ has a different height than ‘ddd’ even in the same font.

I fear the way to go is:

  1. Tokenizer… Split the input-string. Build groups of words you can render (like I wrote above). Separate when encountering a ‘\n’ or one of your image-strings. Remember where you removed one of your images from the string to put it back later on.
  2. Measure all of the tokens separately. Measure all of the images separately.
    you now should have something like that {[t1][img_ls][t2][enter][t3][img_x][t4][img_x][t5]} and measurements for every single one of those.
  3. Render the lot.
    First get the line-height (max height of any element in a line)… Foreach element in list -> If current_height > lineHeight -> lineHeight=current_height; If element == ‘enter’ break;
    Then draw them.

That’s how I would do it.

Calling measure string many times is going to be a performance hit if you have a big paragraph of that sort, in that case you might not find it acceptable.

You could look to this post its akin to getting a bit low level.
I did some work on something similar but never finished it fully because 1 i got sidetracked 2 real life but its good enough to be used / altered for what your doing here.

In the below links show a test class that is addresses something similar to your problem.
Basically in the tests i ran i made a class that mimiced the primary method for DrawString to unroll the matrices, you pass your spritebatch to it to bypass spritebatch.drawstring doing the drawing yourself from there you can wrap text easily by creating your own overload of the drawtext method or create a assortment of overloads that do what you need.

You could alter the Drawtext method in the test and make your own custom version for just your games that allows the behavior you are describing.

you can see notes in the below as well which has a slightly clearer version of the test.