I don't quite have text sprites in Three.js working to my satisfaction. I can imagine using these things in games so that "+10" replaces a captured game element. The "+10" could then slowly rise above the spot where it was awarded until it fades quickly away. The problem in this scenario is that I am not confident that I could place text exactly where it needs to go.
From list night, I am working with the words "Game Over". Since this phrase is obviously longer than it is tall, I specify the canvas dimension accordingly:
I draw the words in the 2D context of canvas. I make the font size 48 pixels high, which means that I have to shift the words down a little more than 48 pixels from the top so that I can see them.
var canvas = document.createElement('canvas'); canvas.width = 250; canvas.height = 100; var context = canvas.getContext('2d'); context.font = '48px Arial'; context.fillText("Game Over", 0, 50);
Unfortunately, using this canvas element as a Three.js texture doesn't quite work. The text is stretched tall:
My problem is that textures in Three.js need to be squares. If they are not squares, Three.js will stretch them until they fit. This explains the undesired appearance of my "Game Over" text. It also tells me how to fix it—make the canvas width and height the same:
This results in a much better looking text sprite:
var canvas = document.createElement('canvas'); canvas.width = 250; canvas.height = 250; var context = canvas.getContext('2d'); context.font = '48px Arial'; context.fillText("Game Over", 0, 50);
I still think I need help placing the text correctly in the scene. I am already using scene (not canvas) coordinates by virtue of setting the sprite's
useScreenCoordinatesproperty to false. If I make a ball with a radius of 100 at the center of the screen, then try to place the text 100 above the center, then my text ought to be immediately on top of the ball. The result, however is:
My text is a little too high there. My problem is that the text is placed at the very top of the canvas. If I want to move the text baseline to the middle, I need only shift the distance from the top by half the height:
That gives me the nicely placed text:
var canvas = document.createElement('canvas'); var size = 250; canvas.width = size; canvas.height = size; var context = canvas.getContext('2d'); context.font = '48px Arial'; context.fillText("Game Over", 0, size/2);
That is not quite a robust solution however. If I decrease the font size of "Game Over", the vertical position is still good, but now the horizontal alignment is off:
Per MDN, there is a
textAlignproperty for the canvas context that supports a value of "center". That sounds perfect. Unfortunately, it is less than perfect:
textAlignproperty is not within the bounding box of the canvas. Rather, it specifies how text is drawn from the specified coordinates. In this case, my coordinates are zero pixels over and
size/2pixels down the canvas:
The text is centered on that x coordinate of zero, which is good—only I need the x coordinate to be in the center of the canvas. In other words, I want
context.fillText("Game Over", 0, size/2);
size/2for the x position as well:
So the important points for this exercise—at least the points that confused me at first—are that canvas, like any other Three.js texture, needs to be a square and centering text on that canvas takes a bit of work.
Final version of the code