Object selection in Torque (v1.2 onward)
by Dave Myers · 03/12/2005 (11:48 pm) · 241 comments
Overview
I originally wrote this tutorial back in Feb 2002 and I still receive emails on this asking for help or just saying thanks. It's very rewarding to know that in some small way this resource helps people new to the Torque Engine. This version has been updated to work with the latest release of TGE, so hopefully it will help answer many of the questions that people had with the original. -Dave
This tutorial provides one method to enable object selection in your TGE-based game. This implementation will show how to implement a bounding box cursor that will be displayed when an object is selected with the mouse. It could easily be enhanced to allow you to implement a wide variety of features.
Using this Tutorial
Bold font is used to show new code in the different code snippets throughout the tutorial. Also, code that is not important has been left out and is denoted by a comment in italics reading "irrelevant code not shown for brevity".
Step 1 - Capture the mouseDown event
First, let's quickly create a new bind and client function that will toggle the cursor. Add the following code to the bottom of the script file.
/starter.fps/client/scripts/default.bind.cs
NOTE: Make sure and delete the current config.cs and config.cs.dso files found in /starter.fps/client. This file (config.cs) is created automatically each time you shutdown the game and is executed when starting up the game.
Second, let's capture any left button mouse click events on the client. To do that, we need to add in a method to the GameTSCtrl. This control is our canvas in the game - so clicking somewhere on this canvas (i.e. our game screen) will generate a mouseDown event, and we can capture that event and deal with it in GameTSCtrl.
I chose to add new members and "getter" methods for the point and vector to the control rather than pass the information back to the client scripts as parameters. Either way seems fine, I just chose the former.
engine/game/gameTSCtrl.h
Now let's add the implementation of the onMouseDown handler method. What we need to do is take the 2D screen coordinates of the mouse and create 3D screen coordinates. We then will create a vector that has the camera world coordinates as the first point and the 3D screen coordinates as the second point. Once we have calculated these two elements, we then call a client script function, which I also named onMouseDown, and let the scripts control it from there. The idea here is that later we will take the 3D screen coordinates and the vector and shoot a picking ray into our 3D world. We'll then check to see if that ray collides with an object in the world.
I believe the code is commented pretty well, so it should be easy to follow along.
engine/game/gameTSCtrl.cc
I then exposed the "getter" methods to the scripting engine, also in engine/game/gameTSCtrl.cc
Currently, the Torque demo has a GUI element called GuiShapeNameHud that is used to display player names and damage over the heads of the models. This control is actually almost the same size as the canvas itself, which means that any mouse events are actually handled by this control, not our GameTSCtrl. I preferred to keep the control, but modify it so that it will call to my new mouse down event handler in GameTSCtrl. To do that I inserted the following onMouseDown handler, which simply calls up to its parent - in this case, our GameTSCtrl.
engine/game/fps/guiShapeNameHud.cc
Step 2 - Client handler for mouse event
We now need to add a handler to the scripts for PlayGui, which is the script name of our canvas GameTSCtrl. This new method will grab the vector and point and call to a server script function SelectObject.
example/starter.fps/client/scripts/playGui.cs
Step 3 - Set up our connection to handle our selected object
Before we can actually select an object, we need to set aside a place to save this information, and provide a way for the server to update the client so that we can render (at least in this example) a bounding box cursor around our selected object. I have chosen to save this information as part of the GameConnection class.
engine/game/gameConnection.h
We'll need to pass the selected object around between the server and client, so in order to do so we need to modify the readPacket and writePacket methods of our GameConnection class. For a brief description of why, take a look at Justin Mette's tutorial on node hiding, starting with Step 2 - Updating ghosts. Basically, we will be saving off the selected object on the server, but our client needs to know what object is selected so that it can render the cursor around the ghost object.
We also need to create the "getter/setter" functions so we can get and set the selected object from the server scripts.
engine/game/gameConnection.cc
Step 4 - Check if we have selected something
The server is responsible for determining if we have selected something, and if so it will save off the selected object for use later. Let's keep this simple and add our new server command SelectObject to an existing script file (I personally put this and other related server commands in a separate file). The code below is pretty well-commented, so it should be pretty easy to follow the logic there.
fps/server/scripts/commands.cs
Step 5 - Example implementation
Your use of object selection will be specific to your game needs. However, let's go ahead and test it by making a small addition to the ShapeBase::renderObject method. There is already code there to show a bounding box if in debug mode, so let's just reuse it in the case we have something selected as a 3D cursor of sorts. First, we need to get the server connection, which is where we stored our selected object earlier. We then simply get the object id from the object and compare it to object id of the shapebase we are rendering. If they match, we go ahead and show the bounding box:
engine/game/shapeBase.cc
NOTE: If you want to select your own player you can hit the 'Tab' key to put yourself in third-person camera view and select him. You cannot hit F8 and drop a camera and then click on him, because in that case the game still thinks you are in first-person mode ($firstPerson = true still) and the check we made in commands.cs (serverCmdSelectObject) will filter out the player:
Conclusion
If you have any problems or suggestions with the tutorial, let's discuss them in the feedback.
Enjoy!
Dave Myers
Lumpy Games
My mad neural firings
I originally wrote this tutorial back in Feb 2002 and I still receive emails on this asking for help or just saying thanks. It's very rewarding to know that in some small way this resource helps people new to the Torque Engine. This version has been updated to work with the latest release of TGE, so hopefully it will help answer many of the questions that people had with the original. -Dave
This tutorial provides one method to enable object selection in your TGE-based game. This implementation will show how to implement a bounding box cursor that will be displayed when an object is selected with the mouse. It could easily be enhanced to allow you to implement a wide variety of features.
Using this Tutorial
Bold font is used to show new code in the different code snippets throughout the tutorial. Also, code that is not important has been left out and is denoted by a comment in italics reading "irrelevant code not shown for brevity".
Step 1 - Capture the mouseDown event
First, let's quickly create a new bind and client function that will toggle the cursor. Add the following code to the bottom of the script file.
/starter.fps/client/scripts/default.bind.cs
[b]moveMap.bind(keyboard, "m", "toggleMouseLook");
function toggleMouseLook(%val)
{
if(%val)
{
if(Canvas.isCursorOn())
CursorOff();
else
CursorOn();
}
}[/b]NOTE: Make sure and delete the current config.cs and config.cs.dso files found in /starter.fps/client. This file (config.cs) is created automatically each time you shutdown the game and is executed when starting up the game.
Second, let's capture any left button mouse click events on the client. To do that, we need to add in a method to the GameTSCtrl. This control is our canvas in the game - so clicking somewhere on this canvas (i.e. our game screen) will generate a mouseDown event, and we can capture that event and deal with it in GameTSCtrl.
I chose to add new members and "getter" methods for the point and vector to the control rather than pass the information back to the client scripts as parameters. Either way seems fine, I just chose the former.
engine/game/gameTSCtrl.h
class GameTSCtrl : public GuiTSCtrl
{
private:
typedef GuiTSCtrl Parent;
[b] // object selection additions
Point3F mMouse3DVec;
Point3F mMouse3DPos; [/b]
public:
GameTSCtrl();
bool processCameraQuery(CameraQuery *query);
void renderWorld(const RectI &updateRect);
void onMouseMove(const GuiEvent &evt);
void onRender(Point2I offset, const RectI &updateRect);
[b] // object selection additions
void onMouseDown(const GuiEvent &evt); //left-mouse click
Point3F getMouse3DVec() {return mMouse3DVec;};
Point3F getMouse3DPos() {return mMouse3DPos;};[/b]
DECLARE_CONOBJECT(GameTSCtrl);
};Now let's add the implementation of the onMouseDown handler method. What we need to do is take the 2D screen coordinates of the mouse and create 3D screen coordinates. We then will create a vector that has the camera world coordinates as the first point and the 3D screen coordinates as the second point. Once we have calculated these two elements, we then call a client script function, which I also named onMouseDown, and let the scripts control it from there. The idea here is that later we will take the 3D screen coordinates and the vector and shoot a picking ray into our 3D world. We'll then check to see if that ray collides with an object in the world.
I believe the code is commented pretty well, so it should be easy to follow along.
engine/game/gameTSCtrl.cc
[b]//--------------------------------------------------------------------------
// object selection additions
//--------------------------------------------------------------------------
void GameTSCtrl::onMouseDown(const GuiEvent &evt)
{
MatrixF mat;
Point3F vel;
if ( GameGetCameraTransform(&mat, &vel) )
{
//get the camera position
Point3F pos;
mat.getColumn(3,&pos);
//take our mouse coordinates and create (x,y,z) screen coordinates
Point3F screenPoint(evt.mousePoint.x, evt.mousePoint.y, -1);
//take our screen coordinates and get the corresponding
//world coordinates (this is what unproject does for us)
Point3F worldPoint;
if (unproject(screenPoint, &worldPoint))
{
mMouse3DPos = pos;
//create a vector that points from our starting point (the
//camera position) and heads towards our point we have chosen
//in the world
mMouse3DVec = worldPoint - pos;
mMouse3DVec.normalizeSafe();
//call client script handler
Con::executef(this, 1, "onMouseDown");
}
}
}[/b]I then exposed the "getter" methods to the scripting engine, also in engine/game/gameTSCtrl.cc
[b]ConsoleMethod( GameTSCtrl, getMouse3DVec, const char*, 2, 2, "()")
{
char* retBuffer = Con::getReturnBuffer(256);
const Point3F &vec = object->getMouse3DVec();
dSprintf(retBuffer, 256, "%g %g %g", vec.x, vec.y, vec.z);
return retBuffer;
}
ConsoleMethod( GameTSCtrl, getMouse3DPos, const char*, 2, 2, "()")
{
char* retBuffer = Con::getReturnBuffer(256);
const Point3F &pos = object->getMouse3DPos();
dSprintf(retBuffer, 256, "%g %g %g", pos.x, pos.y, pos.z);
return retBuffer;
}[/b]Currently, the Torque demo has a GUI element called GuiShapeNameHud that is used to display player names and damage over the heads of the models. This control is actually almost the same size as the canvas itself, which means that any mouse events are actually handled by this control, not our GameTSCtrl. I preferred to keep the control, but modify it so that it will call to my new mouse down event handler in GameTSCtrl. To do that I inserted the following onMouseDown handler, which simply calls up to its parent - in this case, our GameTSCtrl.
engine/game/fps/guiShapeNameHud.cc
class GuiShapeNameHud : public GuiControl {
typedef GuiControl Parent;
// field data
ColorF mFillColor;
ColorF mFrameColor;
ColorF mTextColor;
F32 mVerticalOffset;
F32 mDistanceFade;
bool mShowFrame;
bool mShowFill;
protected:
void drawName( Point2I offset, const char *buf, F32 opacity);
public:
GuiShapeNameHud();
// GuiControl
virtual void onRender(Point2I offset, const RectI &updateRect);
[b] // object selection additions
virtual void onMouseDown(const GuiEvent &evt);[/b]
static void initPersistFields();
DECLARE_CONOBJECT( GuiShapeNameHud );
};
[i] // irrelevant code not shown for brevity[/i]
void GuiShapeNameHud::initPersistFields()
{
Parent::initPersistFields();
addField( "fillColor", TypeColorF, Offset( mFillColor, GuiShapeNameHud ) );
addField( "frameColor", TypeColorF, Offset( mFrameColor, GuiShapeNameHud ) );
addField( "textColor", TypeColorF, Offset( mTextColor, GuiShapeNameHud ) );
addField( "showFill", TypeBool, Offset( mShowFill, GuiShapeNameHud ) );
addField( "showFrame", TypeBool, Offset( mShowFrame, GuiShapeNameHud ) );
addField( "verticalOffset", TypeF32, Offset( mVerticalOffset, GuiShapeNameHud ) );
addField( "distanceFade", TypeF32, Offset( mDistanceFade, GuiShapeNameHud ) );
}
[b]//--------------------------------------------------------------------------
// object selection additions
//--------------------------------------------------------------------------
void GuiShapeNameHud::onMouseDown(const GuiEvent &evt)
{
// Let's let the parent execute its event handling (if any)
GuiTSCtrl *parent = dynamic_cast<GuiTSCtrl*>(getParent());
if (parent)
parent->onMouseDown(evt);
}[/b]
/**
Core render method wich does all the work.
This method scans through all the current client ShapeBase objects
and if they are named, displays their name and damage value. If the
shape is a PlayerObjectType then values are displayed offset from it's
eye point, otherwise the bounding box center is used.
*/
void GuiShapeNameHud::onRender( Point2I, const RectI &updateRect)
{
[i] // irrelevant code not shown for brevity[/i]Step 2 - Client handler for mouse event
We now need to add a handler to the scripts for PlayGui, which is the script name of our canvas GameTSCtrl. This new method will grab the vector and point and call to a server script function SelectObject.
example/starter.fps/client/scripts/playGui.cs
[b]//-----------------------------------------------------------------------------
// object selection additions
//-----------------------------------------------------------------------------
function PlayGui::onMouseDown(%this)
{
// mouseVec = vector from camera point to 3d mouse coords (normalized)
%mouseVec = %this.getMouse3DVec();
// cameraPoint = the world position of the camera
%cameraPoint = %this.getMouse3DPos();
commandToServer('SelectObject', %mouseVec, %cameraPoint);
}
[/b]Step 3 - Set up our connection to handle our selected object
Before we can actually select an object, we need to set aside a place to save this information, and provide a way for the server to update the client so that we can render (at least in this example) a bounding box cursor around our selected object. I have chosen to save this information as part of the GameConnection class.
engine/game/gameConnection.h
class GameConnection : public NetConnection
{
[i]// irrelevant code not shown for brevity[/i]
private:
/// @name Move Packets
/// Write/read move data to the packet.
/// @{
void moveWritePacket(BitStream *bstream);
void moveReadPacket(BitStream *bstream);
/// @}
[b] ///object selection additions
SimObjectPtr<ShapeBase> mSelectedObj;//pointer to our selected object
bool mChangedSelectedObj; //flag used to determine if we have changed our selected object[/b]
public:
[b] ///object selection additions
void setSelectedObject(ShapeBase *so) { mSelectedObj = so; mChangedSelectedObj = true; }
ShapeBase* getSelectedObject() { return mSelectedObj; }
bool hasChangedSelectedObject() { return mChangedSelectedObj; }[/b]
/// @name Protocol Versions
///
/// Protocol versions are used to indicated changes in network traffic.
/// These could be changes in how any object transmits or processes
/// network information. You can specify backwards compatability by
/// specifying a MinRequireProtocolVersion. If the client
/// protocol is >= this min value, the connection is accepted.
///
/// Torque (V12) SDK 1.0 uses protocol = 1
///
/// Torque SDK 1.1 uses protocol = 2
/// @{
static const U32 CurrentProtocolVersion;
static const U32 MinRequiredProtocolVersion;
/// @}We'll need to pass the selected object around between the server and client, so in order to do so we need to modify the readPacket and writePacket methods of our GameConnection class. For a brief description of why, take a look at Justin Mette's tutorial on node hiding, starting with Step 2 - Updating ghosts. Basically, we will be saving off the selected object on the server, but our client needs to know what object is selected so that it can render the cursor around the ghost object.
We also need to create the "getter/setter" functions so we can get and set the selected object from the server scripts.
engine/game/gameConnection.cc
GameConnection::GameConnection()
{
[i]// irrelevant code not shown for brevity[/i]
//blackout vars
mBlackOut = 0.0f;
mBlackOutTimeMS = 0;
mBlackOutStartTimeMS = 0;
mFadeToBlack = false;
[b] //object selection additions
mSelectedObj = NULL;
mChangedSelectedObj = false;[/b]
}
[i]// irrelevant code not shown for brevity[/i]
ConsoleMethod( GameConnection, getControlObject, S32, 2, 2, "")
{
argv;
SimObject* cp = object->getControlObject();
return cp? cp->getId(): 0;
}
[b]//--------------------------------------------------------------------------
// object selection additions
//--------------------------------------------------------------------------
ConsoleMethod( GameConnection, setSelectedObject, bool, 3, 3, "(%object)")
{
ShapeBase *sb;
if(!Sim::findObject(argv[2], sb))
return false;
object->setSelectedObject(sb);
return true;
}
//--------------------------------------------------------------------------
// object selection additions
//--------------------------------------------------------------------------
ConsoleMethod( GameConnection, getSelectedObject, S32, 2, 2, "()")
{
SimObject* so = object->getSelectedObject();
return so? so->getId(): 0;
}[/b]
ConsoleMethod( GameConnection, isAIControlled, bool, 2, 2, "")
{
return object->isAIControlled();
}
void GameConnection::readPacket(BitStream *bstream)
{
char stringBuf[256];
stringBuf[0] = 0;
bstream->setStringBuffer(stringBuf);
clearCompression();
if (isServerConnection())
{
mLastMoveAck = bstream->readInt(32);
if (mLastMoveAck < mFirstMoveIndex)
mLastMoveAck = mFirstMoveIndex;
if(mLastMoveAck > mLastClientMove)
mLastClientMove = mLastMoveAck;
while(mFirstMoveIndex < mLastMoveAck)
{
AssertFatal(mMoveList.size(), "Popping off too many moves!");
mMoveList.pop_front();
mFirstMoveIndex++;
}
[b] // object selection additions
// selected object - do we have a change in status?
if (bstream->readFlag())
{
// do we have a selected object now?
bool hasSelectedObj = bstream->readFlag();
if ((hasSelectedObj) && (bstream->readFlag()))
{
S32 gIndex = bstream->readInt(10);
ShapeBase* obj = static_cast<ShapeBase*>(resolveGhost(gIndex));
if (mSelectedObj != obj)
setSelectedObject(obj);
}
else
mSelectedObj = NULL;
}[/b]
mDamageFlash = 0;
mWhiteOut = 0;
if(bstream->readFlag())
{
if(bstream->readFlag())
mDamageFlash = bstream->readFloat(7);
if(bstream->readFlag())
mWhiteOut = bstream->readFloat(7) * 1.5;
}
[i]// irrelevant code not shown for brevity[/i]
}
void GameConnection::writePacket(BitStream *bstream, PacketNotify *note)
{
[i] // irrelevant code not shown for brevity[/i]
else
{
// The only time mMoveList will not be empty at this
// point is during a change in control object.
bstream->writeInt(mLastMoveAck - mMoveList.size(),32);
S32 gIndex = -1;
[b] // object selection additions
// selected object - have we changed the status of the selected object?
if (bstream->writeFlag(hasChangedSelectedObject()))
{
// do we have a selected object?
if ((bstream->writeFlag(mSelectedObj != NULL)) && (!mSelectedObj.isNull()))
{
gIndex = getGhostIndex(mSelectedObj);
if (bstream->writeFlag(gIndex != -1))
bstream->writeInt(gIndex,10);
}
// reset the status of our object
mChangedSelectedObj = false;
}
gIndex = -1;[/b]
// get the ghost index of the control object, and write out
// all the damage flash & white out
if (!mControlObject.isNull())
{
gIndex = getGhostIndex(mControlObject);
F32 flash = mControlObject->getDamageFlash();
F32 whiteOut = mControlObject->getWhiteOut();
if(bstream->writeFlag(flash != 0 || whiteOut != 0))
{
if(bstream->writeFlag(flash != 0))
bstream->writeFloat(flash, 7);
if(bstream->writeFlag(whiteOut != 0))
bstream->writeFloat(whiteOut/1.5, 7);
}
}
else
bstream->writeFlag(false);
[i] // irrelevant code not shown for brevity[/i]
}Step 4 - Check if we have selected something
The server is responsible for determining if we have selected something, and if so it will save off the selected object for use later. Let's keep this simple and add our new server command SelectObject to an existing script file (I personally put this and other related server commands in a separate file). The code below is pretty well-commented, so it should be pretty easy to follow the logic there.
fps/server/scripts/commands.cs
[b]//-----------------------------------------------------------------------------
// object selection additions
//-----------------------------------------------------------------------------
function serverCmdSelectObject(%client, %mouseVec, %cameraPoint)
{
//Determine how far should the picking ray extend into the world?
%selectRange = 200;
// scale mouseVec to the range the player is able to select with mouse
%mouseScaled = VectorScale(%mouseVec, %selectRange);
// cameraPoint = the world position of the camera
// rangeEnd = camera point + length of selectable range
%rangeEnd = VectorAdd(%cameraPoint, %mouseScaled);
// Search for anything that is selectable – below are some examples
%searchMasks = $TypeMasks::PlayerObjectType | $TypeMasks::CorpseObjectType |
$TypeMasks::ItemObjectType | $TypeMasks::TriggerObjectType;
// Search for objects within the range that fit the masks above. If we are
// in first person mode, we make sure player is not selectable by setting
// fourth parameter (exempt from collisions) when calling ContainerRayCast
%player = %client.player;
if ($firstPerson)
{
%scanTarg = ContainerRayCast (%cameraPoint, %rangeEnd, %searchMasks, %player);
}
else //3rd person - player is selectable in this case
{
%scanTarg = ContainerRayCast (%cameraPoint, %rangeEnd, %searchMasks);
}
// a target in range was found so select it
if (%scanTarg)
{
%targetObject = firstWord(%scanTarg);
%client.setSelectedObject(%targetObject);
}
}[/b]Step 5 - Example implementation
Your use of object selection will be specific to your game needs. However, let's go ahead and test it by making a small addition to the ShapeBase::renderObject method. There is already code there to show a bounding box if in debug mode, so let's just reuse it in the case we have something selected as a 3D cursor of sorts. First, we need to get the server connection, which is where we stored our selected object earlier. We then simply get the object id from the object and compare it to object id of the shapebase we are rendering. If they match, we go ahead and show the bounding box:
engine/game/shapeBase.cc
void ShapeBase::renderObject(SceneState* state, SceneRenderImage* image)
{
[i] // irrelevant code not shown for brevity[/i]
dglNPatchEnd();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
dglSetViewport(viewport);
uninstallLights();
[b] // object selection additions
// if we have been selected, then render a cursor around us
// for now this is simply a bounding box
GameConnection* conn = GameConnection::getServerConnection();
ShapeBase* selectedObj = NULL;
if (conn)
selectedObj = conn->getSelectedObject();
S32 selectedId = -1;
if (selectedObj != NULL)
selectedId = selectedObj->getId();
// Debugging Bounding Box
//object selection change - added || (get() == selectedId) to existing statement
//if (!mShapeInstance || gShowBoundingBox) {
if (!mShapeInstance || gShowBoundingBox || (getId() == selectedId)) {[/b]
glDisable(GL_DEPTH_TEST);
Point3F box;
glPushMatrix();
dglMultMatrix(&getRenderTransform());
box = (mObjBox.min + mObjBox.max) * 0.5;
glTranslatef(box.x,box.y,box.z);
box = (mObjBox.max - mObjBox.min) * 0.5;
glScalef(box.x,box.y,box.z);
glColor3f(1, 0, 1);
wireCube(Point3F(1,1,1),Point3F(0,0,0));
glPopMatrix();
}
[i] // irrelevant code not shown for brevity[/i]NOTE: If you want to select your own player you can hit the 'Tab' key to put yourself in third-person camera view and select him. You cannot hit F8 and drop a camera and then click on him, because in that case the game still thinks you are in first-person mode ($firstPerson = true still) and the check we made in commands.cs (serverCmdSelectObject) will filter out the player:
if ($firstPerson)
{
%scanTarg = ContainerRayCast (%cameraPoint, %rangeEnd, %searchMasks, %player);
}
else //3rd person - player is selectable in this case
{
%scanTarg = ContainerRayCast (%cameraPoint, %rangeEnd, %searchMasks);
}Conclusion
If you have any problems or suggestions with the tutorial, let's discuss them in the feedback.
Enjoy!
Dave Myers
Lumpy Games
My mad neural firings
About the author
Considerable experience developing with Torque-based technologies and produced the first third-party game using any Torque technology (Orbz). Game designer, programmer, and producer, and credits include the innovative title Orbz and the colorful BuggOut.
#122
Hardcoding the vec and pos to (0,0,0) stops the infinite looping problem, but obviously won't yield any results
Any other values I try to hard code end up turning into rollover values, which I have yet to figure out why:
If I use vec instead of test, Output in console: -1073741824 -1075074633 1610612736
These don't seem like accurate numbers to feed into %mouseVec and %cameraPoint for SelectObject()
But, I'm getting these numbers from code used in the resource. Any further suggestions?
09/20/2006 (10:22 am)
Orion: Thanks for the quick reply and info.Hardcoding the vec and pos to (0,0,0) stops the infinite looping problem, but obviously won't yield any results
Any other values I try to hard code end up turning into rollover values, which I have yet to figure out why:
ConsoleMethod(GameTSCtrl, getMouse3DVec, const char*, 2, 2, "()")
{
char* retBuffer = Con::getReturnBuffer(256);
const Point3F &vec = object->getMouse3DVec();
[b]const Point3F test(10.0f, 10.0f, 10.0f);
dSprintf(retBuffer, 256, "%d %d %d ", test.x, test.y, test.z);
Con::printf(retBuffer);
return retBuffer;[/b]
}Output in console: 0 1076101120 0If I use vec instead of test, Output in console: -1073741824 -1075074633 1610612736
These don't seem like accurate numbers to feed into %mouseVec and %cameraPoint for SelectObject()
But, I'm getting these numbers from code used in the resource. Any further suggestions?
#123
%d is for integer values,
%f is for floats, which is what test.x et al are.
09/20/2006 (10:54 am)
in your dSprintf() line, try changing the "%d"s to "%f"s.%d is for integer values,
%f is for floats, which is what test.x et al are.
#124
Top 3 Dumb Things I do(and never learn my lesson):
1) Walk into glass doors
2) Consistently use the wrong parameter for dSprintf(), sPrintf(), ect.
3) Give honest opinion to girlfriend on how her outfit looks, when "you look great" would suffice
I am now selecting objects, even though the box doesn't display. But at least I know I'm selecting it, thanks for the help.
Awesome, awesome resource by the way. Good job Dave
09/20/2006 (11:41 am)
Orion: Much thanksTop 3 Dumb Things I do(and never learn my lesson):
1) Walk into glass doors
2) Consistently use the wrong parameter for dSprintf(), sPrintf(), ect.
3) Give honest opinion to girlfriend on how her outfit looks, when "you look great" would suffice
I am now selecting objects, even though the box doesn't display. But at least I know I'm selecting it, thanks for the help.
Awesome, awesome resource by the way. Good job Dave
#125
yeah, this resource is like my #1 vote for stuff which should be rolled into the stock engine.
09/20/2006 (11:44 am)
:D lol! glad it's working out.yeah, this resource is like my #1 vote for stuff which should be rolled into the stock engine.
#126
09/20/2006 (12:04 pm)
@Michael: Just make sure you're looking directly at her when you say "you look great."
#127
I have another slight problem. ShapeBase::RenderObject() is not being called. As I posted before, the %targetObject variable is definitely telling me I've selected the right object, but I'd still like to have that visual verification. I've put breakpoints inside of the function to no avail. Hints, tips, rants?
*EDIT* Using TSE if that makes a difference.
09/20/2006 (12:37 pm)
Rubes: Thanks for the tip =)I have another slight problem. ShapeBase::RenderObject() is not being called. As I posted before, the %targetObject variable is definitely telling me I've selected the right object, but I'd still like to have that visual verification. I've put breakpoints inside of the function to no avail. Hints, tips, rants?
*EDIT* Using TSE if that makes a difference.
#128
09/20/2006 (12:41 pm)
You're using TSE (not TLK), but perhaps this resource might give you some ideas, if you haven't seen it yet.
#129
Apparently others were having the same problems as me:
www.garagegames.com/mg/forums/result.thread.php?qt=17106
I'm going over my bounding box and transforms now, I'll have to wait to get with my artist tomorrow. At least now that I have my objects selected, I can start moving them and having fun =) P5 Gloves are awesome by the way. They work great with this resource.
09/20/2006 (1:04 pm)
Rubes: Didn't solve my problem, but definitely had info I will need later, thank youApparently others were having the same problems as me:
www.garagegames.com/mg/forums/result.thread.php?qt=17106
I'm going over my bounding box and transforms now, I'll have to wait to get with my artist tomorrow. At least now that I have my objects selected, I can start moving them and having fun =) P5 Gloves are awesome by the way. They work great with this resource.
#130
09/21/2006 (1:00 pm)
I've decided to take my visual confirmation one step further. I've begun implementing object manipulation once selection has occurred. So the user will be able to grab objects and move them around using the mouse, or in my case, the P5. This will give a nice Black and White feel, especially when I throw in the 3D dis-embodied hand.
#131
09/29/2006 (8:51 pm)
I'd just like to say thanks to Dave for keeping this going and all the other comments. Special thanks to PJjerry, who pointed out on Jun 25, 2005 how to get it to work with ver 1.4. (my error was the getServerConnection() has been altered to getConnectionToServer() in v1.4).
#132
But still, I'm wondering... is it really necessary to follow this even if the World Editor has the capability of object selection? Can't we just re-use world editor's object selection mechanism? Where can we find the object selection code for world editor anyway?
Sorry, still very new to Torque engine coding/scripting.
10/11/2006 (8:18 pm)
Great resource!!!But still, I'm wondering... is it really necessary to follow this even if the World Editor has the capability of object selection? Can't we just re-use world editor's object selection mechanism? Where can we find the object selection code for world editor anyway?
Sorry, still very new to Torque engine coding/scripting.
#133
10/13/2006 (12:34 am)
Can someone tell me what does the magic number "10" signify in this code?Quote:
S32 gIndex = bstream->readInt(10);
#134
it's the number of bits used to represent the int.
an S32 is 32 bits, but to make the bitstream as efficient as possible, it can write fewer than the full 32.
10/13/2006 (7:35 am)
Matahari -it's the number of bits used to represent the int.
an S32 is 32 bits, but to make the bitstream as efficient as possible, it can write fewer than the full 32.
#135
Thank You.
10/21/2006 (12:04 am)
Hi Guys, I'm doing some stuff related to this resource and I am having a problem. Hope you can provide me some assistance? Here: http://www.garagegames.com/mg/forums/result.thread.php?qt=52605Thank You.
#136
I have implemented the code, but is does not seem to work. I'm using version 1.4 so i have changed getServerConnection to getConnectionToServer. I tried to change the profile in chathud.gui to "GuiModelessDialogProfile", to make sure that this wasn't the problem.
I also have the Advanced Camera implemented.
The problem is that when you click on the mouse nothing happens. I have changed the code in playgui.cs to:
function PlayGui::onMouseDown(%this)
{
echo("Trying to send vector from camera point to 3d mouse coords!");
}
Just to see if a mouseclick is registrered but there is no readout in the console. The "m" key to release the mouse seems to be working fine, but as no click is registered I'm not able to select anything!
I get no errors in console.log or when I build the engine (and yes - I have tried to rebuild it!)...
Hope you can help, and sorry about the language..
Sincerely
Soeren
10/23/2006 (7:04 am)
HiI have implemented the code, but is does not seem to work. I'm using version 1.4 so i have changed getServerConnection to getConnectionToServer. I tried to change the profile in chathud.gui to "GuiModelessDialogProfile", to make sure that this wasn't the problem.
I also have the Advanced Camera implemented.
The problem is that when you click on the mouse nothing happens. I have changed the code in playgui.cs to:
function PlayGui::onMouseDown(%this)
{
echo("Trying to send vector from camera point to 3d mouse coords!");
}
Just to see if a mouseclick is registrered but there is no readout in the console. The "m" key to release the mouse seems to be working fine, but as no click is registered I'm not able to select anything!
I get no errors in console.log or when I build the engine (and yes - I have tried to rebuild it!)...
Hope you can help, and sorry about the language..
Sincerely
Soeren
#137
Have you implemented the OnMouseDown event in GameTSCtrl, as outlined above ?
If so, try putting some printf()s or breakpoints in that code.
If it's not reaching there either, trace further back in the event chain,
possibly all the way to GuiCanvas::rootMouseDown().
10/23/2006 (8:42 am)
Hi Soeren -Have you implemented the OnMouseDown event in GameTSCtrl, as outlined above ?
If so, try putting some printf()s or breakpoints in that code.
If it's not reaching there either, trace further back in the event chain,
possibly all the way to GuiCanvas::rootMouseDown().
#138
I have checked the console.log to see that there are no syntax errors.
I am sure that the GuiShapeNameHud::onMouseDown routine is entered. It looks like below:
void GuiShapeNameHud::onMouseDown(const GuiEvent &evt)
{
Con::printf("Entering the function --- GuiShapeNameHud::onMouseDown ---");
GuiTSCtrl *parent = dynamic_cast(getParent());
if (parent)
parent->onMouseDown(evt);
}
(and then of course the line "virtual void onMouseDown(const GuiEvent &evt);" at the beginning of the file.)
The code for GameTSCtrl::onMouseDown is entered...
I have tried to put in some printf's (see in the example above) but no output appears in the console no matter where I try to write it. I think I have entered about 10 printf's in the code but none appear on runtime. As you described Orion I have also put a printf in the GuiCanvas::rootMouseDown(), but nothing appear here either.
Can printf's somehow be turned off, so that they does not appear in the console?
Thank you so much for your help so far. Hope you have some sugestions for what could be the problem!
/S
10/25/2006 (1:24 am)
Okay - I tried to find the error with the help of Orion and Rubes (thank you so much for the replies!):I have checked the console.log to see that there are no syntax errors.
I am sure that the GuiShapeNameHud::onMouseDown routine is entered. It looks like below:
void GuiShapeNameHud::onMouseDown(const GuiEvent &evt)
{
Con::printf("Entering the function --- GuiShapeNameHud::onMouseDown ---");
GuiTSCtrl *parent = dynamic_cast
if (parent)
parent->onMouseDown(evt);
}
(and then of course the line "virtual void onMouseDown(const GuiEvent &evt);" at the beginning of the file.)
The code for GameTSCtrl::onMouseDown is entered...
I have tried to put in some printf's (see in the example above) but no output appears in the console no matter where I try to write it. I think I have entered about 10 printf's in the code but none appear on runtime. As you described Orion I have also put a printf in the GuiCanvas::rootMouseDown(), but nothing appear here either.
Can printf's somehow be turned off, so that they does not appear in the console?
Thank you so much for your help so far. Hope you have some sugestions for what could be the problem!
/S
#139
if (Platform::SystemInfo.processor.properties & CPU_PROP_MMX)
Con::printf(" MMX detected");
to
if (Platform::SystemInfo.processor.properties & CPU_PROP_MMX){
Con::printf(" MMX detected");
Con::printf("TESTING PRINTF COMMANDS!");
}
And here is the readout from the console (After I rebuilded the engine!)
Processor Init:
Intel Pentium 4, ~2.80 Ghz
(timed at roughly 2.79 Ghz)
FPU detected
MMX detected
SSE detected
ARGGG - What is going on??
/S
10/25/2006 (1:56 am)
Something realy wierd is going on atm. To test whether my printf's are working I tried to change if (Platform::SystemInfo.processor.properties & CPU_PROP_MMX)
Con::printf(" MMX detected");
to
if (Platform::SystemInfo.processor.properties & CPU_PROP_MMX){
Con::printf(" MMX detected");
Con::printf("TESTING PRINTF COMMANDS!");
}
And here is the readout from the console (After I rebuilded the engine!)
Processor Init:
Intel Pentium 4, ~2.80 Ghz
(timed at roughly 2.79 Ghz)
FPU detected
MMX detected
SSE detected
ARGGG - What is going on??
/S
#140
I deleted the entire project and desided to start from the beginning again (download the latest version without my implementation from CVS), and now my printf commands is working. Why it works now I have no idea..
But I will try to implement the object selection again, and write back with the progress....
/Soeren..
10/25/2006 (2:45 am)
HiI deleted the entire project and desided to start from the beginning again (download the latest version without my implementation from CVS), and now my printf commands is working. Why it works now I have no idea..
But I will try to implement the object selection again, and write back with the progress....
/Soeren..
Associate Orion Elenzil
Real Life Plus
that will let you know if the problem is upstream or downstream from the ContainerRayCast call.
since ContainerRayCast is stock TGE, it seems likely that it's upstream.
i note that my (tge 1.3-based) codebase is also not using getMouse3DPos or getMouse3DVec,
but object selection is fine. so i doubt that's the issue.
also, just a side-note, but you might consider doing the raycasts entirely client-side. - this may not be appropriate for your particular use, but if it is, it'll be a lot more performant. but that's something to do after you've got the basics working! ;)