guiRangeFinderHud
by Tim Dix (Raverix) · 06/01/2009 (8:44 pm) · 27 comments
This code came about from this post, so thank you deepscratch for getting this started, and Ron Nelson for the original snippet.I chose to simplify and do a very basic GUI based off guiTextCtrl. If you're looking for something a bit more flashy, it should be really easy to adapt this to your needs. I tried to make it well commented so that you can follow along.
Instructions: Just save the following file to your source folder, compile, and then place the GUI using the GUI Editor.
T3D/fps/guiRangeFinderHud.cpp
#include "gui/controls/guiTextCtrl.h"
#include "console/consoleTypes.h"
#include "console/console.h"
#include "T3D/gameConnection.h"
#include "T3D/gamebase.h"
class GuiRangeFinderHud : public GuiTextCtrl
{
typedef GuiTextCtrl Parent;
F32 mMaxRange; // Max Range for our finder
public:
GuiRangeFinderHud();
void onRender( Point2I, const RectI &);
static void initPersistFields();
DECLARE_CONOBJECT( GuiRangeFinderHud );
};
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT( GuiRangeFinderHud );
GuiRangeFinderHud::GuiRangeFinderHud()
{
mMaxRange = 1000; //Max range we search for a collision
}
void GuiRangeFinderHud::initPersistFields()
{
Parent::initPersistFields();
addGroup("RangeFinder");
addField("maxRange", TypeF32, Offset(mMaxRange, GuiRangeFinderHud));
endGroup("RangeFinder");
}
void GuiRangeFinderHud::onRender(Point2I offset, const RectI &updateRect)
{
// Must have a connection and game base control object
GameConnection* conn = GameConnection::getConnectionToServer();
if (!conn)
return;
GameBase* control = dynamic_cast<GameBase*>(conn->getControlObject());
if (!control)
return;
MatrixF cam;
Point3F dir;
Point3F startPos;
Point3F endPos;
// Get the camera's tranform,
conn->getControlCameraTransform(0,&cam);
cam.getColumn(3, &startPos); //Camera Position
cam.getColumn(1, &dir); //Camera forward vector
//Calculate the point mMaxRange in front of camera.
endPos = startPos + dir * mMaxRange;
//Store the state of the collision
bool collisionEnabled = control->isCollisionEnabled();
//Disable collision so we don't collide with ourself.
if(collisionEnabled)
control->disableCollision();
//These are the items that we will consider to collide with
static U32 mask = TerrainObjectType |
InteriorObjectType |
WaterObjectType |
StaticShapeObjectType |
StaticTSObjectType |
PlayerObjectType |
ItemObjectType |
VehicleObjectType;
//Get out container, copied from camera.cpp, I think I need it :p
RayInfo collision;
Container* pContainer = control->isServerObject() ? &gServerContainer : &gClientContainer;
//Cast our ray and see what we hit
if (pContainer->castRay(startPos, endPos, mask, &collision))
{
//If our ray hits, set our text
char text[32];
dSprintf(text, 32,"%.0f", (collision.point - startPos).len());
setText(text);
}
else
{
//Otherwise, set the range to maxRange+, ie: 1000+
char text[32];
dSprintf(text, 32,"%.0f+", mMaxRange);
setText(text);
}
//Enable collision if we need to
if(collisionEnabled)
control->enableCollision();
//Let the parent take care of rendering
Parent::onRender(offset,updateRect);
}This was coded for T3D, but it should be extremely easy to port it back to any of the engines. The only thing I think that would be needed to change would be the headers.
Let me know if you've got any problems and I'll do my best to help.

#2
Im curious about the clip of code from lines 43 to 50. I have seen this type of check before, but never bother emulating it in my own code scribbles, assuming it is mostly redundant checking situations that are most probably true. But every time i see it in use, it reminds me that my programing skills are mostly mysterious, this could be a good chance for me to learn something I should be knowing.
06/02/2009 (4:48 am)
Groovy. Im tweaking this for an level edit measuring tool. But it wold also fit nice with an RPG map/clue following puzzle. Thanks Tim for working it out and deepscratch for starting the idea. Also the comments are perfect, code reads just as well as it functions.Im curious about the clip of code from lines 43 to 50. I have seen this type of check before, but never bother emulating it in my own code scribbles, assuming it is mostly redundant checking situations that are most probably true. But every time i see it in use, it reminds me that my programing skills are mostly mysterious, this could be a good chance for me to learn something I should be knowing.
#4
06/02/2009 (5:41 am)
and if anyone has suggestions on how to dynamicaly display world coordinates of players and objects, like the way names are displayed in the name hud, please do tell...
#5
@Caylo - Deepscratch was right about you need those lines for 85, as well as the lines to check collision, and get the camera control. And since you asked the question, I looked at the resources and realized that there was nothing specific to ShapeBase here, so I modified the code to replace the need for ShapeBase to the need for GameBase, this should ensure this works with a range of classes.
@Caylo - You don't even need to be a player for this to work, if you're flying with just the camera as you would in the level editing tool, this will give you a range to what you have under the center of the screen. If you want to modify this give the distance between what you have selected, and yourself, you would basically cut out the ray cast parts, and just do something like this:
@deepscratch - Well, if you want to modify guiShapeNameHud take a look at line 207
06/02/2009 (6:34 am)
@Daniel - Sounds good, like I said, all you should need to do is change the headers. If you go ahead and do it, would you post here what changes you did for the next person?@Caylo - Deepscratch was right about you need those lines for 85, as well as the lines to check collision, and get the camera control. And since you asked the question, I looked at the resources and realized that there was nothing specific to ShapeBase here, so I modified the code to replace the need for ShapeBase to the need for GameBase, this should ensure this works with a range of classes.
@Caylo - You don't even need to be a player for this to work, if you're flying with just the camera as you would in the level editing tool, this will give you a range to what you have under the center of the screen. If you want to modify this give the distance between what you have selected, and yourself, you would basically cut out the ray cast parts, and just do something like this:
(selected.position - startPos).len()
@deepscratch - Well, if you want to modify guiShapeNameHud take a look at line 207
// Render the shape's name drawName(Point2I((S32)projPnt.x,(S32)projPnt.y),shape->getShapeName(),opacity);Instead of passing just shape->getShapeName, you could create a new string, copy the value of the shape name, and then copy the shape's position, and pass that along.
#6
06/02/2009 (3:25 pm)
Nice. Looks kind of familiar to me aye deepscratch? ;)
#7
06/02/2009 (3:43 pm)
yeah Ron, came as a surprise to me too.
#8
06/02/2009 (3:58 pm)
So Tim just throwing this out there but wouldn't it be appropriate to credit those who actually wrote the code?
#9
06/02/2009 (3:59 pm)
wait, that was you wasn't it Ron?
#10
06/02/2009 (4:01 pm)
Yeah sure looks like the code I gave you.
#11
06/02/2009 (5:28 pm)
Which lines of code would you like credited to you Ron? This was a complete rewrite of the code, copied from guiCrossHairHud.cpp, but extending guiTextCtrl. I believe the only thing left in it is the mask types, and that came from camera.cpp.
#12
Resource
Resource
Post
Resource
Resource
Post
Resource
Unless I'm mistaken, there's no code left for you to lay claim to.
06/02/2009 (6:54 pm)
Here's a line by line comparison of my resource vs where the code was adapted from.Resource
// Must have a connection and shape base control object GameConnection* conn = GameConnection::getConnectionToServer(); if (!conn) return; GameBase* control = dynamic_cast<GameBase*>(conn->getControlObject()); if (!control) return;Source: guiCrossHairHud.cpp - line 76
// Must have a connection and player control object
GameConnection* conn = GameConnection::getConnectionToServer();
if (!conn)
return;
ShapeBase* control = dynamic_cast<ShapeBase*>(conn->getControlObject());
if (!control || !(control->getType() & ObjectMask) || !conn->isFirstPerson())
return;Resource
MatrixF cam; Point3F dir; Point3F startPos; Point3F endPos; // Get the camera's tranform, conn->getControlCameraTransform(0,&cam); cam.getColumn(3, &startPos); //Camera Position cam.getColumn(1, &dir); //Camera forward vector //Calculate the point mMaxRange in front of camera. endPos = startPos + dir * mMaxRange;Source: guiCrossHairHud.cpp - line 90
MatrixF cam; Point3F camPos; conn->getControlCameraTransform(0,&cam); cam.getColumn(3, &camPos); // Extend the camera vector to create an endpoint for our ray Point3F endPos; cam.getColumn(1, &endPos); endPos *= gClientSceneGraph->getVisibleDistance(); endPos += camPos;Source: camera.cpp - line 960
Point3F dir;
mat->getColumn(1, &dir);
pos *= mMaxOrbitDist - mMinOrbitDist;
// Use the camera node's pos.
Point3F startPos = getRenderPosition();
Point3F endPos;Source: mePost
Resource
//Disable collision so we don't collide with ourself.
if(collisionEnabled)
control->disableCollision();
//These are the items that we will consider to collide with
static U32 mask = TerrainObjectType |
InteriorObjectType |
WaterObjectType |
StaticShapeObjectType |
StaticTSObjectType |
PlayerObjectType |
ItemObjectType |
VehicleObjectType;
//Get out container, copied from camera.cpp, I think I need it :p
RayInfo collision;
Container* pContainer = control->isServerObject() ? &gServerContainer : &gClientContainer;
//Cast our ray and see what we hit
if (pContainer->castRay(startPos, endPos, mask, &collision))Source: camera.cpp - line 970if(mOrbitObject)
mOrbitObject->disableCollision();
disableCollision();
RayInfo collision;
U32 mask = TerrainObjectType |
InteriorObjectType |
WaterObjectType |
StaticShapeObjectType |
PlayerObjectType |
ItemObjectType |
VehicleObjectType;
Container* pContainer = isServerObject() ? &gServerContainer : &gClientContainer;
if (!pContainer->castRay(startPos, startPos - dir * 2.5 * pos, mask, &collision))Resource
//If our ray hits, set our text char text[32]; dSprintf(text, 32,"%.0f", (collision.point - startPos).len()); setText(text);Source - My recommendation
Post
Resource
//Let the parent take care of rendering Parent::onRender(offset,updateRect);Source: guiCrossHairHud - line 84
// Parent render. Parent::onRender(offset,updateRect);
Unless I'm mistaken, there's no code left for you to lay claim to.
#13
However, it is my understanding he asked you for assistance with finishing it up and then all of sudden you have released it as a resource.
06/03/2009 (1:29 am)
Well Tim I am not upset about what I did for deepscratch as that was work I did for him as a favor. However, it is my understanding he asked you for assistance with finishing it up and then all of sudden you have released it as a resource.
#14
the rendering code looks a lot like the rendering code that Ron wrote up for me, that was 2 days before any of these posts, and was included in the files I send Tim, after he offered to "look" at them and see if he could fix it for me (the whole rendering range thing, which was my idea).
so a short while after I sent the files to Tim, there is a resource up?
bad form, he should at least have asked if I mind that he resource it. he didnt.
if he had, I would have asked that he give credit all round to who worked on this.
just bad form I guess.
one doesnt offer to help, then create a resource from the files you get, without at least informing or asking that you want to resource it.
06/03/2009 (1:36 am)
if anyone is wondering WTF is going on here,the rendering code looks a lot like the rendering code that Ron wrote up for me, that was 2 days before any of these posts, and was included in the files I send Tim, after he offered to "look" at them and see if he could fix it for me (the whole rendering range thing, which was my idea).
so a short while after I sent the files to Tim, there is a resource up?
bad form, he should at least have asked if I mind that he resource it. he didnt.
if he had, I would have asked that he give credit all round to who worked on this.
just bad form I guess.
one doesnt offer to help, then create a resource from the files you get, without at least informing or asking that you want to resource it.
#15
There is nothing else in this entire resource that you could possibly lay claim to as being your own. In fact, anyone wanting to create this resource from scratch needs only to copy the snippet for the ray, and paste it into guiCrossHairHud.cpp - line 101 through 116, and expose the range variable to script. All the code here is stock.
I don't take lightly accusations of code plagiarism. This is completely and entirely new code, based only off what's available in the public forum. And nothing especially new. I had a range finder working in my game two years ago, and anyone wanting to create one need only spend about 10 minutes of coding time to do so.
06/03/2009 (2:32 am)
@Ron - He sent me a file, and I tried to figure out what was wrong, and emailed it back to him. The code deepscratch asked me to help with was based off the speedometer gui, and the only code that is in common between it, and what I released above, is what deepscratch posted publicly here and I modified to this. This part of the code, I attributed. I didn't like the way he implemented it at all, so I decided to create a new public resource, based off my advice to use the guiCrossHairHud and guiTextCtrl and completely separately implement this the way I thought it should be.There is nothing else in this entire resource that you could possibly lay claim to as being your own. In fact, anyone wanting to create this resource from scratch needs only to copy the snippet for the ray, and paste it into guiCrossHairHud.cpp - line 101 through 116, and expose the range variable to script. All the code here is stock.
I don't take lightly accusations of code plagiarism. This is completely and entirely new code, based only off what's available in the public forum. And nothing especially new. I had a range finder working in my game two years ago, and anyone wanting to create one need only spend about 10 minutes of coding time to do so.
#16
06/03/2009 (4:00 am)
@deepscratch - The rendering code looks a lot like the rendering code in all such GUI controls in Torque, save for the snippet getting the range, which I attributed. Rendering the range between you and what's under your cursor is by no means a new idea. Although asking you for permission might have avoided this conversation, I didn't feel it was needed at the time since I didn't use any of the code you emailed, only the code you publicly posted here, which again, I attributed.
#17
06/03/2009 (4:24 am)
I don't see the problem here - Raverix is posting a Resource with the intention of helping the community, and as far as I can see has attributed the code he got from your public forum post correctly.
#18
@Omroth - The issue that deepscratch has with this is that he never intended to release his version as a resource. If I were in his place and if my files indeed looked like Tim's, I would be upset too. However, I don't put my code I want to keep private on the forums.
06/03/2009 (8:43 am)
@Tim - Well your explanation is the same method I used, so I am satisfied that you could have done this on your own. Also I am not a T3D owner so I never saw those posts I just sent him the stuff over MSN. I also never saw the full files just the portion that I wrote which is pretty close to identical to the method that you have in the onRender function above. I think what looks off here is the timing of your release as deepscratch had just sent you his version a day or two prior. If you say you already had something, well this is not important enough for me to mess with any further and I will accept your word on it.@Omroth - The issue that deepscratch has with this is that he never intended to release his version as a resource. If I were in his place and if my files indeed looked like Tim's, I would be upset too. However, I don't put my code I want to keep private on the forums.
#19
This is the code posted on the forums. this makes up 90% of the functionallity of this resource. The rest, is boilerplate GUI hud code.
As for the timing, I'm in the process of porting all my code from TGE to T3D, this was something on my list, so after discussing on the forums how to build this gui, giving my suggestion to use the guiCrossHairHud and guiTextCtrl as a starting point, I went ahead and developed my own version precisely how I outlined.
06/03/2009 (8:55 am)
For the sake of completeness since you don't have access to the forums,MatrixF cam; Point3F dir; Point3F startPos; Point3F endPos; // Get control camera info conn->getControlCameraTransform(0,&cam); cam.getColumn(3, &startPos); cam.getColumn(1, &dir); endPos = startPos + dir * rayDistance; // Make sure we don't extend the camera into anything solid conn->getControlObject()->disableCollision(); RayInfo collision; U32 mask = TerrainObjectType | InteriorObjectType | WaterObjectType | StaticShapeObjectType | PlayerObjectType | ItemObjectType | VehicleObjectType; Container* pContainer = conn->getControlObject()->isServerObject() ? &gServerContainer : &gClientContainer; if (pContainer->castRay(startPos, endPos, mask, &collision)) mDistance = collision.distance;
This is the code posted on the forums. this makes up 90% of the functionallity of this resource. The rest, is boilerplate GUI hud code.
As for the timing, I'm in the process of porting all my code from TGE to T3D, this was something on my list, so after discussing on the forums how to build this gui, giving my suggestion to use the guiCrossHairHud and guiTextCtrl as a starting point, I went ahead and developed my own version precisely how I outlined.
#20
06/03/2009 (2:04 pm)
Yup thats the stuff I gave deepscratch. But like I said, its not a big enough deal to me to fuss about it any further. He had asked me how I would go about making a range finder from a the camera position. The only thing missing in what you have above from what I sent him was the couple of optional comments I added. 
Torque Owner Daniel Buckmaster
T3D Steering Committee