Table of Contents:
- Mouselook Script and Realtime Text – Introduction
- Using the Mouselook Script
- Running the Script in Your Game
- Adding Realtime Text
- Changing the Font Resolution
- Customizing Your Font
- Adding Text to Your HUD
- Word Wrapping
- Extra: More Text Formatting
- Conclusion
Mouselook Script and Realtime Text – Introduction
Did you know that Blender’s game engine has support for real font? If we catch you still using bitmap fonts you’ll be put in stocks in the town square and have tomatoes thrown at you. This tutorial was originally just going to be a simple one on creating realtime text, but in putting together a quick demo level for it I also created a mouselook script I would like to offer everyone. For those of you unfamiliar with the term mouselook, it refers to using mouse movement to rotate the camera and look around the scene. This is typical of first person shooter type games. I should note right off the bat that you don’t need to know anything about python to do this tutorial or to use any of the scripts involved.
After we work with the mouselook script we’ll get into adding realtime text. Here we’ll deal with adding text, changing the font resolution, changing the text value in a game, and formatting the text. Formatting will include basic string operations but most notably we’ll learn how to word wrap text. Word wrapping refers to splitting long lines of text into separate lines based on line length, something that was difficult with bitmap fonts but is really simple now that real font is supported. Below is a screenshot of the scene we’ll be working with towards the end of the tutorial.
Click image for full size
Using the Mouselook Script
You can download a simplified mouselook example file here
The script is super simple to use, and includes camera angle limitations so the camera stops rotating when you’re looking straight up or straight down. This angle range can be easily changed too.
Now you can either reverse engineer that scene to understand it, import the objects into your scene, or follow these instructions to learn how to implement it on your own. First, here’s the actual script itself. If you’re implementing this into your own scene, simply paste the following code into a new text document in Blender’s text editor, and name it something like “mouselook.py”.
from bge import render as r
import math
cont = bge.logic.getCurrentController()
own = cont.owner
mouse = cont.sensors["Mouse"]
parent = own.parent
#set speed for camera movement
sensitivity = 0.05
#set camera rotation limits
high_limit = 180
low_limit = 0
h = r.getWindowHeight()//2
w = r.getWindowWidth()//2
x = (h - mouse.position[0])*sensitivity
y = (w - mouse.position[1])*sensitivity
if own["startup"]:
r.setMousePosition(h, w)
own ["startup"] = False
else:
rot = own.localOrientation.to_euler()
pitch = abs(math.degrees(rot[0]))
if high_limit > (pitch+y) > low_limit:
pitch += y
elif (pitch+y) < low_limit:
pitch = low_limit
elif (pitch+y) > high_limit:
pitch = high_limit
rot[0] = math.radians(pitch)
own.localOrientation = rot.to_matrix()
parentRot = parent.localOrientation.to_euler()
yaw = math.degrees(parentRot[2]) + x
parentRot[2] = math.radians(yaw)
parent.localOrientation = parentRot.to_matrix()
r.setMousePosition(h, w)
Running the Script in Your Game
In short all you have to do is run the script from a camera which is parented to your main character. Also give the camera a boolean property called “startup” set to True. That’s all. The script rotates the camera but also rotates the object it’s parented to so that your main character is facing the same direction the camera is. So when you open that example file you’ll see the camera running the script from a mouse movement sensor and an always sensor(set to true pulse). This camera is parented to my main character(which is a cube) which also has typical FPS movement controls. To be safe, make sure your main character’s Z axis is pointed up. Check out the images below for the different settings for both the cube and the camera and then let’s move on to text in the game engine.
Settings for the Camera:
Settings for the Cube:
Adding Realtime Text
Blender uses the Text objects for realtime font. It renders them as real font when you start the game. So start a new scene and go into camera view. Left click near the upper left corner to place the 3d cursor there. Now press Shift+A and add a Text object. We went into camera view before adding the text so the text would be facing the camera. If your text isn’t facing the camera, go to the Editing tab in the User Preferences and change the Align To option to View. That way any objects you add will be aligned to the view instead of the world axis. It’s worth noting that you can rotate and scale the text however you want and it’ll still render skewed like that in the game though, which is awesome. Now press P in the 3D View.
Changing the Font Resolution
There you have it. You may notice the font is a little pixelated though. We can fix this in two ways. You can either move the text object further from the camera(and scale it up as needed) to sharpen it, or create a python script to change the resolution. So let’s make that script now. Go to the Text Editor in Blender and create a new file called “text_res”. Paste in the following code:
cont = bge.logic.getCurrentController()
own = cont.owner
own.resolution = 5
Now with the Text object still selected, go to the Logic Editor window and add an Always sensor connected to a Python controller. Click on the script field in the controller and select “text_res”. Press P in the 3D View again. No more blurry text! Change the resolution value until your text looks good. Don’t go too high. High values run the risk of freezing things up as Blender tries to make your text a needlessly high quality. A value of 1 is default, so start at 2 and go from there.
Logic Bricks setup:
No more blurry text:
Customizing Your Font
You can change the font color by changing the object color. To do that, go to the Object properties(cube icon in the Properties window) and change the Object Color option. To change the font, go to the Font properties(F icon in the Properties window) and load in different fonts there.
Adding Text to Your HUD
Now that we know how to add and customize text, we’re going to work with a real game and create an overlay scene which will show us messages and HUD elements like health or ammo. The initials HUD stand for Heads Up Display, and shows the player valuable information about their character like health, score, and ammo. Here we’ll also learn how to format the text and word wrap long strings(in coding text is referred to as strings). We’ll also learn how to change the text dynamically in game using both logic bricks and python.
Download the game level start file here
When you open up the file, you’ll notice it already has the cube and the camera from the mouselook blend. I’ve also added a walk and crouch animation on the camera and cube to make movement more interesting. Also note that in the render settings I have the animation frame rate set to 60 for smoother animations. So the scene is ready to play. Press P to roam around. Use WSAD to move and tap CTRL to crouch. Collect the ammo box in middle of the level. Our goal right now is to add an ammo counter to a HUD that increases with every ammo box you pick up. So first let’s create the overlay scene that will have the HUD. Create a new scene by going to the top header in Blender and clicking the + sign next to the scene field. Then select “New”.
Rename this scene to “HUD”. Go in to front view and add a camera. In side view move this camera to the left away from the world origin. Now back in camera view add a Text object and position it in the upper left of the view. Press Tab to go into Edit Mode. Backspace the default text and write “Ammo:”. If the text is pixelated in game then fix that the same way we fixed it in the font resolution section of the tutorial. Now duplicate this text and move it to the right next to the first one. Edit this to simply say “0″. This will be our ammo counter that will change every time you pick up an ammo box. Now with that “0″ object still selected, under the properties panel in the Logic Editor window click on “Add Text Game Property”. Change the type to Integer since we’re working with whole numbers, not strings or floats(numbers with decimal places). Now whatever we change this property to will be what’s displayed in the game. We’ll be using logic bricks to change its value shortly.
Let’s switch back to the game level scene now. Go up into the top header and click on the icon to the left of the scene field and choose “Scene” to switch back to our main level scene. Now with the camera selected in this scene go to the logic editor. We’re going to add the HUD as an overlay scene now. So add an Always sensor, connect it to an And controller, then connect that to a Scene actuator. Change the actuator Mode to Add Overlay Scene, and select HUD as the scene.
Now press P in the 3D View to play the game. You should see the HUD scene overlayed on top of the level scene.
Now we’re going to select the ammo box and add some logic to it to send a message to the ammo counter when the main character collides with it. When our ammo counter receives this message it will increase. So select the green ammo box. You’ll notice in the Logic Editor that it already has some logic that makes it spin around and which tells it to delete itself when anything collides with it. Let’s add an actuator that’s connected to that collision sensor. So add a Message actuator. Type in ammo in the Subject field. Connect this to the same controller that the Collision sensor is connected to. Now whenever the main character collides with the ammo box, the ammo box disappears and also sends out the message “ammo”.
Now switch back to the HUD scene and select the ammo counter. Add a Message sensor and type in ammo in the subject field. Connect this to an And controller and connect that to a Property actuator. Change the actuator Mode to Add, change the Property to Text, and change the Value to 1. So this line of logic says that when this receives the message “ammo” that it will add 1 to the Text property.
That should do it. Go back to the game level scene and play the game. Collect the ammo box and notice that the ammo counter changes from 0 to 1. Now duplicate the ammo box all around the scene and collect them all. That does it for changing the text value with logic bricks.
Word Wrapping
If you have a game with long dialogue or storytelling, you’ll want to format your long strings into paragraphs. You can manually start a new line by adding “\n” into your strings in python, or take the manual work out of it by using the textwrap python module. With this module we can take long strings and split them into separate lines at a certain length. Use monospaced font like Courier or DejaVu Sans Mono for best results as line length is determined by the number of characters, not by the line’s pixel width. For example in a regular font like Arial a line with a lot of lower case l’s will not be as long as other lines because the l’s only occupy a tiny amount of space. So to space your lines more consistently, use a monospaced font which is a type of font where every character occupies the same pixel width. For more samples of this check out the wikipedia page Samples of Monospaced Font.
Moving on. In the HUD scene add a new Text object towards the left of the camera view. Again fix the resolution if needed. In the Font properties change the font to a monospaced font like Courier. Back in the Logic Editor add a Text Game Property just like we did before. Keep the Type as String this time. Now create a new text file in the Text Editor and name this “text_wrap”. Paste in the following code:
import textwrap
cont = bge.logic.getCurrentController()
own = cont.owner
startmessage = "Welcome to this tutorial on text in the game engine."
own["Text"] = textwrap.fill(startmessage, 20)
Now add an Always sensor connected to a Python controller that runs the text_wrap script. Press P in the 3D View to see how it looks. The variable startmessage is where we define what the message will say. The variable own["Text"] is how we call the object’s Text property so we can change it. Then we use the function text.wrap.fill(startmessage, 20) to say we want to change the Text property to the startmessage value but split it into lines of 20 characters long. That’s all there is to word wrapping with python!
This message will display on screen once we start the game, but obviously we don’t want to leave it there forever. So add a Delay sensor and change the Delay to 200. Connect this to an And controller and connect that to a Visibility actuator with Visible unchecked. This says that after a delay of 200 tics the object becomes invisible. Now go back to the game level scene and press P in the 3D View to play the game. The start message will pop up, then disappear after a couple seconds. And we’re finished!
Extra: More Text Formatting
Here’s just a few more basic string formatting options.
capitalize() – Capitalizes the first letter of the string in the parenthesis
lower() – Makes all letters of a string in the parenthesis lowercase
upper() – Makes all letters of a string in the parenthesis uppercase
There are more options for working with strings below:
http://www.tutorialspoint.com/python/python_strings.htm
Conclusion
For more information on learning python you can check out my beginner’s BGE python script tutorial which shows you the basics of using python in the game engine and accessing logic brick information through scripting.
If you have notice any errors or have any comments about the tutorial then please contact me. Until next time!
Blengine