Chapter 2 – Getting the mouse into the fray
To get mouse coordinates we will use an extended HUD class. What is a hud ? Its a HEADS UP DISPLAY. Usually its the class that will render health, ammo and other nice overlays in real time in the viewport.
Lets create a new file named MyHud. Now you should anticipate you will have to change its “extends Object” to something. Lets extend from GameHUD. First thing we will do is wire it to our game. Again, go to your IsometricGameInfo class and add the following to its default properties :
HUDType=class‘MyHud’
Now I will try let go the white gloves a bit so we can both get to a pleasant pace for this tutorial. If you start having troubles integrating the classes, try setting up PostBeginPlay function like we coded in the IsometricGamePlayerController. This should output something to the console if the class has a proper instance. Remember that the Log function is your eyes to the code. You can make it output any variables. I will add Log functions as we go so do not worry about the details, I will explain them as we go along. As a last thing, I may use the following syntax to describe functions : CLASS :: FUNCTION, this is my C++ background getting the better of me, but its quicker to say in which class and which function I am referring to.
- Compile and run to see that no error is present.
Getting mouse coordinates
Add the following function to your MyHud class and take the time to read the comment :
/******************************************************************
*
* TUTORIAL FUNCTION
*
* This function will fetch mouse coordinates from the UI
* Hierarchy in the UIController of the PlayerController
*
*
******************************************************************/
function vector2D GetMouseCoordinates()
{
local Vector2D mousePos;
local UIInteraction UIController;
local GameUISceneClient GameSceneClient;
UIController = PlayerOwner.GetUIController();
if ( UIController != None)
{
GameSceneClient = UIController.SceneClient;
if ( GameSceneClient != None )
{
mousePos.X = GameSceneClient.MousePosition.X;
mousePos.Y = GameSceneClient.MousePosition.Y;
}
}
return mousePos;
}
Now if you do not catch what the comment means, do not worry about it, with this we get the mouse coordinates. If you really want to know more go to GameUISceneClient.uc.
Now the UDK theory about HUD calculation is that everything is supposed to be calculated in a function called PostRender. All the variables we need to calculate will be located in our player controller for our pawn to know where the mouse is located in 3d space. Unfortunately, with UDK, the only valid place to calculate this is inside the HUD. The reason is that we need a variable called Canvas that can turn mouse coordinates into 3d world coordinates inside the game. Copy the following PostRender function in your MyHud class :
/******************************************************************
*
* PostRender event
*
* Use postRender function to define and call all hud drawing
* routine.
*
*
******************************************************************/
event PostRender()
{
local IsometricCamera PlayerCam;
local IsometricGamePlayerController IsoPlayerController;
super.PostRender();
//Get a type casted reference to our custom player controller.
IsoPlayerController = IsometricGamePlayerController(PlayerOwner);
//Get the mouse coordinates from the GameUISceneClient
IsoPlayerController.PlayerMouse = GetMouseCoordinates();
//Deproject the 2d mouse coordinate into 3d world. Store the MousePosWorldLocation and normal (direction).
Canvas.DeProject(IsoPlayerController.PlayerMouse, IsoPlayerController.MousePosWorldLocation, IsoPlayerController.MousePosWorldNormal);
//Get a type casted reference to our custom camera.
PlayerCam = IsometricCamera(IsoPlayerController.PlayerCamera);
//Calculate a trace from Player camera + 100 up(z) in direction of deprojected MousePosWorldNormal (the direction of the mouse).
//-----------------
//Set the ray direction as the mouseWorldnormal
IsoPlayerController.RayDir = IsoPlayerController.MousePosWorldNormal;
//Start the trace at the player camera (isometric) + 100 unit z and a little offset in front of the camera (direction *10)
IsoPlayerController.StartTrace = (PlayerCam.ViewTarget.POV.Location + vect(0,0,100)) + IsoPlayerController.RayDir * 10;
//End this ray at start + the direction multiplied by given distance (5000 unit is far enough generally)
IsoPlayerController.EndTrace = IsoPlayerController.StartTrace + IsoPlayerController.RayDir * 5000;
//Trace MouseHitWorldLocation each frame to world location (here you can get from the trace the actors that are hit by the trace, for the sake of this
//simple tutorial, we do noting with the result, but if you would filter clicks only on terrain, or if the player clicks on an npc, you would want to inspect
//the object hit in the StartFire function
IsoPlayerController.TraceActor = Trace(IsoPlayerController.MouseHitWorldLocation, IsoPlayerController.MouseHitWorldNormal, IsoPlayerController.EndTrace, IsoPlayerController.StartTrace, true);
//Calculate the pawn eye location for debug ray and for checking obstacles on click.
IsoPlayerController.PawnEyeLocation = Pawn(PlayerOwner.ViewTarget).Location + Pawn(PlayerOwner.ViewTarget).EyeHeight * vect(0,0,1);
//Your basic draw hud routine
DrawHUD();
}
The magic of type casting
There is multiple ways of accessing variables inside our custom player controller. The way I prefer is to type-cast the variable only once and use it for the entire function. Depending on the way the compiler works this may be inneficient, but I do not possess enough knowledge about this particular topic to let the compiler do it for me.
First way of getting a variable from another class :
local MyClass MyVar;
MyVar = MyClass(OtherClass);
MyVar.Member += 1;
or
MyClass(OtherClass).Member += 1;
To make the tutorial easier to follow, I use the first approach.
Chapter 2 – Setting up for movement
Im having trouble compiling this. The PlayerMouse Variable doesnt seem to exist
PlayerMouse must be declared in the PlayerController because its referenced with IsoPlayerController.PlayerMouse, sorry but you should compile when the tutorial says so, I did it that way so you will not end up with undeclared variables, just look into chapter 2 setting up for movement and it will be pretty obvious what to add
i cant set up VS2008 to work properly so i use simple text editor for scripts and Frontend to compile. Plz tell me how can i declare PlayerMouse variable in my PlayerController for compile to succeed
vitiank you should follow the tutorial from chapter 0 and install vs2008 and install nfringe and if you just follow the explanations you should be able to compile correctly. Now if you are a hardcore programmer and cannot help but use notepad or such other software, you should make a sub folder like explained in chapter 0 for your projet and modify the proper ini files so that the frontend will be able to know where to look for your file.
GameHUD.uc does not exist in the July 2010 release. I’ve tried using copying it from a November 09 install with no luck. Any suggestions? Thanks.
@FozZ
Try using UDKHUD or UTHUD
This really is some good quality tuto mate! I didn’t finish it yet, and encounter quite a lot of difficulties because of the new UDK releases (and the fact that I’m adapting your stuff to be directly as I want it ^^), but still very helpful.
I’d like to point out 2 things that you should mention in a EDIT in my opinion:
- first one is the commment ok Jake answering to FozZ => GameHUD.uc doesn’t exist anymore, replace it with UTHUD.uc.
- a bit trickier: I’m using the latest classes they made (using July 2010 build), namely all the UT****.uc (e.g. UTPawn instead of Pawn). I guess that from now on, most of the users will do so, and there comes the problem which took me hours to solve: the new “GameInfo.uc” is “UTGame.uc”, and this one will never use your custom HUD class!!!
=> Fortunately, i can finally spread the solution in order to prevent people from falling into depression: from now on, UE3 can use either an Unreal Script HUD or a Flash one (called scaleform); this new scaleform HUD is the default one, which is why my custom Unreal Script HUD was not used. The trick is to add in your IsometricGameInfo.uc – default properties – the following statement:
———————–
bUseClassicHUD=true
———————–
This will make the engine use the Unreal Script HUD again!
Thanks LeNain that is really good information to pass on !