Hoy nos centraremos en crear un HUD sencillito para el ejercicio que vamos arrastrando de recolección de monedas y ya de paso, crearemos un pequeño sistema de debug por consola para mostrar en el HUD valores que creamos importantes en ciertas clases. Por supuesto, es opcional y una herramienta más para aquellos que no tengan un debugger en condiciones configurado para trabajar con UDK (cosa que parece ser más frecuente de lo que debería).
En primer lugar analizamos la función más importante de la clase HUD (development/Src/Engine/Classes/HUD.uc):
HUD.uc
/**
* The Main Draw loop for the hud. Gets called before any messaging. Should be subclassed
*/
function DrawHUD()
{
local vector ViewPoint;
local rotator ViewRotation;
if ( bShowOverlays && (PlayerOwner != None) )
{
Canvas.Font = GetFontSizeIndex(0);
PlayerOwner.GetPlayerViewPoint(ViewPoint, ViewRotation);
DrawActorOverlays(Viewpoint, ViewRotation);
}
PlayerOwner.DrawHud( Self );
}
Como véis, debemos hacer un override de dicho método para pintar lo que sea necesario en nuestro HUD. También vemos que podemos delegar parte del HUD a PlayerController (llamada PlayerOwner.DrawHud(self) al final). Éste a su vez, delegará en DrawHUD de Pawn y de PlayerInput (que veremos más adelante su uso). También es importante fijarnos que pinta el HUD dependiendo del lugar en el que está mirando la cámara y demás, y por tanto, si queréis experimentar haciendo HUDs raros, tenéis que meter mano por aquí también.
Aquí tengo un ejemplo de utilización de pintado de HUD de un antiguo ejercicio. En él, se pinta un reloj (una textura y un rectángulo de colores según su estado, para indicar el tiempo que queda (¿Os suena de algo verdad?).
ESATHUD.uc
class ESATHUD extends HUD;
var CanvasIcon clockIcon;
var Texture2D clockTex;
var int clock;
var int FullClock;
var int MediumClock;
var int LowClock;
function ResetTimer(int newValue, int current)
{
FullClock=newValue;
MediumClock=FullClock * 0.66f; //2/3 Full
LowClock=FullClock * 0.33f; //1/3 de Full
SetTimer( 1, true, 'ClockTimer');
clock = current;
}
function ClearMyTimers()
{
ClearTimer('ClockTimer');
}
function ClockTimer()
{
//`log("Clock: "@clock@" ; FULL: "@FullClock);
if(clock > 0)
{
clock--;
}
}
function DrawHUD()
{
super.DrawHUD();
//Canvas.DrawIcon(clockIcon, 0, 0);
//Colocas "El cursor" de dibujo dónde deseas dibujar en la pantalla
Canvas.SetPos(100,15);
Canvas.SetDrawColor(255, 255, 255); // White
Canvas.DrawTile(clockTex,32.0f,32.0f,0.0f,0.0f,256.0f,256.0f,,,);
Canvas.Font = class'Engine'.static.GetLargeFont();
Canvas.SetDrawColor(255, 255, 255); // White
Canvas.SetPos(70, 15);
Canvas.DrawText(clock);
if(clock < LowClock)
{
Canvas.SetDrawColor(255, 0, 0); // Red
}
else if (clock < MediumClock)
{
Canvas.SetDrawColor(255, 255, 0); // Yellow
}
else
{
Canvas.SetDrawColor(0, 255, 0); // Green
}
Canvas.SetPos(200, 15);
Canvas.DrawRect(20 * clock, 30);
}
/**
* Puedes llamar a la llamada desde la consola ShowDebug y la etiqueta que quieras. En este caso
* Como puedes ver más abajo, existe la etiqueta GameInfo, que llama a una función de display debug
* que tiene tu GameInfo
* Para desactivar el mostrado de debug basta con colocar en consola el comando ShowDebug
*
*/
function ShowDebugInfo(out float out_YL, out float out_YPos)
{
if( ShouldDisplayDebug( 'GameInfo' ) )
{
ESATGameInfo(WorldInfo.Game).DisplayDebug(self, out_YL, out_YPos);
}
else
{
if( ShouldDisplayDebug( 'Pawn' ) )
{
(ESATGameInfo(WorldInfo.Game).GetALocalPlayerController().Pawn).DisplayDebug(self, out_YL, out_YPos);
}
else
{
super.ShowDebugInfo( out_YL, out_YPos );
}
}
}
DefaultProperties
{
clockTex=Texture2D'ESAT-Assets.Time'
clockIcon=(Texture=Texture2D'ESAT-Assets.Time')
FullClock=30
//IMPORTANT to post render actors!!
bShowOverlays=true
}
Como podéis ver en DrawHUD, lo primero que hacemos es llamar a la clase padre (también podemos copiar y pegarla antes o en su defecto modificar lo que necesitemos). El funcionamiento del HUD es bastante simple. Consta de un Canvas en el que debemos colocar un cursor en la posición que deseemos pintar o escribir (Canvas.SetPos(100,15);). Una vez allí, podemos pintar tiles con DrawTile, texto con DrawText, iconos con DrawIcon, rectángulos con DrawRect. Podemos echarle un vistazo a la clase base Canvas.uc para ver todas las posibilidades.
La función ShowDebugInfo, se utiliza como sistema de debug en otras clases. Por ejemplo, la función en la clase GameInfo de este mismo proyecto es esta:
ESATGameInfo.uc
[...]
simulated function DisplayDebug(HUD HUD, out float out_YL, out float out_YPos)
{
local string T;
local Canvas Canvas;
Canvas = HUD.Canvas;
out_YPos += out_YL;
Canvas.SetPos(4, out_YPos);
Canvas.SetDrawColor(255,0,0);
T = "GameInfo [" $ GetDebugName() $ "]";
Canvas.DrawText(T, FALSE);
out_YPos += out_YL;
Canvas.SetPos(4, out_YPos);
Canvas.SetDrawColor(255,255,255);
Canvas.DrawText("Score:" @ Score @ "InternalDataValue:" @ InternalDataValue, FALSE);
out_YPos += out_YL;
Canvas.SetPos(4,out_YPos);
Canvas.DrawColor.B = 255;
Canvas.DrawText(" STATE:" @ GetStateName(), FALSE);
out_YPos += out_YL;
Canvas.SetPos(4,out_YPos);
Canvas.DrawColor.B = 255;
Canvas.DrawText(" bWaitingToStartMatch:" @ bWaitingToStartMatch, FALSE);
out_YPos += out_YL;
Canvas.SetPos(4,out_YPos);
Canvas.DrawColor.B = 255;
Canvas.DrawText(" bUsingArbitration:" @ bUsingArbitration, FALSE);
out_YPos += out_YL;
Canvas.SetPos(4,out_YPos);
}
[...]
Como véis, se pintan en el HUD los valores que deseemos ver más adelante al abrir la consola de comandos (tabulador al iniciar el juego) y escribiendo ShowDebug y el nombre de la clase que hayamos indicado en la clase HUD.
¡Ejercicio!
Ahora toca realizar un HUD para nuestro juego de monedas. Una vez realizado, ya estará la funcionalidad básica del proyecto que se os pedirá inicialmente (si, mis alumnos no se pueden quejar, que el aprobado lo tienen con leer y practicar un poquillo, que aunque parezca mentira, ¡a veces no hacéis ni eso pillastres!).