HUD Overview and Canvas functions
by Eater
Who this
tutorial is for
This tutorial is a detailed overview of all
the wonderful things you can do with HUDs and the Canvas class. Although I
do mention some things on how to create a simple HUD, this tutorial is
geared more towards advanced coders that want to find out a few more
tricks about making good HUDs. If you've never made a HUD before you may
find yourself a little confused. This is normal. Feel free to mail me any
questions you may have at [email protected].
Canvas and where it
all begins
First off, whenever you're making a HUD, you should
remember that everyone a HUD draws is drawn on the Canvas. The Canvas is
basically an object that draws thing directly on the player's screen. If
you've ever coded Java applets, the Graphics object is probably the
closest thing to the UT Canvas I can think of. The HUD is basically a set
of instructions that tell the Canvas object what to draw and where. The
HUD is redrawn as often as possible (every tick I believe). Whenever the
HUD is redrawn, the "PostRender(Canvas Canvas)" function is called. This
function is called by the PlayerPawn and gives you access to the Canvas
class so you can draw things on it. The PlayerPawn also calls the
PostRender function of weapons for things like custom crosshairs (like for
the rocket launcher), but we'll focus on just the HUD for now. Another
thing to keep in mind about the HUD is that in multiplayer games it exists
client-side (since there is no need for the server to know what the player
has going on with his HUD), so you should put "simulated" before all the
functions to ensure your own well being.
"What this all means
to me"
If you don't feel like figuring out what I said above,
here is a summary of what all that means to you, a guy that just wants to
make a custom HUD: The whole HUD process starts with the "PostRender(Canvas Canvas)" function which is called about every tick (in
other words, as often as possible). All the drawing is done by the Canvas
object. You should put "simulated" before all your functions in your HUD.
Simple enough, right? Good.
Making and using the HUD
Before I go into detail about how to actually draw pictures and
text on the HUD, I want to explain where and how you can use this HUD. The
best place to use new HUD objects is in a new gametype. I'm not sure about
mutators however, as it may be possible to modify the HUD with a mutator
without having to create a new HUD object. If, however, you want to use
your HUD in a new gametype just set the HUDType property of your new
gametype to the class name of your HUD. For most UT modifications, you'll
want to subclass ChallengeHUD, although if you're making a more total
conversion you might want to subclass the HUD class.
Basic
functions and variables
As stated before, all the drawing is
done by the Canvas object, sent to the HUD through the PostRender(Canvas
Canvas) function. Note that if you want to draw things on the HUD with
other functions besides PostRender, be sure to send the Canvas object to
them too so they actually have something to draw on. Now without any
further comments, here is my list of all the important functions and
variables in the Canvas class:
font Font - this is the font
that the Canvas will use when it draws text. I will explain more about
fonts later on.
float OrgX, OrgY - these are the
coordinates of the point (0,0). Usually you won't alter these, but there
are situations (explained later on) where altering these values can be
helpful.
float ClipX, ClipY - this is the bottom right
corner of the drawing region. Depending on the resolution, these values
will vary. Again, usually you won't alter these, but there are situations
where it may be helpful.
float CurX, CurY - the current
location for drawing. If you draw something, this is where it will be
drawn.
byte Style - the style in which pictures or text
will be drawn (transparent, masked, etc.). So if you want to draw a masked
icon, make sure that the Style variable is set to STY_Masked.
color DrawColor - the color in which something will be
drawn. The default is gray (127,127,127). If you draw a picture while the
DrawColor is not white, that picture's colors WILL be altered. To alter
the color, simply enter
Canvas.DrawColor.r = REDVALUE;
Canvas.DrawColor.g =
GREENVALUE;
Canvas.DrawColor.b = BLUEVALUE;
where REDVALUE, GREENVALUE, and BLUEVALUE are the amounts of
red green and blue you want in that color (255 is the max amount you can
set per color).
function StrLen( coerce string String, out
float XL, out float YL ) - return the dimensions of the string String
(XL and YL) based on the currently selected font.
function
DrawText( coerce string Text, optional bool CR) - draws the string
Text at (CurX,CurY) with the font Font.
function DrawTile(
texture Tex, float XL, float YL, float U, float V, float UL, float VL)
- used for drawing parts of an icon or drawing an icon with irregular
dimensions. This function will be discussed later on.
function
DrawActor( Actor A, bool WireFrame, optional bool ClearZ ) - draws the
actor A on the player's screen. This only makes sense if the actor A is
normally hidden. The only place I've seen this used is by the weapon class
for drawing the first person model.
function DrawPortal( int X,
int Y, int Width, int Height, actor CamActor, vector CamLocation, rotator
CamRotation, optional int FOV, optional bool ClearZ ) - draws a
rectangular area that displays the view from another actor. Most of the
values are pretty obvious. In my own experience I've noticed that this
function doesn't always work. If you are having trouble, make sure FOV is
set to 90.
event Reset() - resests all the variables to
their defaults. Useful for cleaning up after you do something messy (more
below).
function SetPos( float X, float Y ) - sets CurX to
X and CurY to Y, just like writing CurX = X; CurY = Y; only faster.
function SetOrigin( float X, float Y ) - sets OrgX to X and
OrgY to Y, just like writing OrgX = X; OrgY = Y; only faster.
function SetClip( float X, float Y ) - sets ClipX to X and
ClipY to Y, just like writing ClipX = X; ClipY = Y; only faster.
function DrawPattern ( texture Tex, float XL, float YL, float
Scale ) - draws a repeating pattern with sizes XL and YL and with a
scale Scale (that scale is applied to each "picture" in the pattern). Note
that the pattern is drawn as if it started at (0,0), so if you're drawing
in around the middle of the screen don't be surprised if you don't have
the upper-left hand corner of Tex in the upper-left hand corner of your
pattern (if you want to know what I mean, test this function out for
yourself). Also, keep in mind that the scale is reversed, so if you enter
0.5 the images will be 2x BIGGER, and with scale 2 they will be 2x
SMALLER.
function DrawIcon ( texture Tex, float Scale ) -
draws the icon Tex with a scale factor Scale. You will probably be using
this a lot.
function DrawRectangle ( texture Tex, float RectX,
float RectY ) - draws the icon Tex with a horizontal scale of RectX
and a vertical scale for RectY.
Drawing from the
bottom-right
This is really a beginner thing, but just so you
know, if you want to draw an icon along the bottom of the screen, since
the coordinates of the bottom will change with the resolution (as well as
the coordinates for the right edge), you should use ClipX and ClipY (that
is after all what they're there for). So if you want to draw a 64x64 pixel
icon in the lower right-hand corner, you would set the CurX to ClipX-64
and CurY to ClipY-64.
Fonts
The Font variable in
the Canvas class represents the font with which a text string will be
drawn. You can set this to any Font you want, but there are some
predefined Fonts in ChallengeHUD you should be aware of. Since the UT HUD,
unlike the Unreal HUD, changes depending on a player's resolution (so if
you increase the resolution the icons will be made bigger so as to
compensate), the fonts have to change with the resolution too. So if you
are making a HUD that changes with the resolution, you may want to use the
predefined font functions. The FontInfo class is a UT class that
determines what font you should use depending on the player's current
resolution. In the ChallengeHUD class, there is a FontInfo variable named
"MyFonts". This class contains a lot of functions that return the font you
want. Below is a list of all these functions. Note that you should enter
the current horizontal resolution, ClipX, for Width:
function
font GetHugeFont(float Width) - returns a HUGE font.
function
font GetBigFont(float Width) - returns a big font.
function font
GetMediumFont(float Width) - returns a medium font.
function
font GetSmallFont(float Width) - returns a small font.
function
font GetSmallestFont(float Width) - returns an even smaller
font.
function font GetAReallySmallFont(float Width) - returns a
really small font.
function font GetACompletelyUnreadableFont(float
Width) - returns a completely unreadable font.
Note that some of
the smaller fonts may not have a full character set and you might only be
able to use numbers.
Text wrapping and the use of origins and
clips
By default, if you draw some text at the edge of the
screen it will be automatically wrapped to the opposite edge. Of course,
this doesn't look very good and sometimes you need to draw a sort of "text
box" with wrapped text (like the Unreal translator). I have some good news
- you CAN do this.
The text wrapping is based on ClipX and OrgX.
The Canvas class assumes these are the edges of the screen, but as I
mentioned earlier, these variables can be changed. However, be sure never
to lose the original value of ClipX and ClipY, unless you want to be
drawing the rest of your HUD in a rather small portion of the screen. To
start off, you'll want to have two local variables in your function for
storing the original values of ClipX and ClipY. For this part of the
tutorial, we'll call these variables TempX and TempY. Before you do
anything, make sure TempX = ClipX and TempY = ClipY. Now that the original
clip values are safe and sound, we can start messing around with
them.
First you'll want to use the setOrigin function to set the
upper left-hand corner of our text box, then you'll want to use the
setClip function to determine the lower right-hand corner. Now you'll want
to enter setPos(0,0) so that the text starts in the upper left-hand corner
of the box, and your text box is all set. Now you can set the font, make
sure the colors are set right, etc. etc. and draw your text (with a single
DrawText function). After you're done with that, we have to clean things
up so that we can draw other stuff on the Canvas after this. First of all
you'll want to call Canvas.Reset() to clean things up, and then you'll
want to set ClipX and ClipY back to TempX and TempY. That's it, you're
done!
The Scale factor
NOTE: This section
only applies to people subclassing the ChallengeHUD class.
As I
mentioned before in the Fonts section, the UT HUD changes in size
depending on the resolution to give the impression that it stays the same.
It uses the floating point Scale, set in the SetupHUD() function, to
control the size of just about everything, so you'll want to multiply the
scale of your icons and the locations you enter by Scale. You may also
want to multiply it by StatusScale, which is the scale of the HUD set in
the menu (so it would be YourScaleOrLocation*Scale*StatusScale).
The almighty tile
The DrawTile function is a native
function in the Canvas class that actually draws an image. All those
DrawIcon and DrawPattern are just UnrealScript functions that use the
DrawTile function. However, the DrawTile function can be used to do a lot
of fun things. Here is a description of all the arguments of that
function:
native(466) final function DrawTile( texture Tex,
// this is the actual image you want to draw, simple enough
float
XL, // the horizontal length of the thing we're drawing, in
pixels
float YL, // the vertical length of the thing we're
drawing, in pixels
float U, // The horizontal offset of the
image (so if we're drawing an image 128 in length with XL 128 and UL 128
and we enter 64 here, it will look like 2 halves of the image on opposite
sides. Still confused? Here is my ASCII art to the
rescue:
//
//XL = 128, UL = 128, U = 0
("before"):
//[op]
//
//XL = 128, UL = 128, U = 64
("after"):
//p][o
//
float V, // The vertical offset
of the image (so if we're drawing an image 128 in height with YL 128 and
VL 128 and we enter 64 here, it will look like 2 halves of the image on
opposite sides. Still confused? Imagine the above ASCII art but rotated 90
degrees...
float UL, // how much of the image Tex to draw (so if
the image is 128 in length and we enter 64, we will draw half)
float
VL // how much of the image Tex to draw (so if the image is 128 in
height and we enter 64, we will draw half)
);
So, if our image
is 128 in length and we have UL set to 64 and XL set to 64, we will draw
half of the image.
If, under the same setup, we have XL set to 128,
we will draw half of that image with 2x the horizontal scale (so half the
image will cover the same area as the whole image with UL
128).
Also, there are a few things to keep in mind about U and V.
First of all, remember that it has nothing to do with XL and YL, so if you
have an image 128 in length and enter UL = 128 and XL = 64, entering U =
32 will NOT result in the image being cut in half as described in the
above ASCII art (it will be cut into 1/4 and 3/4). Think of XL and YL as a
scale applied after all the other stuff is done. Another thing to keep in
mind is that the image will be moved to the left for U and up for V, not
right and down as would seem to make sense.