Problems with Client Side objects
by Brandon Pollet · in Torque Game Engine · 02/16/2005 (5:54 pm) · 8 replies
I have been searching for a way to do a 3d crosshair with client-side objects and while I can make a 3d crosshair with server side objects I can't make it work on the client side. Whenever I create a client side object from script(I'm working from this resource) it will appear but with no handle in the world editor. With no handle I can't access it and make it move with mouse commands like I can a server side object. Does anyone have any ideas about what I could be doing wrong? Or what I need to do instead. I've really been banging my head against the wall on this one, any help would be appreciated.
About the author
Brandon earned a Master's of Science in Computer Science from the University of Tulsa in 2005 before they asked him to leave. Since then he has worked in web development and mobile development all while honing his game design/programming skills.
#2
02/18/2005 (11:10 pm)
Thomas thanks for the reply, but I have another question. When you say that you made a new GUI component, did you create a new class that extended GuiControl, or GuiTSCtrl, or did you just add create a new instance? Sorry for the question but I have really been having trouble wrapping my mind around the engine, especially the relationship between the 'play gui' and the 3D world, if that makes any sense.
#3
I've discontinued using the code below, so there are no guarantees for it to work or not crash your engine ;-)
What this was ment to do is have a reticle when the mouse pointer is pointing at water, and when it points at something I could shoot at, it changed to a different reticle shape. Just FYI. Its not optimized or anything, but it worked in my setup
Oh - it also sends a command to the server to set a turret aim position - you might not need that part of the code at all.
02/19/2005 (2:30 am)
I made a component that extended GuiTSCtrl and put it on top of the playGui - not a replacement.I've discontinued using the code below, so there are no guarantees for it to work or not crash your engine ;-)
What this was ment to do is have a reticle when the mouse pointer is pointing at water, and when it points at something I could shoot at, it changed to a different reticle shape. Just FYI. Its not optimized or anything, but it worked in my setup
Oh - it also sends a command to the server to set a turret aim position - you might not need that part of the code at all.
#include "dgl/dgl.h"
#include "gui/guiControl.h"
#include "game/gameTSCtrl.h"
#include "console/consoleTypes.h"
#include "sceneGraph/sceneGraph.h"
#include "game/shapeBase.h"
#include "game/gameConnection.h"
#include "game/battleship/clientSideTSStatic.h"
#ifndef _NETSTRINGTABLE_H_
#include "sim/netStringTable.h"
#endif
//----------------------------------------------------------------------------
/// Displays an area marker on the water surface of where the guns are aiming
/// Parent MUST be the GameTSCtrl
///
/// This is a stand-alone control and relies only on the standard base GuiControl.
class GuiTargetAreaHud : public GuiTSCtrl {
typedef GuiControl Parent;
Point3F mOldMouseWorldPos;
Point3F mMouseWorldPos;
ClientSideTSStatic* pWaterAreaMarker;
ClientSideTSStatic* pTargetAreaMarker;
ClientSideTSStatic* pCurrentAreaMarker;
protected:
void createMarkers();
virtual void onMouseDown(const GuiEvent &evt);
virtual void onRightMouseDown(const GuiEvent &evt);
StringHandle mMouseMoveCmd;
public:
GuiTargetAreaHud();
// GuiControl
virtual void onRender(Point2I offset, const RectI &updateRect);
void onRemove();
static void initPersistFields();
DECLARE_CONOBJECT( GuiTargetAreaHud );
};
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiTargetAreaHud);
static char gMouseMoveCmdStr[128];
extern void sendRemoteCommand(NetConnection *conn, S32 argc, const char **argv);
#define MOUSE_MOVE_CMD "onNewTurretAimLocation"
GuiTargetAreaHud::GuiTargetAreaHud() : mMouseMoveCmd(MOUSE_MOVE_CMD)
{
gNetStringTable->expandString( mMouseMoveCmd, gMouseMoveCmdStr, 128, 0, NULL );
mMouseWorldPos.set(0, 0, 0);
mOldMouseWorldPos = mMouseWorldPos;
pWaterAreaMarker = NULL;
pTargetAreaMarker = NULL;
pCurrentAreaMarker = NULL;
}
void GuiTargetAreaHud::onRemove()
{
if( pCurrentAreaMarker )
{
pCurrentAreaMarker = 0;
}
if( pWaterAreaMarker )
{
pWaterAreaMarker->onRemove();
pWaterAreaMarker->deleteObject();
}
if( pTargetAreaMarker )
{
pTargetAreaMarker->onRemove();
pTargetAreaMarker->deleteObject();
}
}
void GuiTargetAreaHud::initPersistFields()
{
Parent::initPersistFields();
}
//----------------------------------------------------------------------------
/// Core rendering method for this control.
///
/// @param updateRect Extents of control.
void GuiTargetAreaHud::onRender( Point2I, const RectI &updateRect)
{
if (!pCurrentAreaMarker) {
createMarkers();
pCurrentAreaMarker = pWaterAreaMarker;
}
// Must be in a Game TS Ctrl
GameTSCtrl *parent = dynamic_cast<GameTSCtrl*>(getParent());
if (!parent) return;
// Must have a connection and control object
GameConnection* conn = GameConnection::getServerConnection();
if (!conn) return;
ShapeBase* control = conn->getControlObject();
if (!control) return;
// Collision info.
static U32 losMask = TerrainObjectType | WaterObjectType | VehicleObjectType | TurretObjectType | ShapeBaseObjectType;
control->disableCollision();
#4
This code uses some stuff from the click and pick resource, so there are other changes required to make it work. But it might give you an idea of how I made it work.
Also remember to edit the playGui.gui and remove the noCursor = 1; line - else the cursor wont show up.
02/19/2005 (2:32 am)
// Test to see if it's behind something, and we want to
// ignore anything it's mounted on when we run the LOS.
RayInfo info;
Point3F startPos = parent->getMouse3DPos();
Point3F endPos = startPos + parent->getMouse3DVec()*1000;
if (gClientContainer.collideBox(startPos, endPos ,losMask, &info))
{
mMouseWorldPos = info.point;
if ((info.object->getTypeMask() & VehicleObjectType) || (info.object->getTypeMask() & TurretObjectType) || (info.object->getTypeMask() & ShapeBaseObjectType)) {
pCurrentAreaMarker = pTargetAreaMarker;
pTargetAreaMarker->setHidden(false);
pWaterAreaMarker->setHidden(true);
} else {
pCurrentAreaMarker = pWaterAreaMarker;
pTargetAreaMarker->setHidden(true);
pWaterAreaMarker->setHidden(false);
}
}
// Move reticle to mouse position
pCurrentAreaMarker->setPosition(mMouseWorldPos);
// Now we need to inform the server of the new aim location
if (mOldMouseWorldPos != mMouseWorldPos) {
const int argc = 2;
char mousePosStr[128];
dSprintf( mousePosStr, 128, "%f %f %f", mMouseWorldPos.x, mMouseWorldPos.y, mMouseWorldPos.z );
const char* argv[argc] = { gMouseMoveCmdStr, mousePosStr };
NetConnection *connection = NetConnection::getServerConnection();
if(!connection)
{
AssertFatal( connection, "Failed to get server connection!" );
return;
}
sendRemoteCommand(connection, argc, argv);
mOldMouseWorldPos = mMouseWorldPos;
}
// Restore control object collision
control->enableCollision();
}
//----------------------------------------------------------------------------
void GuiTargetAreaHud::createMarkers()
{
pWaterAreaMarker = new ClientSideTSStatic();
pWaterAreaMarker->setField("shapeName", "game/data/shapes/reticles/water_r.dts");
// Register the Object.
if (!pWaterAreaMarker->registerObject())
{
// Problem ...
Con::errorf("Could not create water reticle");
// Destroy Shape.
delete pWaterAreaMarker;
}
pTargetAreaMarker = new ClientSideTSStatic();
pTargetAreaMarker->setField("shapeName", "game/data/shapes/reticles/target_r.dts");
// Register the Object.
if (!pTargetAreaMarker->registerObject())
{
// Problem ...
Con::errorf("Could not create target reticle");
// Destroy Shape.
delete pTargetAreaMarker;
}
}
void GuiTargetAreaHud::onMouseDown(const GuiEvent &evt) {
// Must be in a Game TS Ctrl
GameTSCtrl *parent = dynamic_cast<GameTSCtrl*>(getParent());
if (!parent) return;
parent->onMouseDown(evt, 0);
}
void GuiTargetAreaHud::onRightMouseDown(const GuiEvent &evt) {
// Must be in a Game TS Ctrl
GameTSCtrl *parent = dynamic_cast<GameTSCtrl*>(getParent());
if (!parent) return;
parent->onMouseDown(evt, 1);
}This code uses some stuff from the click and pick resource, so there are other changes required to make it work. But it might give you an idea of how I made it work.
Also remember to edit the playGui.gui and remove the noCursor = 1; line - else the cursor wont show up.
#5
02/19/2005 (9:46 am)
That is awesome Thomas, thanks. I'll start working this in right now.
#6
While this is still probably a pretty stupid question I have learned so much about the engine just from working on this target. Thanks for the help you've given me so far, it has really made things easier.
03/01/2005 (12:31 am)
Thomas, I have worked through the code you posted here but something is still not working. It seems like I am having trouble getting access to the GUIControl that I create. I can create a new GuiTargetAreaHud from script but I never get any of the desired feedback from the functions. It's like GameTSCtrl or GUITSCtrl are answering the callbacks for onMouseMove, and onRender before my GUIControl can do it. Do you have any idea what I might be missing? Is there some specific way to layer the new GUIControl ontop of the existing ones?While this is still probably a pretty stupid question I have learned so much about the engine just from working on this target. Thanks for the help you've given me so far, it has really made things easier.
#7
There can be several reasons. First and foremost - did you enable the cursor? If you didnt, then all mouse movement is caught by the movemanager and send to the control object instead of your gui component.
Secondly you need to make sure that the gui component is on top. So manually open your playGui.gui and move the section to the bottom - or do it in the editor by "bring to front". Same thing
Third option can be that your gui component isnt covering the entire gui area. Make sure its 100% in all directions and set to relative
Last thing I can think of is that the dreaded chat hud. In the playGui.cs the chatgui is pushed on top of everything else. Comment out the lines in the onWake and onSleep and try again
03/01/2005 (12:53 pm)
Hey BrandonThere can be several reasons. First and foremost - did you enable the cursor? If you didnt, then all mouse movement is caught by the movemanager and send to the control object instead of your gui component.
Secondly you need to make sure that the gui component is on top. So manually open your playGui.gui and move the section to the bottom - or do it in the editor by "bring to front". Same thing
Third option can be that your gui component isnt covering the entire gui area. Make sure its 100% in all directions and set to relative
Last thing I can think of is that the dreaded chat hud. In the playGui.cs the chatgui is pushed on top of everything else. Comment out the lines in the onWake and onSleep and try again
#8
03/01/2005 (4:18 pm)
Thomas, thanks for the quick response. I think I must be doing something wrong with the control itself. When I try to add a new GUIControl from the GUI Editor it locks up the engine. Thanks for the suggestions though, if I can figure out how to make a correct GUIControl they will come in handy.
Torque Owner Thomas \"Man of Ice\" Lund
I combined/hacked the shapename gui and the click'n'pick to move the reticle around with the mouse cursor.