Game Development Community

visible waypoint/objective markers ?

by Tom Vogt · in Torque Game Engine · 09/15/2002 (2:12 am) · 27 replies

In order to avoid people getting lost on the map, I would like to implement visible waypoint markers, i.e. they must show up in-game, very much like the objective markers in T2 do.

I've tried all the markers in Torque, but non of them appear to have that property. Has anyone coded this already?
Page «Previous 1 2
#1
09/16/2002 (6:45 pm)
I have done ones like that but I don't know ALL of the math behind it so it's kindof sketchy. It's not that hard to do if you know what you're doing. would you like it?
#2
09/16/2002 (11:21 pm)
Yes, I would definitely love this, as right now I don't even know where to start. :-(
#3
09/18/2002 (3:18 pm)
#include "dgl/dgl.h"
#include "gui/guiControl.h"
#include "gui/guiTSControl.h"
#include "console/consoleTypes.h"
#include "sceneGraph/sceneGraph.h"
#include "game/shapeBase.h"
#include "game/game.h"
#include "game/gameConnection.h"
#include "game/missionMarker.h"
#include "gui/guiPopUpCtrl.h"
#include "gui/guiBitmapCtrl.h"


//-----------------------------------------------------------------------------
/*
To add a marker, add a marker object to the map.
*/
class GuiWaypointHud : public GuiBitmapCtrl {
   typedef GuiBitmapCtrl Parent;
	
   // field data
   ColorF   mFillColor;
   ColorF   mFrameColor;
   ColorF   mTextColor;
	
   F32      mVerticalOffset;
   F32      mDistanceFade;
   bool     mShowFrame;

  	StringTableEntry mMarker;
	StringTableEntry mWaypnt;  //I like uniform length variables  :)

	TextureHandle mTexMarker;
	TextureHandle mTexWaypnt;
	
public:
   GuiWaypointHud();

   // GuiControl
   bool onWake();
	virtual void onRender(Point2I, const RectI &updateRect);
   
   static void initPersistFields();
   DECLARE_CONOBJECT( GuiWaypointHud );
};


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

IMPLEMENT_CONOBJECT(GuiWaypointHud);
static void findObjectsCallback(SceneObject* obj, S32 val)
{  
   Vector<SceneObject*> * list = (Vector<SceneObject*>*)val;
   list->push_back(obj);
}

static const F32 cDefaultVisibleDistance = 500.0f;

GuiWaypointHud::GuiWaypointHud()
{
   mFillColor.set( 0.25, 0.25, 0.25, 0.25 );
   mFrameColor.set( 0, 1, 0, 1 );
   mTextColor.set( 0, 1, 0, 0.75 );
   mShowFrame = true;
   mVerticalOffset = 0.5;
   mDistanceFade = 0.1;
	mMarker = StringTable->insert("");
	mWaypnt = StringTable->insert("");
}

void GuiWaypointHud::initPersistFields()
{
   Parent::initPersistFields();
	addField( "fillColor", TypeColorF, Offset( mFillColor, GuiWaypointHud ) );
   addField( "frameColor", TypeColorF, Offset( mFrameColor, GuiWaypointHud ) );
   addField( "textColor", TypeColorF, Offset( mTextColor, GuiWaypointHud ) );
	
	addField( "markerImage", TypeFilename, Offset( mMarker, GuiWaypointHud ) );
	addField( "waypointImage", TypeFilename, Offset (mWaypnt, GuiWaypointHud ) );

   addField( "showFrame", TypeBool, Offset( mShowFrame, GuiWaypointHud ) );
   addField( "verticalOffset", TypeF32, Offset( mVerticalOffset, GuiWaypointHud ) );
   addField( "distanceFade", TypeF32, Offset( mDistanceFade, GuiWaypointHud ) );
}

bool GuiWaypointHud::onWake()
{
   if (! Parent::onWake())
      return false;
   mMarker = StringTable->insert(mMarker);
	mWaypnt = StringTable->insert(mWaypnt);
   if (*mMarker)
	   mTexMarker = TextureHandle(mMarker, MeshTexture);
   else
	   mTexMarker = NULL;
	if (*mWaypnt)
		mTexWaypnt = TextureHandle(mWaypnt, MeshTexture);
	else
		mTexWaypnt = NULL;
   return true;
}

//-----------------------------------------------------------------------------
/**
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.
*/
struct WaypointF
{
		Point3F pos;
		char* name;
		bool marker;
		int team;
};

F32 mDist(Point3F point)
{
	return sqrt(point.x * point.x + point.y * point.y + point.z * point.z);
}

void GuiWaypointHud::onRender( Point2I offset, const RectI &updateRect)
{
	// Must be in a TS Control
	
   // Must have a connection and control object
   GameConnection* conn = GameConnection::getServerConnection();
   if (!conn) return; //need connection to server
	ShapeBase* control = conn->getControlObject();
	if (!control) return;
	WaypointF waypointData[20];//waypoint data
	int count = 0;//control->getWaypoints(waypointData); //get user waypoints (player.cc/h) (no longer = just defines)
   Vector<MissionMarker*> markers;
   gServerContainer.findObjects(MarkerObjectType, findObjectsCallback, (S32)&markers); //find all marker objects

   //distinguish between marker and waypoint and put the data into a separate array
	for (U32 i = 0; i < markers.size(); i++)
   {
		waypointData[count].name = (char*)markers[i]->getName();
		waypointData[count].team = markers[i]->getFoFIndex();
		waypointData[count].pos = markers[i]->getPosition();

		//waypointData[count].marker = false;
		waypointData[count].marker = true;
		WayPoint* wp = dynamic_cast<WayPoint*>(markers[i]);
		if(wp)
			waypointData[count].marker = false;
		count++;
		//if you have more than 20 on your screen, it's going to be very cluttered anyway
		if (count >= 20)
			break;
	}

	dglClearBitmapModulation();	//clear any color modulation
	TextureHandle bitMap;
	bitMap = mTexWaypnt;
   GuiTSCtrl *parent = dynamic_cast<GuiTSCtrl*>(getParent());
   if (!parent) return; //need parent
	for (int inc = 0; inc < count; inc++)
	{

		MatrixF cam;
		Point3F camPos;
		VectorF camDir;
		conn->getControlCameraTransform(0,&cam);
		cam.getColumn(3, &camPos);
		cam.getColumn(1, &camDir);
		
		F32 camFov;
		conn->getControlCameraFov(&camFov);
		
		F32 markDist = mDist(camPos - waypointData[inc].pos)/2;
		VectorF shapeDir = waypointData[inc].pos - camPos;
		F32 dot = mDot(shapeDir, camDir);
		Point2I extent = parent->getExtent();
		Point3F screen;
		screen.x = 0;
		screen.y = 0;
		screen.z = 0;
		Point3F temp = waypointData[inc].pos;
		temp -= camPos;
		temp /= 10;
		temp += camPos;
		if (!parent->project(temp, &screen))
		{
			float angle = 180 / 3.1415926535 * acos(mDot(camDir, temp)/(mDist(camDir-camPos) * mDist(temp-camPos)));
			screen.x = extent.x;
			if (angle > camFov/2)
				screen.y = 0;
			screen.y = extent.y/2 + (camPos.y - waypointData[inc].pos.y);
		}

		Point2I pos = parent->getPosition();
		if (screen.x > extent.x - (mProfile->mFont->getStrWidth((const char*)waypointData[inc].name)/2 + 5))
			screen.x = extent.x - (mProfile->mFont->getStrWidth((const char*)waypointData[inc].name)/2 + 5);
		if (screen.y > extent.y - 20)
			screen.y = extent.y - 20;
		if (screen.x < pos.x + (mProfile->mFont->getStrWidth((const char*)waypointData[inc].name)/2 + 5))
			screen.x = pos.x + (mProfile->mFont->getStrWidth((const char*)waypointData[inc].name)/2 + 5);
		if (screen.y < pos.y + 20)
			screen.y = pos.y + 20;
		
		bitMap = mTexMarker;
		glColor4f(1.0,1.0,0.0,0.7);
		if (!waypointData[inc].marker)
		{		
			bitMap = mTexWaypnt;
			glColor4f(1.0,0.0,0.0,0.7);
			if (waypointData[inc].team == control->getFoFIndex())
				glColor3f(0.0,1.0,0.0);
		}
		if(bitMap)
		{
			// Make the center of the bitmap the offset point
			Point2I imgCenter( bitMap.getWidth()/2, bitMap.getHeight()/2 );
			dglSetBitmapModulation(ColorF(1.0,0.0,0.0));
			if (waypointData[inc].team == control->getFoFIndex())
				dglSetBitmapModulation(ColorF(0.0,1.0,0.0));
			dglDrawBitmap(bitMap,Point2I(screen.x - imgCenter.x,screen.y + imgCenter.y));
		}
		else
		{
			dglDrawRectFill(Point2I(screen.x, screen.y), Point2I(screen.x + 20, screen.y - 20), ColorI(1.0,0.0,0.0));
		}
		screen.x -= mProfile->mFont->getStrWidth((const char*)waypointData[inc].name)/2;
		screen.y += bitMap.getHeight() + 10;
		dglSetBitmapModulation(mTextColor);
		dglDrawText(mProfile->mFont, Point2I(screen.x, screen.y - 2), waypointData[inc].name);
	    static char buf[32];
	    dSprintf(buf, sizeof(buf), "%i", (int)markDist);
		dglDrawText(mProfile->mFont, Point2I(screen.x + (mProfile->mFont->getStrWidth((const char*)waypointData[inc].name) - mProfile->mFont->getStrWidth((const char*)buf))/2, screen.y + 10), (char*)buf);
		dglClearBitmapModulation();
	}
}
The display when it's not in front of the view doesn't work too well, so any suggestions on that would be appreciated. Other than that, it only works with sticking an icon on marker objects defined in the map. I havn't been able to test it with user defined waypoints yet. Other than that it should work sufficiently. And, as you can see, I stripped a lot from shapenamehud.cc :)
#4
09/19/2002 (1:12 am)
hm, which version of torque are you using? I get this compile error:

gui/guiWaypointHud.cc:221: no matching function for call to
'ShapeBase::getFoFIndex()'

and indeed, there is no "getFoFIndex" anywhere in the source.
#5
09/19/2002 (6:38 am)
Ahh...that's a function from our FOF hud to get the team number of the object. This is used for coloring the marker to show team ownership. You can just yank that out of there and all of the coloring stuff. Make sure you have those files too, or else you'll get squares instead of icons. You have to set the filename in the gui editor.
#6
09/19/2002 (7:06 am)
Ah, it works great now. Thanks a lot!
#7
11/21/2002 (8:45 am)
I've finally had a chance to test this in multiplayer, and there's a problem - the markers show up only on the server, not on the client.

How do I tell it to ghost the markers to the client?
#8
11/21/2002 (5:11 pm)
I had the same problem. You have to find the waypoints differently. Here's the source:
for(SimSetIterator itr(conn); *itr; ++itr)
	{
		if((*itr)->getType() & (MarkerObjectType | StaticShapeObjectType))
		{
		ShapeBase *shape = static_cast<ShapeBase*>(*itr);
			if (shape->getWaypointStatus() == 2)
			{
				char* waypointName = (char*)shape->getShapeName();
				if (waypointName == 0)
				{
					waypointName = "unknown";
					if (shape->getFoFIndex() == 1)
						waypointName = (char*)Con::getVariable( "pref::Server::TeamName1" );
					if (shape->getFoFIndex() == 2)
						waypointName = (char*)Con::getVariable( "pref::Server::TeamName2" );
					if (shape->getFoFIndex() == 0)
						waypointName = "Neutral";
				}

				bool isMarker = true;
				WayPoint* wp = dynamic_cast<WayPoint*>(shape);
				if (wp)
					isMarker = false;
That should help you get started.
#9
11/22/2002 (12:25 am)
Sorry, this just confuses me completely. Where is that code supposed to go? (I'm not much into Torque coding, just scripting)
#10
11/22/2002 (8:42 am)
Ah, well, that pretty much replaces the stuff were waypointData got it's...well...data. I actually restructured it so that it uses one loop instead of 2 because I didn't know what I was doing before. I don't really want to just copy-paste my file because that will probably just confuse you more because of all of the specialization there now.
#11
11/22/2002 (9:48 am)
Hm, I tried, and after a few tries got it to work, but it still shows only locally.

Oh darn, I guess I'll have to set our coder to this problem and go back to my scripts. Thanks for the help anyway.
#12
11/22/2002 (9:59 am)
That way of getting the waypoint data should work properly. It has worked for my team for a couple months now...

You probably just forgot to port something over. Make sure that you're getting your information from the SimIterator, not by going through the server scenegraph.
#13
11/22/2002 (10:55 am)
How about a resource?
#14
11/22/2002 (11:13 am)
Well, I still have to fix the placement on the screen of the waypoints - I don't know enough math to do it, and I could use some help. If I can do that, I'd be happy to submit it.
#15
06/22/2003 (6:56 am)
Bump bump, any progress on this?
#16
06/22/2003 (2:15 pm)
*pokes Chris*
#17
06/22/2003 (5:20 pm)
I'm working on the same project as Hobbs and I've taken over this area of the project.

The method Chris had implemented in our project wasn't good enough for what we needed, since the behavior he coded acted more like 'road signs' then an actual sensor network, ie Tribes/Tribes 2 sensor network.

After we discovered this flaw in the design I took over the project and began reimplementing, through research and guess work, the sensor network code that was ripped out of the engine.

This has gone very well, better then I had hoped, and we now have a lot of the functionality that was lost such as line of sight and radius based sensor detection.

Now I'm in the process of recreating the Tribes/Tribes 2 command screen to provide an easy interface for clients to specify their own waypoints.

You can see the waypoints in action here:
www.cs.montana.edu/~blanche/waypoints.JPG
However, due to the enormous changes I made to the engine for this functionality and the very little time I have, I wont be sharing this with the community anytime soon. Sorry for the frustration and I hope you figure out what you need.
#18
06/24/2003 (3:19 pm)
Blah...

Yeah, what I did would work for most people, but not for our project. The actual rendering still needs work. I havn't touched the projection or anything. They project fine when the waypoints are actually in the viewspace, but when they're not, the project function fails, and I have to do some kind of other projection routine, which I don't know how to do. What's in there is merely guesswork and is really not fit for release. It is also very specialized to our project. It's really not THAT hard to do. Use what I had posted before as a template and code it yourself. You're probably going to have to make major changes to it anyway for your particular project anyway.


EDIT:
Oh yeah, and at the time I coded it, I wasn't too great at torque yet, and just looking over it, I see a LOT of things that should be done that would make that code a whole lot more efficient and torque-ized (not to mention shorter). And, I really don't have time to keep it up to date. So, sorry :\
#19
06/01/2004 (8:05 am)
Hey, I was wondering if anyone had fixed this up to work fully, I was gonna give it a try but ended up screwing up the code :P. If anyone has fixed this let me know!
#20
06/01/2004 (1:46 pm)
I would also be interest in a working waypoint GUI.
Page «Previous 1 2