Game Development Community

dev|Pro Game Development Curriculum

Context sensitive crosshair/object interaction

by Gareth Fouche · 02/28/2006 (6:57 pm) · 38 comments

Download Code File

As described in my plan a while ago, this resource adds a context sensitive crosshair to your game. Its based on the guiCrossHairHud that comes with TGE.

The crosshair is basically continually firing a ray into the scene on the client side, and storing a reference to the first object that intersects that ray. Then, when it comes time to render, it calls a script function to determine which "mode" it is in, based on that object. I put this in script so you can easily change the logic without recompiling the engine code. Based on which mode its in, it renders a different cursor. The modes are :

- normal
- hostile
- talk
- interact

I took a page from one of the gui components here, guiBitmapButtonCtrl, in the way I handled loading up the different bitmaps. In code, where you define the crosshair, you specify a bitmap string field. This is the name of the bitmap used in normal mode. For the other modes, the bitmaps must be named the same as the basic one, with "_[modename]" added to the end. I've included example bitmaps, which are named according to this convention :

- crossHair.png
- crossHair_hostile.png
- crossHair_talk.png
- crossHair_interact.png


Ok, to add this to your project, first add guiAdvancedCrossHairHud.cc to your project. Also, you need to modify the existing guiBitmapControl, which is in the \gui\controls\ subfolder. The setbitmap() functions need to be virtual, so that when the advanced crosshair calls setbitmap(), its overriden function is called, not guiBitmapControls (its ancestor). I've included the modified header file "guiBitmapControl.h", so you can just copy this over it. If you find the cursor turning into a black square instead of the bitmap when you look at something, its probably because you left this out ;)

Next, copy the .png files into the " \starter.fps\client\scripts\" folder, so that the game finds them when it loads.

Add "guiAdvancedCrossHairHud.cs" into the same folder. This is the bit of scripted logic that determines what the mode is based on the object. You'll see that it sets the mode to "normal" if the found object is the terrain (or it didn't find an object), "hostile" if its another player, and "interact" if its anything else (ie trees, houses, shapes etc). You can change this to suit whatever your game requirements are.

Again in the " \starter.fps\client\scripts\" folder, modify "default.bind.cs" by adding the following at the end (note this only works if your crosshair is named "CrossHair", but we will handle that in a minute ;)) :

moveMap.bind(keyboard, "m",  "Interact");

function Interact(%val)
{
   if(%val)
   {
      %obj = CrossHair.getSelectedObject();
      if(%obj !$= -1)
	   commandToServer('Interact',%obj.getGhostID());      
   }
}


So you press "m" to interact with the object under your cursor (it can be any distance away, if you want to change that so theres limited range, modify the code to do a check, I'm leaving that up to you guys)

Now open "\starter.fps\client\init.cs" and add the following :

exec("./scripts/guiAdvancedCrossHairHud.cs");

just after the line that says

exec("./scripts/centerPrint.cs");


In the "\starter.fps\client\" folder, make sure to delete config.cs and config.cs.dso, so that your key binding takes effect.

Now, in the "\starter.fps\client\ui" folder, open playGui.gui and find the line where they define the crosshair :

new GuiCrossHairHud() {

and change it to define an Advanced Crosshair, named "CrossHair" :

new GuiAdvancedCrossHairHud(CrossHair) {

You'll see a little further down where the base bitmap name is defined (./crossHair), notice you dont need the image type extension on the end, ie no .png. You dont need to make any changes here, unless your cursor bitmaps are named something else.

Almost done now, just need to put in the server side stuff. Open up "\starter.fps\server\commands.cs" and add the following at the bottom :

function serverCmdInteract(%client, %objID)
{
  onInteractWith(%client, %objID);
}

Now you need to define the function that actually handles interaction between your player and the object. What it does is very dependant on your game specifics, but I'm going to give you an example so you have an idea of how to do it. You could just put this code in the same file, but I put it at the end of "\starter.fps\server\game.cs", its up to you really :

function onInteractWith(%client, %objID)
{

  %obj = %client.resolveObjectFromGhostIndex(%objID);
  echo("(SERVER) INTERACTING WITH " @ %obj);

  if(%obj.getType() & $TypeMasks::PlayerObjectType)
  {
      echo("Your Death Stare does " @ %obj.getShapeName() @ " 200 points of damage! ZAP!");
      %obj.applyDamage(200);     
  }
}

All this piece of code does is check if the target object is a player, and if it is damages it. If you wanted to do something to Items (say pick them up, or use them), you would need to add another "if statement" checking for the right TypeMask (you can find the available types in the objectTypes.h file, just copy how I do the "if" there, replacing PlayerObjectType with something else ;)), and call an appropriate function, like %client.player.pickup(%obj).

Another thing to note there is the "resolveObjectFromGhostIndex" call. This is important, and a useful thing to remember. When the client sends the server an ID, it is the ID of a "ghost" object, ie a copy. You need this call for the server to figure out which of its objects corresponds to the ghost object on the clients side.


Ok, thats it, hope you enjoy it, have fun slaughtering Kork with a nasty look ;).
Page «Previous 1 2
#1
02/28/2006 (7:42 pm)
wow!! sounds nice... i'll try it now and give some feedback ;)
#2
02/28/2006 (8:29 pm)
perfect! this is "extremely useful" resource!
just found time to put it in... and ... just perfect! it can be extended ... imagination is a limit ;)
btw, one thing:
Quote:Next, copy the .png files into the " \starter.fps\client\scripts\" folder, so that the game finds them when it loads.
should be
Quote:Next, copy the .png files into the " \starter.fps\client\ui\" folder (overwriting old crossHair.png file), so that the game finds them when it loads.
for those who are new to Torque.
#3
03/01/2006 (4:34 am)
Sure would love to see a screenie of this in action
#4
03/01/2006 (5:54 am)
Awesome, this is one of the things I wanted to implement since I began working with Torque. Hopefully this is compatible with TSE with small modification. :)
#5
03/03/2006 (8:43 am)
Wow, this is just plain cool!!!! Very easy to implement. It makes a tremendous difference in the feel of a game.

[Edit]
how can I get more specific about interactions? I want to discern between weapon pickups and usable items like switches or doors.

I see the code in guiAdvancedCrossHairHud.cc that sets the cursor based on mMode (onRender), but don't see where mMode is set.

[Edit]
Aha! Found it in the guiAdvancedCrossHairHud.cs SWEET!!! YES!
#6
03/03/2006 (9:13 pm)
Great resource! I'm having a slight issue though. When I'm in game, and alt-tab out of game (in 1280 x 1024 mode, haven't tested it full screen nor on any other res) the crosshair/sword/hand/whatever icons dissapear completely when i get back in game. Now, if I do this again and alt-tab out and back in, then it returns to the screen and all is well until i alt-tab again, then i have to alt-tab AGAIN and so on.
#7
03/05/2006 (12:45 pm)
I've found that what you experience happens also with the terrain textures. (At least on the head TSE)

Also, I'm unable to convert this to TSE. I lack the knowledge of how things are handled (literally; stupid TextureHandles) in the source. :( Oh well.
#8
03/13/2006 (1:07 pm)
Got some problems:

I have the 1.4 version of Torque, and it seems that this resource need some polishing for this version - IF i didn't make any mistake while implementing the code...
I also have the lightining pack, by the way.

Well, this happened after i have installed the resource:
-No context sensitive change anywhere
-no response from the camera when i pressed f8 to deteach it from the player model

After some struggle, i deactiveted the changes in "\starter.fps\server\commands.cs" :
[/code]
function serverCmdInteract(%client, %objID){ onInteractWith(%client, %objID);}
[/code]
After quoting it from the script, camera flight with f8 returned to work properly.
I searched the console.log for errors, nothing besides that... any leads, people?
Thanks in advance.
#9
03/13/2006 (1:14 pm)
I also installed it over 1.4 and TLK, and it worked great. Not enough info to troubleshoot yet thought, try reimplementing?
#10
03/13/2006 (1:15 pm)
i have heavily modified TGE1.4+TLK and not see any problems.
actualy this resource don't touch in any way the code of the camera.. can be something else conflicting..
#11
03/13/2006 (4:34 pm)
Thanks guys! Now i know the problem's around here; gonna reimplement it all over, let's see what's wrong - i may probably made some mistake around VIsualC++ 6 recompiling, let's try again...
---------------------------------------------------------------------------------------------------------------------------------------
Stupid of me, i forgot to mention: when i first added the new guiAdvancedCrossHairHud.cc and guiBitmapCtrl.h, the compiler wasn't creating the .exe at all - strange error messages appearing, then after some poking around it started re-compiling the exe... my guess is that some option on the C++ compiler is completely wrong, i rememnber the compiler complaining about "wrong instructions" on the command options, like -V or -I or something like that. I think i'll have to re-install everthing from scratch on the backup copy, i hope i don't miss this time :D
thanks again!
#12
03/15/2006 (9:38 pm)
Eric, try doing "clean/rebuild" - might help
#13
03/16/2006 (3:09 am)
Has anyone managed to get TriggerObjectTypes working? All the other types seem to work...
#14
03/21/2006 (9:32 am)
I have am attempting to take this over to TSE, I have gotten as far as having no errors except this particular code bit. The OnRender bit is probably going to have to be recoded. Particularily this part.

mTextureHandle_Hostile = GFXTexHandle(buffer, BitmapTexture, true);
      if (!mTextureHandle_Hostile)
         mTextureHandle_Hostile = mTextureHandle;
      dStrcpy(p, "_talk");
      mTextureHandle_Talk = GFXTexHandle(buffer, BitmapTexture, true);
      if (!mTextureHandle_Talk)
         mTextureHandle_Talk = mTextureHandle;
      dStrcpy(p, "_interact");
      mTextureHandle_Interact = GFXTexHandle(buffer, BitmapTexture, true);
      if (!mTextureHandle_Interact)
         mTextureHandle_Interact = mTextureHandle;
#15
03/22/2006 (2:43 pm)
Matt H, please be sure to post your code when you get it working. :) I'd be extremely pleased to use it.
#16
03/23/2006 (6:39 pm)
Hmm, well I was working on this a bit more tonight. I have it compiling at least, the crosshair does not change as the above code is still a bit screwy. I believe though, I have found a larger problem in that, the "ghosting" functions (in getGhostID, etc) do not work properly in TSE. I found an older post where Ben said something about they aren't up to snuff as they had been focusing on graphics. Anyway, back to TGE for the time being for me.
#17
04/03/2006 (6:12 pm)
great resource, if I want to intiate the interaction rightaway when the crosshair enters an object, instead of pressing a button to initiate the interaction. How can I modify this resource to get what I want?
thanks!!
#18
04/04/2006 (6:03 am)
In GuiAdvancedCrossHairHud.cs, there is a routine called function GuiAdvancedCrossHairHud::selectMode, where you could put in code to trigger something. This routine gets called quite often, so use flags or something when you put in a call, or you could end up with a huge number of cascading calls!
#19
04/10/2006 (7:49 am)
For anyone who needs a range check on the crosshair, the following works nicely, 20 seems to be a good value :)

guiAdvancedCrossHairHud.cc -> around line 139, change

endPos *= gClientSceneGraph->getVisibleDistance();

to

endPos *= 20.0f;   // range check!
#20
06/21/2006 (10:58 am)
Thanks for this resource, I found it very useful and easy to implement in TGE 1.4. For some reason I didn't have a CrossHair section in my PlayGui but I copied a section from my TGE 1.3 PlayGui file and it all worked fine after the necessary changes.

Also, thanks Gavin for the range check code, works brilliantly and saved me a lot of time looking through the code and trying to implement it myself!

Matt Grint
Midnight Artists
Page «Previous 1 2