Game Development Community

dev|Pro Game Development Curriculum

Commander Map

by Kyle Carter · 03/01/2004 (10:52 am) · 155 comments

Download Code File

To use this resource:

1. Copy guiCommanderHud.cc to your engine/gui subfolder.
2. Open your IDE of choice (or a text editor if that's what you like).
3. Add the source file to your project so it will be compiled into Torque.
4. Do a clean rebuild.
5. Go to the GUI of your choice and add a GuiCommanderHud to it. Poof, instant GUI!

Security and Scoping Issues:

The HUD is designed to prevent people from abusing it in-game. It does not change how anything is scoped, so people will only see what the net code would have previously allowed them to see. If you want to have a special "commander map" behavior that shows all active objects you will need to add it either via server side scripting or in GameConnection::doneScopingScene(). Remember, the best way to prevent cheating and improve net performance on your game is to only scope what people need to see.

If you're particularly paranoid, you may want to remove the ConsoleMethods at the end of the file and control the commander map with events; this is probably unnecessary in most cases, as the commander map reveals no more information than the player could get by opening a map in single player mode or a dedicated server and flying/walking around.

Panning and Zooming:

There are three useful actions you can do via scripting with the GuiCommanderHud. First, you can zoom. This basically consists of changing the FOV of the overhead camera that the view is being rendered from (see GuiCommanderHud::processCameraQuery()), so you want to stick to values between 0 and one half pi. Larger values can give "interesting" results though no value should crash the engine. The available script methods for this are zoom() to instantly set the zoom level and zoomTo() to smoothly interpolate to the requested zoom level.

pan() and panTo() let you set the x,y co-ordinates of the overhead camera - essentially setting where the center of the map is. If you wish to pan onto an object, get the first two words of its position and pass them to pan() or panTo().

There are also two exposed fields, panSpeed and zoomSpeed, which let you tweak how quickly panning and zooming occurs. Negative values for these will give catastrophic results!

Performance:

On a 1.8Ghz P4 with 512mb of RAM and a GeForce 4 440 Go (equivalent to a fast GeForce 2), I get 70fps in the test FPS level without the map on screen, and 40fps with it on the screen (in addition to the normal FPS view). Suggested usage is to run the GuiCommanderHud in its own GUI, so that you don't have the overhead of the PlayGUI and its view of the world.

The GuiCommanderHud only renders interior, terrain, water, and environmental objects. You can easily change the mask it uses for rendering the scene by editing GuiCommanderHud::renderWorld() - there is a comment to guide you. Re-enabling all DTS shapes will bring a significant performance hit, since you'll be rendering potentially all the objects in the game world!

Extensions:

There are three major areas in which the GuiCommanderHud could be extended for your game.

First, you may want to render an overlay or icons indicating where objectives/players are. There is a comment located where you would want to render these objects, in GuiCommanderHud::onRender(). Using standard DGL calls will give good results.

Second, you may want to have the control handle mouse input. Looking at EditTSCtrl (located in engine/editor/editTSCtrl.*) will be an excellent guide for this process. You could either inherit from EditTSCtrl, or copy its mouse handling code to the GuiCommanderHud. The project() and unproject() functions that GuiCommmanderHud inherits from GuiTSCtrl may also be useful here.

Finally, you may wish to optimize rendering speed by caching output to a texture, rendering only the texture, and updating the texture as needed when the map needs to change its view. (You could even render to a large texture and simply pan it around, though this would kill the neat parallaxing and depth buffering effects that you could gain from actually rendering the world into the GuiCommanderHud.) This would be a bit tricky, but GuiCommanderHud::onRender would be your starting point. Look at TSShapeInstance::snapshot() for guidance on how to implement this sort of functionality in OpenGL - beware that the DirectX layer may not place nice with this.

Usage Restrictions:

None. Knock yourself out! :) I would ask that you put my name in your credits somewhere and send me a free copy of your game if this resource is a major piece of functionality for your project, but you are by no means required to do so. I'd also appreciate it if, if you found bugs or made enhancements for the code, if you'd send me your change(s) so I can merge them back into this resource. Many eyes find more bugs. ;)

Addendums:

Neat bit of code to try from the console(replace 1494 with the SimObject you want to track). Notice my commander hud is named commHud.

commHud.zoomTo(0.02);
function panPlayer() { commHud.panTo(getWord(1494.getPosition(), 0), getWord(1494.getPosition(), 1)); schedule(100, 0, panPlayer); }
panPlayer();
#21
10/13/2004 (10:10 pm)
I tried it with 1.3.0 and it works perfectly, although with Release, not Debug.

Nick
#22
10/13/2004 (10:14 pm)
Mysterious. Do you get the same behavior in Debug? Are there any console errors or other detritus to help identify the problem?
#23
10/13/2004 (10:32 pm)
No, I meant I haven't tried it at all with Debug. I'll try that tonight.

Nick
#24
10/28/2004 (11:04 am)
It works great with 1.3 in release for me, but it doesn't work with the lighting pack at all. Anyone else had trouble with this GUI and the lighting pack? I didn't merg it with our build, so I'm not sure what changes have been made(I just know it broke my precious commander map :-( ). Its the entire GUI, not just the terrain or something, BTW(perhaps it's a conflict w/ 1.3 & the lighting pack?).
#25
03/01/2005 (1:03 pm)
Joseph that error you are reporting has to do with particle effects... here is the fix...
Fix To Annoying Console Message
Files modified...
~/Torque/engine/game/fx/explosion.cc
Find:
if (mDataBlock->particleEmitter) {
      ParticleEmitter* emitter = new ParticleEmitter;
      emitter->setDataBlock(mDataBlock->particleEmitter);
      emitter->registerObject();
      emitter->emitParticles(getPosition(), mInitialNormal, mDataBlock->particleRadius,Point3F(0, 0, 0), U32(mDataBlock->particleDensity * mFade));
   }
Replace with:
if (mDataBlock->particleEmitter) {
      ParticleEmitter* emitter = new ParticleEmitter;
      emitter->setDataBlock(mDataBlock->particleEmitter);
      // sr: Adding the if else block and the deleteWhenEmpty, since this emitter isn't properly 
      // cleand up in onRemove
      if (emitter->registerObject()) {
         emitter->emitParticles(getPosition(), mInitialNormal, mDataBlock->particleRadius,Point3F(0, 0, 0), U32(mDataBlock->particleDensity * mFade));
         emitter->deleteWhenEmpty();
      } else {
         Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
      }
   }

Hope that helps
#26
03/01/2005 (1:31 pm)
Could someone possibly show how to properly get this thing to popup after adding the .cc to the engine? I know it's in there somewhere but I can't quite seem to get it to popup.

*Update* NM I figured it out, just create a new GUI control and bind the pushdialog to a keypress, viola!
#27
03/02/2005 (6:44 am)
Hi,
I m new to Torque and C++. I m using Torque 1.3 with Synapse Lighting Pack.

I added guicommandermap.cc into my project, did recompile with no errors. bt i m not getting any result after adding guicommandermap into my playgui. do i need to add/change some other settings? I will appriciate if somebody could help me to implement this.
Thanx.

Ali Shikla
#28
06/16/2005 (2:38 am)
Very useful !!! Thanks !!!
#29
12/03/2005 (9:23 pm)
For those interested in having the commander map rotate so the top of the map is always the direction the player is facing, simply replace the processCameraQuery() function in guiCommanderMap.cc with this version below:

bool GuiCommanderHud::processCameraQuery(CameraQuery *q)
{
   // Scale ranges based on the highest/lowest point in the terrain
   F32 maxHi = gClientSceneGraph->getCurrentTerrain()->findSquare(8, 0,0)->maxHeight / 10;
   F32 minHi = gClientSceneGraph->getCurrentTerrain()->findSquare(8, 0,0)->minHeight / 10;

   q->object = NULL;
   q->nearPlane = 1;
   q->farPlane  = mFabs(maxHi) + mFabs(minHi);
   q->fov       = mCurZoom;

   GameConnection* conn;
   conn = GameConnection::getConnectionToServer();
   if (!conn)
      return false;

   MatrixF playercam, mat1, mat2;
   conn->getControlCameraTransform(0, &playercam); // store camera information

   // Get camera angle
   AngAxisF aa(playercam);
   aa.axis.x = 0.0f;
   aa.axis.y = 0.0f;
   aa.setMatrix(&mat1);

   // Create angle to look straight down
   aa.axis.x = 1.0f;
   aa.axis.y = 0.0f;
   aa.axis.z = 0.0f;
   aa.angle = 3.14/2;
   aa.setMatrix(&mat2);

   // Combine the camera angles
   mat1.mul(mat2);

   // Make sure we're high enough that we we won't clip
   mat1.setColumn(3, Point3F(mCurPan.x, mCurPan.y, maxHi + 100));
   q->cameraMatrix = mat1;

   return true;
}

Oh, I should probably add that if you're a TGE 1.3 user, in the above function you'll need to replace this line:
conn = GameConnection::getConnectionToServer();
with this:
conn = GameConnection::getServerConnection();
#30
12/03/2005 (11:57 pm)
Awesome this resource and Robert Geiman's modification work perfectly on 1.4
#31
12/04/2005 (8:22 am)
Thanks Robert. Great addition!
#32
12/13/2005 (5:35 am)
Anyone gotten this working in TSE? I have converted over the GL code but I lock up every time it tries to render.
#33
12/14/2005 (11:26 am)
I made another small modification to CommanderMap, for anyone interested. It allows the player to zoom in/out via the mouse scroll button when their mouse cursor is over the map. The code to do this is below:

Add these two function declarations to the class, just above the "DECLARE_CONOBJECT( GuiCommanderHud )" line:
bool onMouseWheelUp(const GuiEvent &event);
bool onMouseWheelDown(const GuiEvent &event);

Add these two new function definitions to the end of the file:
bool GuiCommanderHud::onMouseWheelUp(const GuiEvent &event)
{
   F32 delta = (mZoomGoal/16) * mZoomSpeed;

   // Don't let the player zoom so far in that they can't
   // tell what's they are looking at.
   if (mZoomGoal - delta >= 0.08)
       mZoomGoal -= delta;

   return( true );
}

bool GuiCommanderHud::onMouseWheelDown(const GuiEvent &event)
{
   F32 delta = (mZoomGoal/16) * mZoomSpeed;

   // Don't let the player zoom so far out that the land doesn't
   // fill the whole commander map
   if (mZoomGoal + delta <= 1.75)
      mZoomGoal += delta;

   return( true );
}

Finally, while CommanderMap exposes the 'zoomSpeed' field, it's not actually being used in the code. You'll want to fix this by changing this line in GuiCommanderHud::OnRender() from:
mCurZoom += (mZoomGoal - mCurZoom) * (F32)dt/1000.f;
to this:
mCurZoom += (mZoomGoal - mCurZoom) * ((F32)(dt/1000.f) * mZoomSpeed);

Finally, I'd recommend changing your zoom speed in the GUI editor from the default 1 to 2.5, which will speed up the zooming greatly.
#34
12/25/2005 (10:44 am)
Huge resource hit on my comp, probably be great if it took a snapshot of the first render, then used an event system to update it or just rendered the mission area.
#35
01/09/2006 (6:45 am)
excellent work m8, and well done to Robert Geiman on his amazing add-ons.
the map directional via mouse works a treat,
but alas
i cant get the mouse zoom to work... =( donno why , no errors in compliing it or runnning it , just wont work. i'll try a few more things but it doesn't look hopeful.

any way i hope someone can answer me this. i'm not quite sure how to attach a bitmap to a player in the map view. so that you my see yourself (as a bitmap ) on the map, and get the map to following that player.

any help would be great
THanks

P.s i'm on MSN and irc nearly all day, you can contact me on "walsh dot stephen at gmail dot com"
#36
01/09/2006 (6:55 am)
Stephen, did you put in the fix in the OnRender() function to ensure that the zoomSpeed is being used? I'd be more than happy to try and help you get the zoom part working. I'll try later today or tomorrow implementing those changes listed in my post to a virgin TGE install to ensure I listed everything needed.

Out of curiosity, are you using TGE 1.3 or 1.4?
#37
01/09/2006 (7:00 am)
using 1.3 =)

Thanks for you help Robert.
yes i put in the onRender() Fix =)
#38
01/09/2006 (3:15 pm)
sorry rob still no luck with that file must be a key bind problem with my mouse wheel.


any ideas on how to bind it?
#39
01/09/2006 (3:49 pm)
tried it in the torque orginal demo- no joy, the mouse wheel works i tested it with messages to the console.

do i have to hold down any key while i zoom in or something??? just dont get it???
#40
01/09/2006 (3:54 pm)
I'm at a loss, Stephen. I've taken a fresh TGE 1.3 install, placed that CommanderMap.cc file in the TGE project, recompiled, and loaded up with a -game Demo. I then clicked on the Walkthrough button so I had an actual moving mouse cursor (rather than the crosshair that's part of the FPS demo), moved the mouse over the commandermap and I'm able to zoom in/out just by scrolling the middle mouse button up/down.