Game Development Community

dev|Pro Game Development Curriculum

Mouse, Camera & Selection Combined Resource

by Ehab Yosry Amer · 09/26/2007 (12:55 pm) · 161 comments

Download Code File

This is all fully working on TGE 1.5.2 the files attached can save you a lot of time if u are starting on a fresh copy of the SDK if u replace them all over the existing ones
Edit: I'll be working on a separate resource to make this running on TGEA (1.8.1 till something more recent is out), when its ready I'll update this resource with a link for the new one :)
Before I start on the resource I would like to thank the authors of those resources for their GREAT work and help to the whole Torque community.
WoW Player Control Emulation by James Spellman
Updated Object Selection (with TLK bonus) by Rubes
GLU quadrics for Torque by James "Corvidae" Williams
Object selection in Torque by Dave Myers
Advanced Camera by Thomas "Man of Ice" Lund
TGE 1.5.x - Bonus Resource Bundle by John Kabus (BobTheCBuilder)
Multiple objects highlight by Diego Potapczuk
and Ted Southard for the help of making this compatible on TGEA

NOTE: The 1.5.x Bonus Resource Files that are in the file u downloaded from this resource works on 1.5.2 ONLY so in case u have a different version (1.5 or 1.5.1) please visit the original post of the mentioned resource to get the appropriate version of the files

How to install

If you are using a fresh copy of TGE 1.5.2 (or any 1.5.x version) u could replace all the affected files listed with the original ones, but if u already have some resources applied to ur engine (or any updates u made to the code) to the affected files mentioned then u'll (unfortunatly) will have to follow the steps (& this LOOOONNNNGGG post) to make this update
The new files that didn't exist in the project should be added

New Source Files:
enginelightingSystemguiObjectView.cc
enginelightingSystemguiObjectView.h
enginelightingSystemsgGuiExposureControl.cc
enginelightingSystemsgLightingModel.cc
enginelightingSystemsgLightManager.cc
enginelightingSystemsgLightManager.h
enginedgl/glu.h
enginedgl/glu.cc
enginedgl/gluos.h

those files should be added to ur project:
as in visual studio right click on the folder that the files should be placed in, click add existing files & select them.

In case that there is a file that u were not asked to replace while u r copying the files to ur SDK, then this is a new file and should be added to the project

Engine Files Affected:

enginegamegameTSCtrl.h
enginegamegameTSCtrl.cc
enginegameshapeBase.h
enginegameshapeBase.cc
engineguicoreguiCanvas.h
engineguicoreguiCanvas.cc
enginegameGameConnection.h
enginegame GameConnection.cc
enginesimSceneObject.h
enginesimSceneObject.cc




Step 1 gamegameTSCtrl Files
This section has the complete code to GameTSCtrl header & cc files

This is the file gamegameTSCtrl.h
BUT PLEASE NOT THE CHANGE TO BE DONE IN THE NEXT FILE IF U ARE APPLYING THIS RESOURCE ON TGEA
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

#ifndef _GAMETSCTRL_H_
#define _GAMETSCTRL_H_

#ifndef _DGL_H_
#include "dgl/dgl.h"
#endif
#ifndef _GAME_H_
#include "game/game.h"
#endif
#ifndef _GUITSCONTROL_H_
#include "gui/core/guiTSControl.h"
#endif
#ifndef _EDITTSCTRL_H_
#include "editor/editTSCtrl.h"
#endif
#ifndef _ITICKABLE_H_
#include "core/iTickable.h"
#endif

class ShapeBase;

//----------------------------------------------------------------------------
class GameTSCtrl : public GuiTSCtrl, public virtual ITickable {
private:
   typedef GuiTSCtrl Parent;

	// cursor constants
	enum {
		DefaultCursor = 0,
		HandCursor,
		UseCursor,
		MoveCursor,
		//
		NumCursors
	};

	Point3F	smCamPos;
	Gui3DMouseEvent mLastEvent;
	Point2I	lastCursor;

	bool doUpdate;	// Limits the update rate to the tick rate
	bool canDrag;	// Allows dragging only if MouseDown was on this object
	ShapeBase* mTrackObject;	// Last mouse-down object
	ShapeBase* mCursorObject;	// The object under cursor

protected:
    // These three methods are the interface for ITickable
    virtual void interpolateTick( F32 delta);
    virtual void processTick( void);
    virtual void advanceTime( F32 timeDelta);

public:
	F32	mProjectDistance;	// Distance we can select things

	GuiCursor*	mCursors[NumCursors];
	GuiCursor*	mCurrentCursor;

	GameTSCtrl( void);

   Point3F getMouse3DVec() {return mMouse3DVec;};
   Point3F getMouse3DPos() {return mMouse3DPos;}

	bool processCameraQuery( CameraQuery *query);
	void renderWorld( const RectI &updateRect);

	void onMouseDown( const GuiEvent &event);
	void onMouseUp( const GuiEvent &event);
	void onMouseMove( const GuiEvent &evt);
   void onMouseDragged( const GuiEvent &event);

	void onRightMouseDown( const GuiEvent &event);
	void onRightMouseUp( const GuiEvent &event);
   void onRightMouseDragged( const GuiEvent &event);

	void onRender( Point2I offset, const RectI &updateRect);

	DECLARE_CONOBJECT(GameTSCtrl);

	bool onAdd( void);
	static void consoleInit();

	bool grabCursors( void);
	void setCursor( U32 cursor);

	void make3DMouseEvent( Gui3DMouseEvent &gui3DMouseEvent, const GuiEvent &event);
	void on3DMouseMove( const Gui3DMouseEvent &event);

	ShapeBase* collide( const Gui3DMouseEvent &event);

	private:

   Point3F mMouse3DVec;
   Point3F mMouse3DPos;
};

#endif
& this is GameTSCtrl.cc
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

#include "game/gameTSCtrl.h"
#include "game/gameConnection.h"
#include "gui/core/guiCanvas.h"

bool useObjectHighlite = true;

//----------------------------------------------------------------------------
// Class: GameTSCtrl
//----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GameTSCtrl);

GameTSCtrl::GameTSCtrl() {
	mProjectDistance = 50.f;	// Distance we can select things

	mCursorObject = NULL;	// Last mouse-down object
	mTrackObject = NULL;		// The object under cursor
	
	doUpdate = false;	// Limits the update rate to the tick rate
	canDrag = false;	// Allows dragging only if MouseDown was on this object

   mProcessTick = true;	// Enables processTick calls
}

//---------------------------------------------------------------------------
bool GameTSCtrl::processCameraQuery( CameraQuery *camq) {
	GameUpdateCameraFov();
	bool ret = GameProcessCameraQuery( camq);

	// Record the camera's position
	camq->cameraMatrix.getColumn( 3, &smCamPos);

	return ret;
}

//---------------------------------------------------------------------------
void GameTSCtrl::renderWorld( const RectI &updateRect) {
   GameRenderWorld();
   dglSetClipRect( updateRect);
}

void GameTSCtrl::make3DMouseEvent(Gui3DMouseEvent & gui3DMouseEvent, const GuiEvent & evt) {
	(GuiEvent&)(gui3DMouseEvent) = evt;

	// get the eye pos and the mouse vec from that...
	Point3F sp( evt.mousePoint.x, evt.mousePoint.y, 1);

	Point3F wp;
	unproject( sp, &wp);

	gui3DMouseEvent.pos = smCamPos;
	gui3DMouseEvent.vec = wp - smCamPos;
	gui3DMouseEvent.vec.normalize();
}

//---------------------------------------------------------------------------

void GameTSCtrl::onMouseDown( const GuiEvent &evt) {
	lastCursor = Canvas->getCursorPos();
	canDrag = true;

	// Get a new Cursor Object
	make3DMouseEvent( mLastEvent, evt);
	on3DMouseMove( mLastEvent);

	// New Track Object
	mTrackObject = (ShapeBase*)mCursorObject;

	if (mTrackObject)
		setCursor( UseCursor);

	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);
      //------------NOTE IF U ARE APPLYING THIS ON TGEA SET THE VALUE TO 1 NOT -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();

         //did we click more than once?
         S32 doubleClick = (evt.mouseClickCount > 1)?1:0;

         //call client script handler
         Con::executef(this, 2, "onMouseDown", Con::getIntArg(doubleClick));
      }
   }
}

void GameTSCtrl::onMouseUp( const GuiEvent &evt) {	
	// Restore last cursor position
	if (canDrag) {
		Canvas->setCursorPos( lastCursor);
		canDrag = false;
	}
	
	// Keep hand cursor if we've got a Cursor Object
	if (mCursorObject)
		setCursor( HandCursor);
	else
		setCursor( DefaultCursor);
}

void GameTSCtrl::onMouseDragged( const GuiEvent &evt) {
	if (canDrag) {
	
		static const char *argv[2];
		Point2I diff( evt.mousePoint - lastCursor);
	
		// Use Move Cursor if moving
		if (!diff.isZero()) {
			setCursor( MoveCursor);
			
			// If you don't want to continue tracking, use the following:
			// mTrackObject = NULL;
		}
	
		// Perform script-based yaw and pitch callbacks
		if (diff.x) {
			argv[0] = "yaw";
			argv[1] = Con::getFloatArg( diff.x);
			Con::execute( 2, argv);
		}
		if (diff.y) {
			argv[0] = "pitch";
			argv[1] = Con::getFloatArg( diff.y);
			Con::execute( 2, argv);
		}
	
		// HACK - Have GuiCanvas skip next MouseMoveEvent
		Canvas->ignoreNextMove = true;
		Canvas->setCursorPos( lastCursor);
	}
}

void GameTSCtrl::onMouseMove( const GuiEvent &evt) {
	if (doUpdate && useObjectHighlite) {
		doUpdate = false;
	
		// Get a new Cursor Object
		make3DMouseEvent( mLastEvent, evt);
		on3DMouseMove( mLastEvent);

		// Restore Default Cursor if no selectable object under the cursor		
		if (!mCursorObject)
			setCursor( DefaultCursor);
	}
}

//---------------------------------------------------------------------------

void GameTSCtrl::onRightMouseDown( const GuiEvent &evt) {
	lastCursor = Canvas->getCursorPos();
	canDrag = true;

	// Get a new Cursor Object
	make3DMouseEvent( mLastEvent, evt);
	on3DMouseMove( mLastEvent);

	// New Track Object
	mTrackObject = (ShapeBase*)mCursorObject;
	
	if (mTrackObject)
		setCursor( UseCursor);
}

void GameTSCtrl::onRightMouseUp( const GuiEvent &evt) {
	make3DMouseEvent( mLastEvent, evt);
	on3DMouseMove( mLastEvent);

	if (mTrackObject) {
		// Use only objects we've tracked
		if (mTrackObject == mCursorObject)
			mTrackObject->onUse();
		else
			mTrackObject = NULL;
	}

	// Restore last cursor position
	if (canDrag) {
		Canvas->setCursorPos( lastCursor);
		canDrag = false;
	}
	
	// Keep hand cursor if we've got a Cursor Object
	if (mCursorObject)
		setCursor( HandCursor);
	else
		setCursor( DefaultCursor);
}

void GameTSCtrl::onRightMouseDragged( const GuiEvent &evt) {
	onMouseDragged( evt);
}

void GameTSCtrl::onRender( Point2I offset, const RectI &updateRect) {
	CameraQuery camq = mLastCameraQuery;

	// check if should bother with a render
	GameConnection * con = GameConnection::getConnectionToServer();
	bool skipRender = !con || (con->getWhiteOut() >= 1.f) || (con->getDamageFlash() >= 1.f) || (con->getBlackOut() >= 1.f);

	if (!skipRender)
		Parent::onRender( offset, updateRect);

	dglSetViewport( updateRect);

	if (GameProcessCameraQuery( &camq))
		GameRenderFilters( camq);

	// Draw controls after so they aren't affected by the filters. (If we're doing that.)
	if (!skipRender && !mApplyFilterToChildren)
		Parent::renderChildControls( offset, updateRect);
}

static const char* cGetMouse3DVec(SimObject *ptr, S32 argc, const char **argv)
{
   GameTSCtrl* obj = static_cast<GameTSCtrl*>(ptr);

   char* retBuffer = Con::getReturnBuffer(256);
   const Point3F &vec = obj->getMouse3DVec();
   dSprintf(retBuffer, 256, "%g %g %g", vec.x, vec.y, vec.z);
   return retBuffer;
}

static const char* cGetMouse3DPos(SimObject *ptr, S32 argc, const char **argv)
{
   GameTSCtrl* obj = static_cast<GameTSCtrl*>(ptr);

   char* retBuffer = Con::getReturnBuffer(256);
   const Point3F &pos = obj->getMouse3DPos();
   dSprintf(retBuffer, 256, "%g %g %g", pos.x, pos.y, pos.z);
   return retBuffer;
}

void GameTSCtrl::consoleInit()
{
   Con::addCommand("GameTSCtrl", "getMouse3DVec", cGetMouse3DVec, "GameTSCtrl.getMouse3DVec();", 2, 2);
   Con::addCommand("GameTSCtrl", "getMouse3DPos", cGetMouse3DPos, "GameTSCtrl.getMouse3DPos();", 2, 2);
}

bool GameTSCtrl::grabCursors() {
	struct _cursorInfo {
		U32 index;
		const char * name;
	} infos[] = {
		{ DefaultCursor,	"DefaultCursor" },
		{ HandCursor,	"HandCursor" },
		{ UseCursor,	"UseCursor" },
		{ MoveCursor,	"MoveCursor" }
	};

	//
	for(U32 idx = 0; idx < (sizeof(infos) / sizeof(infos[0])); idx++) {
		SimObject * obj = Sim::findObject(infos[idx].name);
		if (!obj) {
			Con::errorf(ConsoleLogEntry::Script, "GameTSCtrl::grabCursors: failed to find cursor '%s'.", infos[idx].name);
			return(false);
		}

		GuiCursor *cursor = dynamic_cast<GuiCursor*>(obj);
		if(!cursor) {
			Con::errorf(ConsoleLogEntry::Script, "GameTSCtrl::grabCursors: object is not a cursor '%s'.", infos[idx].name);
			return(false);
		}

		//
		mCursors[infos[idx].index] = cursor;
	}

	//
	mCurrentCursor = mCursors[DefaultCursor];
	
	return true;
}

void GameTSCtrl::setCursor( U32 cursor) {
	AssertFatal(cursor < NumCursors, "GameTSCtrl::setCursor: invalid cursor");

	mCurrentCursor = mCursors[cursor];
	Canvas->setCursor( mCurrentCursor);
}

ShapeBase* GameTSCtrl::collide( const Gui3DMouseEvent &event) {
   GameConnection* conn = GameConnection::getConnectionToServer();
	if (!conn)
		return false;

	SceneObject* controlObj = conn->getControlObject();
	if (controlObj)
		controlObj->disableCollision();

	//
	Point3F startPnt = event.pos;
	Point3F endPnt = event.pos + event.vec * mProjectDistance;

	//
   static U32 losMask = TerrainObjectType | InteriorObjectType | ShapeBaseObjectType;
	RayInfo ri;
	bool hit = gClientContainer.castRay( startPnt, endPnt, losMask, &ri);

	if (controlObj)
		controlObj->enableCollision();

	if (hit && (ri.object->getTypeMask() & ShapeBaseObjectType))
		return (ShapeBase*)ri.object;
	else
		return NULL;
}

bool GameTSCtrl::onAdd() {
	if (!Parent::onAdd())
		return false;

	// grab all the cursors
	if (!grabCursors())
		return false;

	return true;
}

void GameTSCtrl::on3DMouseMove( const Gui3DMouseEvent & event) {
	if (mCursorObject = collide( event)) {
		// Set Hand Cursor over selectable objects
		if (mCursorObject->IsSelectable())
			setCursor( HandCursor);
		else
			mCursorObject = NULL;
	}
	
	ShapeBase::setHighlighted( mCursorObject);
}

// These three methods are the interface for ITickable
void GameTSCtrl::interpolateTick( F32 delta) {
}

void GameTSCtrl::processTick() {
	// Attempt to provide better performance by limiting the rate collisions are tested
	doUpdate = true;
}

void GameTSCtrl::advanceTime( F32 timeDelta) {
}
The file is almost the same as the one posted in the WoW controls emulation resource except that it has a part from the Object selection resource in the function on mouse down (its actually a merge with no edits although I'm sure that there is much in common in them & it can be optimized) plus some other slight changes to function & variable names from the later resource as they were already applied from the first.
Step 2 GameShapeBase Files
In the file shapeBase.h at the line 850 (approx) add the following
static U32 sLastRenderFrame;
   U32 mLastRenderFrame;
   F32 mLastRenderDistance;
   U32 mSkinHash;

[b] // object selection
	bool isSelectable;
	static ShapeBase* highlighted;
	static ShapeBase* selected;
        bool mHighlighted; [/b]

   /// This recalculates the total mass of the object, and all mounted objects
   void updateMass();
in the same file at 954 add
public:
   ShapeBase();
   ~ShapeBase();

   [b]void setHighlight(bool highlight);
   bool isHighlight();[/b]

   TSShapeInstance* getShapeInstance() { return mShapeInstance; }
In the same file at 1510 add
/// Sets the FOV for this object if used as a camera
   virtual void setCameraFov(F32 fov);

   /// Returns true if the FOV supplied is within allowable parameters
   /// @param   fov   FOV to test
   virtual bool isValidCameraFov(F32 fov);
   /// @}

   [b]bool IsSelectable( void) { return isSelectable; };
   
	static void setSelected( ShapeBase* obj);
   static void setHighlighted( ShapeBase* obj);
   
  	virtual void onSelect( void);
	virtual void onDeselect( void);
   virtual void onUse( void);[/b]

   void processTick(const Move *move);
   void advanceTime(F32 dt);
In shapeBase.cc make sure that you include
[b]#include "dgl/glu.h"[/b]
And at about 40 add
F32  ShapeBase::sWhiteoutDec = 0.007;
F32  ShapeBase::sDamageFlashDec = 0.007;
U32  ShapeBase::sLastRenderFrame = 0;

[b]ShapeBase* ShapeBase::highlighted = NULL;
ShapeBase* ShapeBase::selected = NULL;[/b]

static const char *sDamageStateName[] =
{
   // Index by enum ShapeBase::DamageState
   "Enabled",
   "Disabled",
   "Destroyed"
};
At the end of the shapeBase constructor add
mFadeOut = true;
   mFading = false;
   mFadeVal = 1.0;
   mFadeTime = 1.0;
   mFadeElapsedTime = 0.0;
   mFadeDelay = 0.0;
   mFlipFadeVal = false;
   mLightTime = 0;
   damageDir.set(0, 0, 1);

   [b]isSelectable = true;
   mHighlighted = false;[/b]
}
The Add the following code just before the function ProcessTick in the class shapeBase
[b]
//----------------------------------------------------------------------------

void ShapeBase::setSelected( ShapeBase* obj) {
	if (selected == obj)
		return;

	if (selected && (selected != obj))
		selected->onDeselect();
	
	selected = obj;
	
	if (selected)
		selected->onSelect();
}

void ShapeBase::setHighlighted( ShapeBase* obj) {
	highlighted = obj;
}

void ShapeBase::onSelect() {
	Con::printf( "Object Selected");

	Con::executef( this, 1, "onSelect");
}

void ShapeBase::onDeselect() {
	Con::printf( "Object Deselected");

	Con::executef( this, 1, "onDeselect");
}

void ShapeBase::onUse() {
	Con::printf( "Use Object");

	Con::executef( this, 1, "onUse");
}

void ShapeBase::setHighlight(bool highlight) { 
      mHighlighted = highlight;
      setMaskBits(ShieldMask);
   }

   bool ShapeBase::isHighlight() { 
      return mHighlighted;
   }

ConsoleMethod( ShapeBase, setHighlight, void, 3, 3, "(bool highlight)")
{
   object->setHighlight(dAtob(argv[2]));
}

ConsoleMethod( ShapeBase, isHighlight, bool, 2, 2, "")
{
   return object->isHighlight();
}
[/b]
In the function ShapeBase::renderObject(..) add the following
void ShapeBase::renderObject(SceneState* state, SceneRenderImage* image)
{
   PROFILE_START(ShapeBaseRenderObject);
   AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");

   RectI viewport;
   dglGetViewport(&viewport);

[b]
   // Object selection additions
   // if we have been selected, then render us with a brighter light.
   // Must be called just prior to the call to installLights().
   
   GameConnection* conn = GameConnection::getConnectionToServer();
   ShapeBase* selectedObj = NULL;
   
   if (conn)
   	   selectedObj = conn->getSelectedObject();
   
   S32 selectedId = -1;
   
   if (selectedObj != NULL)
	   selectedId = selectedObj->getId();

   if (getId() == selectedId)
   {
	quadric = gluNewQuadric();
   	glPushMatrix();
	dglMultMatrix(&getRenderTransform());
	gluQuadricDrawStyle(quadric, GL_FILL);
	gluQuadricNormals(quadric, GL_SMOOTH);
	glColor3f(0, 1, 0);
	gluDisk(quadric, 0.9, 1.1, 32, 1);
	glPopMatrix();
   }

   if (highlighted == this)
	   LightManager::sgGlobalBlendColor = ColorF( 5.0, 5.0, 5.0, 5.0);

if(mHighlighted == true)
   {
	   LightManager::sgGlobalBlendColor = ColorF( 3.0, 3.0, 3.0, 3.0);
   }[/b]

   gClientSceneGraph->getLightManager()->sgSetupLights(this);

   glMatrixMode(GL_PROJECTION);
   glPushMatrix();
   state->setupObjectProjection(this);

   // This is something of a hack, but since the 3space objects don't have a
   //  clear conception of texels/meter like the interiors do, we're sorta
   //  stuck.  I can't even claim this is anything more scientific than eyeball
   //  work.  DMM
In the same function at about line 2430 add the following
glMatrixMode(GL_MODELVIEW);
   dglSetViewport(viewport);

   gClientSceneGraph->getLightManager()->sgResetLights();

   // MAR: need to reset this so that other non-selectable objects (like TSSTatics) don't get rendered brightly
   // since this doesn't get reset automatically for those objects
[b]
   LightManager::sgGlobalBlendColor = ColorF(1.0, 1.0, 1.0, 1.0);

[/b]
   // Debugging Bounding Box
   if (!mShapeInstance || gShowBoundingBox) {
      glDisable(GL_DEPTH_TEST);
      Point3F box;

in the function packupdate add the bold line
if (stream->writeFlag(mask & ShieldMask)) {
         stream->writeNormalVector(mShieldNormal, ShieldNormalBits);
         stream->writeFloat( getEnergyValue(), EnergyLevelBits );
      }

	  [b]stream->writeFlag(mHighlighted);[/b]

      if (stream->writeFlag(mask & InvincibleMask)) {
         stream->write(mInvincibleTime);
         stream->write(mInvincibleSpeed);
      }

& in function unpackupdate add the bold code
f(stream->readFlag())     // ShieldMask
      {
         // Cloaking, Shield, and invul masking
         Point3F shieldNormal;
         stream->readNormalVector(&shieldNormal, ShieldNormalBits);
         F32 energyPercent = stream->readFloat(EnergyLevelBits);
      }

	 [b] if (stream->readFlag())
		  mHighlighted = true;
	  else
		  mHighlighted = false; [/b]

      if (stream->readFlag()) {  // InvincibleMask
         F32 time, speed;
         stream->read(&time);
         stream->read(&speed);
         setupInvincibleEffect(time, speed);
      }
Step 3 GuiCoreGuiCanvas Files
As for the file GuiCanvas.h around line 143 add this
public:
	[b]bool ignoreNextMove;	// Force next MouseMoveEvent to be ignored[/b]
   DECLARE_CONOBJECT(GuiCanvas);
   GuiCanvas();
   virtual ~GuiCanvas();
In GuiCanvas.cc around 233
mShowCursor = true;
   rLastFrameTime = 0.0f;
	[b]ignoreNextMove = false;[/b]

   mMouseCapturedControl = NULL;
   mMouseControl = NULL;
Add these lines at the very start of the function
void GuiCanvas::processMouseMoveEvent(const MouseMoveEvent *event)
if (ignoreNextMove) {
		ignoreNextMove = false;
		return;
	}
Step 4 GameGameConnection Files
In GameConnection.h add the bold lines around line 86
void moveWritePacket(BitStream *bstream);
   void moveReadPacket(BitStream *bstream);

   [b]///object selection additions
   SimObjectPtr<ShapeBase> mSelectedObj;//pointer to our selected object
   //SimObjectPtr<ShapeBase> mClickedObj;//pointer to our Clicked object
   bool mChangedSelectedObj; //flag used to determine if we have changed our selected object
   //bool mChangedClickedObj; //flag used to determine if we have changed our Clicked object
   /// @}[/b]
public:
	[b]///object selection additions
   void setSelectedObject(ShapeBase *so) { mSelectedObj = so; mChangedSelectedObj = true; }
   ShapeBase* getSelectedObject()  { return  mSelectedObj; }
   void clearSelectedObject() { mSelectedObj = NULL; mChangedSelectedObj = true; }
   bool hasChangedSelectedObject() { return mChangedSelectedObj; }
void setDeselectObj()  { mSelectedObj = NULL; mChangedSelectedObj = true; } //<------ ADD 
[/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 compatibility by
   /// specifying a MinRequireProtocolVersion.  If the client
   /// protocol is >= this min value, the connection is accepted.
And in GameConnection.cc add those lines in the line 74 approx.
//blackout vars
   mBlackOut = 0.0f;
	mBlackOutTimeMS = 0;
	mBlackOutStartTimeMS = 0;
	mFadeToBlack = false;

	[b]//object selection additions
   mSelectedObj = NULL;
   mChangedSelectedObj = false;[/b]
And add the following code anywhere (but better before the function " ConsoleMethod( GameConnection, isAIControlled, bool, 2, 2, "") ")
[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;
}

//--------------------------------------------------------------------------
// object selection additions
//--------------------------------------------------------------------------
ConsoleMethod( GameConnection, clearSelectedObject, void, 2, 2, "()")
{ 
	object->clearSelectedObject(); 
}
[/b]
Before the function "void GameConnection::consoleInit()" add the following, and update that function as shown
[b]
static bool cSetSelectedObj(SimObject *obj, S32, const char **argv)
{
   GameConnection *cptr = (GameConnection *) obj;
   ShapeBase *gb;
   if(!Sim::findObject(argv[2], gb))
      return false;

   cptr->setSelectedObject(gb);
   return true;
}

static int cGetSelectedObj(SimObject *obj, S32, const char **argv)
{
   GameConnection *cptr = (GameConnection *) obj;
   SimObject* cp = cptr->getSelectedObject();
   return cp? cp->getId(): 0;
}
static bool cDeselectObj(SimObject *obj, S32, const char **argv)
{
	GameConnection *cptr = (GameConnection *) obj;
	cptr->setDeselectObj();
		return true;
}

 [/b]

//--------------------------------------------------------------------------
void GameConnection::consoleInit()
{
   Con::addVariable("Pref::Net::LagThreshold", TypeS32, &mLagThresholdMS);
   Con::addVariable("specialFog", TypeBool, &SceneGraph::useSpecial);

[b]Con::addCommand("GameConnection", "setSelectedObj", cSetSelectedObj, "conn.setSelectedObj(%obj)", 3, 3);
   Con::addCommand("GameConnection", "getSelectedObj", cGetSelectedObj, "conn.getSelectedObj()", 2, 2);
   Con::addCommand("GameConnection", "DeselectObj", cDeselectObj, "conn.DeselectObj()", 2, 2);

[/b]
}
In the function GameConnection::readPacket(...) add this code
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]
And in writepacket add this
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]
Step 5 SimSceneObject Files
In the file sceneObject.cc around the line 140, change the function declaration to
[b]ConsoleFunction( containerRayCast, const char*, 4, 6, "( Point3F start, Point3F end, bitset mask, SceneObject exempt1=NULL SceneObject exempt2=NULL)"[/b]
& add this in the same function
SceneObject* pExempt = NULL;
   [b]SceneObject* pExempt2 = NULL;[/b]
if (argc > 4) {
      U32 exemptId = dAtoi(argv[4]);
      Sim::findObject(exemptId, pExempt);
   }
   if (pExempt)
      pExempt->disableCollision();

   [b]if (argc > 5) {
      U32 exemptId = dAtoi(argv[5]);
      Sim::findObject(exemptId, pExempt2);
   }
   if (pExempt2)
      pExempt2->disableCollision();[/b]

   RayInfo rinfo;
   S32 ret = 0;
   if (gServerContainer.castRay(start, end, mask, &rinfo) == true)
      ret = rinfo.object->getId();

   if (pExempt)
      pExempt->enableCollision();

   [b]if (pExempt2)
      pExempt2->enableCollision();[/b]
Step 6 GameFPSGuiShapeNameHud
Add this line in engine/game/fps/guishapeNameHud.cc anywhere in the public area
[b]
virtual void onMouseDown(const GuiEvent &evt);
[/b]
And this at the end of the file
[b]
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]
Script Changes
Step 7 default.bind.cs
Comment out those lines
moveMap.bind( keyboard, s, movebackward);
moveMap.bind( keyboard, space, jump);
[b]//moveMap.bind( mouse, xaxis, yaw);
//moveMap.bind( mouse, yaxis, pitch);[/b]
And those lines too
$mvTriggerCount1++;
}

[b]//moveMap.bind( mouse, button0, mouseFire );
//moveMap.bind( mouse, button1, altTrigger );[/b]
Add those lines anywhere
[b]$cameraYawSpeed = -75.0;
$cameraPitchSpeed = -37.0;
$cameraZoomSpeed = -10.0;[/b]
And update these as follows
function yaw(%val)
{
    
   [b]$advCamera::Yaw = getMouseAdjustAmount(%val)*$cameraYawSpeed ;[/b]
   $mvYaw += getMouseAdjustAmount(%val);
}

function pitch(%val)
{
    [b]$advCamera::Pitch = getMouseAdjustAmount(%val)*$cameraPitchSpeed;[/b]
   $mvPitch += getMouseAdjustAmount(%val);
}

function jump(%val)
{
   $mvTriggerCount2++;
}

[b]function zoomCamera(%val)
{
     $advCamera::Zoom = getMouseAdjustAmount(%val)*$cameraZoomSpeed;
}[/b]

moveMap.bind( keyboard, a, moveleft );
moveMap.bind( keyboard, d, moveright );
moveMap.bind( keyboard, w, moveforward );
moveMap.bind( keyboard, s, movebackward );
moveMap.bind( keyboard, space, jump );
moveMap.bind( mouse, xaxis, yaw );
moveMap.bind( mouse, yaxis, pitch );
[b]moveMap.bind( mouse, zaxis, zoomCamera );[/b]
Step 8 defaultGameProfiles.cs
Add those lines anywhere
[b]
//--------------------------------------
// Cursors

new GuiCursor( HandCursor) {
   hotSpot = "1 1";
   renderOffset = "0 0";
   bitmapName = "./CUR_hand";
};

new GuiCursor( UseCursor) {
   hotSpot = "1 1";
   renderOffset = "0 0";
   bitmapName = "./CUR_grab";
};

new GuiCursor( MoveCursor) {
   hotSpot = "1 1";
   renderOffset = "0 0";
   bitmapName = "./CUR_Blank";
};[/b]
Step 9 PlayGUI.gui
Update the following line
forceFOV = "0";
      helpTag = "0";
      [b]noCursor = "0";[/b]
At the end delete both the config.cs files OR if u would like u could add the keybindings with ur hands (like I usually do) :D :D
Step 10 playGUI.cs (NOT .GUI)
Add this function anywhere
[b]
function PlayGui::onMouseDown(%this, %doubleClick)
{
   // 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, %doubleClick);
}[/b]
step 11 camera.cs
Add this datablock to the camera script file in server/scripts
[b]
datablock AdvancedCameraData(AdvCameraData)
{
   lookAtOffset = "0 0 2";
   thirdPersonOffset = "0 -3 3";
   godViewOffset = "0 -20 20";
   maxTerrainDiff = 2;
   orbitMinMaxZoom = "5 100";
   orbitMinMaxDeclination = "10 80";
   damping = 0.25;

};[/b]

Step 12 game.cs
Is server/scripts/directory, the script file game.cs, the function "GameConnection::onClientEnterGame" add the following in the first thing
[b]// create advanced camera
      %this.advCamera = new AdvancedCamera() {
      dataBlock = AdvCameraData;
   };
   MissionCleanup.add(%this.advCamera);
   %this.advCamera.scopeToClient(%this); [/b]
& in function "GameConnection::onClientLeaveGame" add this
[b]if (isObject(%this.advCamera))

      %this.advCamera.delete();[/b]
& in "createPlayer" add this at the end
[b]
%newPos = %player.getEyeTransform();
   %this.advCamera.setTransform(%newPos);
// We set the camera system to run in 3rd person mode around the %player
  %this.advCamera.setPlayerObject(%player);
  %this.advCamera.setThirdPersonMode();
  %this.advCamera.setFollowTerrainMode(false);
  %this.advCamera.setVerticalFreedomMode(false);
  %this.setCameraObject(%this.advCamera); [/b]
In "GameConnection::onDeath" add
[b]
// clear connections camera
   %this.advCamera.clearPlayerObject();
   %this.advCamera.clearTargetObject();
   %this.clearCameraObject();[/b]
step 13 server/scripts/Commands.cs
Add this function anywhere in the script file
[b]
function serverCmdSelectObject(%client, %mouseVec, %cameraPoint, %doubleClick)
{
   //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.setSelectedObj(%targetObject);
if (%doubleClick)
        {
//A DOUBLE CLICK IS DETECTED, DO WHAT U WANT HERE
//THE SINGLE CLICK IS ACCEPTED & IF THERE IS A DOUBLE CLICK IS FOUND THE CODE IN THIS BLOCK 
//(UNDER THE IF CONDITION WILL BE EXECUTED)
        }
   }
}
[/b]


Optional Steps
since this is .. well a combined resource those are a couple of resources that would help u design a RPG game
1- The Flight Compendium by Bruno Grieco
plus a fix for the wheeled vehicles Vehicle Steering Upgrade by James Jacoby
It allows the AI players to driver any wheeled vehicle.
Plz refer to the original resource for the script changes u need, the engine changes are complete in the accompanied resource
2- guiHealthBarHUD Advanced by Dreamer
it allows the original GuiHealthBarHud to display the health of another Player (or object), u'll need to set the object to display its health when u create it, otherwise it will display the health of the control Object (if I remember it right) but anyway, plz check the original resource for the script changes
3- Basic TerrainDeformer Object for Torque by Robert Brower
It allows u to change the service of the terrain from script like making explosives make crates in the ground & stuff like that. plz visit the original post.
I didn't actually try it yet, but I'm sure that it will be very helpful
4-Add Radial Force and Vorticity to PhysicalZone by Orion Elenzil
it adds radial physical zones to the game.
NOTE: to add it please uncomment the line or add it if u dont have it
if (pz->isActive()) {
      shape->mGravityMod   *= pz->getGravityMod();
      shape->mAppliedForce += pz->getForce();
	  [b]//shape->mAppliedForce += pz->getRadialForce(shape->getPosition());//in line 1320 [b]
I didn't actually try it yet, but I'm sure that it will be very helpful

& I just wanted to add them in the resource to my reference

if there is anything u couldn't get to work plz post it on this resource if u couldn't find a solution on the original resource, they are all working so if there is something wrong then it will probably be my fault.
I hope this proves to be helpful (& I'm sorry its this big :D)

About the author

Recent Blogs

Page «Previous 1 2 3 4 5 6 7 Last »
#1
09/24/2007 (11:26 am)
WOOT! Thank you Ehab! This is wicked sick! Excellent work!
#2
09/24/2007 (11:39 am)
did u run through any problems applying the resource ? or u replaced the files directly ?? even if so, any problems ??
#3
09/25/2007 (9:57 am)
I put all the resources into the proper places and tried to rebuild and got a couple errors.

Linking...
shapeBase.obj : warning LNK4229: invalid directive '/OPT:NOWIN98' encountered; ignored
shapeBase.obj : error LNK2019: unresolved external symbol "void __stdcall gluDisk(struct GLUquadric *,double,double,int,int)" (?gluDisk@@YGXPAUGLUquadric@@NNHH@Z) referenced in function "public: virtual void __thiscall ShapeBase::renderObject(class SceneState *,class SceneRenderImage *)" (?renderObject@ShapeBase@@UAEXPAVSceneState@@PAVSceneRenderImage@@@Z)
shapeBase.obj : error LNK2019: unresolved external symbol "void __stdcall gluQuadricNormals(struct GLUquadric *,unsigned int)" (?gluQuadricNormals@@YGXPAUGLUquadric@@I@Z) referenced in function "public: virtual void __thiscall ShapeBase::renderObject(class SceneState *,class SceneRenderImage *)" (?renderObject@ShapeBase@@UAEXPAVSceneState@@PAVSceneRenderImage@@@Z)
shapeBase.obj : error LNK2019: unresolved external symbol "void __stdcall gluQuadricDrawStyle(struct GLUquadric *,unsigned int)" (?gluQuadricDrawStyle@@YGXPAUGLUquadric@@I@Z) referenced in function "public: virtual void __thiscall ShapeBase::renderObject(class SceneState *,class SceneRenderImage *)" (?renderObject@ShapeBase@@UAEXPAVSceneState@@PAVSceneRenderImage@@@Z)
shapeBase.obj : error LNK2019: unresolved external symbol "struct GLUquadric * __stdcall gluNewQuadric(void)" (?gluNewQuadric@@YGPAUGLUquadric@@XZ) referenced in function "public: virtual void __thiscall ShapeBase::renderObject(class SceneState *,class SceneRenderImage *)" (?renderObject@ShapeBase@@UAEXPAVSceneState@@PAVSceneRenderImage@@@Z)
../example/torqueDemo.exe : fatal error LNK1120: 4 unresolved externals


I suppose I should mention:
Before applying this resource, I DID have a previous resource installed (The WoW Emulation Resource that you used in this compiled resource). However, I took what you have uploaded and wrote OVER all of my engine codes (I made a backup first). I didn't mention this before because all of your files wrote over mine so it should work just like a clean install. If this is the problem though, I certainly can try again on a clean install of Torque.
#4
09/25/2007 (10:15 am)
try to cleanup then rebuild, that might solve this problem, its not a syntax error, it is just a problem linking the compiled files together.
& abt the resource u already have; no its not a problem at all
#5
09/25/2007 (11:53 am)
In Visual Studio, I had to go into my "Solution Explorer" and right click the "dgl" folder and choose Add->Existing... and then open the 3 glu files. I thought that was a little crazy...

Ok so after applying this to a clean install, everything compiled ok. I am going to be testing it out soon to verify functionality and will get back to you.
#6
09/25/2007 (12:04 pm)
no man, thats not crazy
thats actually the way it is done, if u r adding a file that doesn't exist in the project u'll have to add it in, so its better to add the files in their specified folder 1st then add them in the project, so as to keep everything grouped together & not have the C++ files scattered around on ur computer.

I'll probably be updating the resource in the next few days to allow having a left & right click game interface, like having a script for onmouseodown which is already there, and another for onRightMouseDown too, but its nothing to worry abt its a minor change, but I'm a ltl busy to fix right now.

OH and btw u'll need to add the AdvancedCamera files too, same way as the dgl files, but in the game folder in the SDK, dont forget that !!
#7
09/25/2007 (12:14 pm)
Can you do the WoW method of "onBOTHMouseDown" to make the character move?
#8
09/25/2007 (12:29 pm)
onBothMouseDown ?? well I think that its possible although its not usual to have such an input.
but there will usually be a onMouseDown OR onRightMouseDown before it
oh & u reminded me of something btw, I fixed the engine code for a doubleClick but I didn't fix that in the script i posted, check the post again @ step 12 after 5 mins it should be updated
#9
09/25/2007 (12:32 pm)
So like maybe:

onMouseDown
{
onRightMouseDown
{
moveMyGuy()
}
}

pseudo-code of course :D
#10
09/25/2007 (12:44 pm)
steps 10 & 13 are modified, they are script changes in playgui.cs & commands.cs
this should give u the double click.

no its going to be like (let this be something like a sequence of execution)
onMouseDown OR onRightMouseDown
|
V
onBothMouseDown (to do wat u want abt it)

but I strongly advice not to seriously consider such an input, there is always the middle mouse button instead !!
I'll look into it if there is even something to do with the middle click, but still u have 4 inputs already !!
left click, left click x2
right click and right click x2 (coming soon, I'll do my best to make them be finished by tomorrow or something)
u still need more mouse inputs ??
#11
09/25/2007 (12:47 pm)
no i was only wondering if it was possible to make the character move the direction it is facing when both mouse clicks are held down together as it works that way in WoW. No, I am not doing a remake of WoW, but I really do like being able to play the entire game with nothing but the mouse. (And yet at the same time I am a huge keyboard 'hotkey' fan :P )

If this is too much to ask, don't worry about it. :)

Middle Mouse button would be good, I am only thinking about those poor folks living in the past without a middle mouse button...
#12
09/25/2007 (1:02 pm)
I'll give it a shot & will tell u as soon as I'm done with it. I think i have an idea of how to get it functional
#13
09/25/2007 (1:16 pm)
Ok SWEET! Everything in this resource is working. I do have a problem with it though. LOL!

Before adding the resource, I had the camera forced to 3rd person view with the toggleFirstPerson commented out. Now, it starts in 1st person instead of 3rd and I still can't toggle out, so I am stuck in the wrong view :P
#14
09/25/2007 (1:33 pm)
double check step 12, its almost related to the advanced camera, if u still have a problem plz post the function createplayer, in the file game.cs so I could check it with u
#15
09/25/2007 (2:06 pm)
I redid everything in step 12 and I am still stuck on first person view...
#16
09/25/2007 (4:05 pm)
I've updated step 12:
in createplayer function add those 2 lines before u setup the camera in this function (as shown above) or after
%player.setTransform(%spawnPoint);
%newPos = %player.getEyeTransform();
   %this.advCamera.setTransform(%newPos);

c if this helps, I've tried it here & the 3rd person view didn't work from the 1st time, & that actually fixed something in the orbit mode, something that didn't look very good which is the camera comes from a VVVEEEERRRRYYYYYY far away place till it reaches the character, & while its traveling it sometimes moves underground, but thats fixed now
#17
09/26/2007 (6:38 am)
I completely UN-did everything from step 12 and I am still stuck in 1st person view.

I put it all back in and no change either. Since it isn't working either way, I'd rather just get it fixed.

If I use Alt+C I can toggle to the observer cam, but my view twitches and I cannot control it. Toggling back to the player allows me to move/look around as normal. If I push F11, I can see the advCamera positioned right above the player1 spawn point, but it does not follow the player. It doesn't seem to have any kind of link at all to the player.

If I completely comment out the observer cam, I cannot toggle to it with Alt+C and the advCamera still does nothing, so I put that back in, but I left out the scopeToClient for the observer cam since the advCamera already does that.
#18
09/26/2007 (6:42 am)
yes, I figured out what the problem is, I accidentally removed a couple of console function while i was working on the resource, which are isFirstPerson() & setFirstPerson(bool) in the gameconnection.cc file
plz check the attached file contents & replace that file after 1 min till I update it

sorry for the inconvenience :)
#19
09/26/2007 (7:42 am)
LOL! I kinda thought that's what happened too, but like I told you, I never had explicit C++ training, so I didn't really want to look at those *.cc files.

Anyway, I am rebuilding the engine with the fixed gameConnection.cc file and I will let you know.

BTW, I did notice that trying to toggle into 1st person mode manually with the console, it is telling me it can't find the function setFirstPerson. I assume this is because of the gameConnection.cc problem, but I thought I'd mention it just in case.
#20
09/26/2007 (8:03 am)
Sweet! Rebuild successful and I now have 3rd person view.

Of course you know about the wierdness when the level first loads? The camera shoots across the terrain super fast until it gets to the desired position behind the player. Is there any way to make that instant, or do I have to watch that camera move when the level loads?

Also, let us know when/if you setup the "hold both mouse buttons to move the direction you are facing". If it is too much trouble, I'll just bind that to the middle-mouse click.
Page «Previous 1 2 3 4 5 6 7 Last »