Game Development Community

Constraining RTSCamera movement within the mission area/miniMap

by Martin "Founder" Hoover · in RTS Starter Kit · 11/26/2004 (7:51 am) · 13 replies

It kind of bugged me that you could move the camera beyond the mission area, since the mini map won't display units there. So I tossed something together to stop it from happening :)

All the modifications occur in RTSCamera.cc

At the top of the file, after the last #include add:

#ifndef _MISSIONAREA_H_
#include "game/missionArea.h"
#endif

now everything else happens down in void RTSCamera::processTick(const Move* move)

down somewhere around line 384 find:
// Update pos
   Point3F pos;
   pos.x = mTargetPos.x;
   pos.y = mTargetPos.y;
   pos.z = getTerrHeight(mTargetPos) + mCurrHeight;

and After that, add all this juicy stuff (but add it before temp.setPosition(pos);):

bool adjusted = false;
   bool adjustedX = false;
   bool adjustedY = false;
   const RectI area = MissionArea::smMissionArea;
      
//whenever the camera gets to an edge, stop feeding it new positions to go to
//so it simply stops
   if(pos.x <= area.point.x){
      pos.x = F32(area.point.x);
      adjusted = true;
      adjustedX = true; }
   if(pos.x >= (area.point.x + area.extent.x)){
      pos.x = F32(area.point.x + area.extent.x);
      adjusted = true;
      adjustedX = true; }
   if(pos.y <= area.point.y){
      pos.y = F32(area.point.y);
      adjusted = true;
      adjustedY = true; }
   if(pos.y >= (area.point.y + area.extent.y)){
      pos.y = F32(area.point.y + area.extent.y);
      adjusted = true;
      adjustedY = true; }

   if(adjusted)
   {
      mTargetPos.x = pos.x;
      mTargetPos.y = pos.y;
//this keeps the camera from bouncing against the edges
      if(adjustedX)
         mPrevPos.x = pos.x;
      if(adjustedY)
         mPrevPos.y = pos.y;
//lets grab the new height adjustment for this pos to ensure it doesnt jump around
      pos.z = getTerrHeight(Point2F(pos.x, pos.y)) + mCurrHeight;
   }

now go down into the if(move) block, and find these two lines:

mTargetPos.x += ((tempX * mCos(-1 * mCurrYawAngle)) - (tempY * mSin(-1 * mCurrYawAngle)));
      mTargetPos.y += ((tempY * mCos(-1 * mCurrYawAngle)) + (tempX * mSin(-1 * mCurrYawAngle)));

Now we need to replace those two lines all together with the following:

// In order to keep the camera from being stuck on the border of the map we must
// allow it to move away from the edge if thats the move direction. But if its trying to move 
// beyond the edge then we dont want to add anything to the target position thus avoiding 
// bouncing against the border
      if(adjustedX)
      {
         F32 newValue = mTargetPos.x + ((tempX * mCos(-1 * mCurrYawAngle)) - (tempY * mSin(-1 * mCurrYawAngle)));
         if(newValue > area.point.x && newValue < (area.point.x + area.extent.x))
            mTargetPos.x = newValue;

      }
      else
         mTargetPos.x += ((tempX * mCos(-1 * mCurrYawAngle)) - (tempY * mSin(-1 * mCurrYawAngle)));
      
      if(adjustedY)
      {
         F32 newValue = mTargetPos.y + ((tempY * mCos(-1 * mCurrYawAngle)) + (tempX * mSin(-1 * mCurrYawAngle)));
         if(newValue > area.point.y && newValue < (area.point.y + area.extent.y))
            mTargetPos.y = newValue;
      }
      else
         mTargetPos.y += ((tempY * mCos(-1 * mCurrYawAngle)) + (tempX * mSin(-1 * mCurrYawAngle)));

And that's all there is to it. The camera should get right on the edge of the mission area and simply stop moving.

#1
11/26/2004 (10:50 pm)
Thanks Martin. :)
#2
11/26/2004 (11:52 pm)
Very awesome
#3
12/05/2004 (7:52 am)
Works great thanks Martin.
#4
11/06/2005 (2:33 am)
Great work, but honestly wouldn't it be easier to to simply set an OnLeaveMissionArea function to transpose your coordinates, or even simply prevent movement? This way you don't need to play around with the source code?
#5
11/09/2005 (12:04 pm)
The camera isn't actually an object that is "in" or "out" of the mission area, so those calls aren't available (as far as I am aware anyway). Would love to hear that I was wrong and this actually works, but pretty sure I'm right!
#6
11/10/2005 (2:48 am)
Oh thats odd, I honestly assumed it would, oh well back to the drawing board on yet another thing ;)
#7
02/14/2006 (5:33 am)
Is there a dissadvantage to expanding the mission area to cover the entire map?
#8
02/15/2006 (4:58 pm)
None spring to mind. Of course I am assuming you are referring to making the mission area the same size as the terrain tile. I have actually had some mission areas larger then the tiles (Granted I was using a small squareSize for those terrains). Unless you add some sort of code which sets data for every square meter, you should be able to have a mission area as large as you want.
#9
05/03/2007 (9:32 pm)
A little tip around this good resource.

Once the code is added as Martin indicates, we cannot move the camera out of the mission area, even if we want to. Why we would want to? you are (reasonably) thinking. In my case I want to move out the area to have a better perspective, have a more comfortable position to place objects, an so on. So the ideal would be to have total free movement while we are in the Editor, and limited to mission area movement while not. Lucky for us, it is indeed very easy to implement, thanks to the gEditingMission value:

first we add this, just with the Martin include, at the end of the #include block
#ifndef _EDITOR_H_
#include "editor/editor.h"
#endif

Then we take the 2nd code block of Martin and put this after the
const RectI area = MissionArea::smMissionArea;
and before the comment "//whenever the camera ..."
if(!gEditingMission) // if the editor is off...
   {
and add a "}" at the end of that Martin block code to close the new if statement.

Now, instead of replace the two lines
mTargetPos.x += ((tempX * mCos(-1 * mCurrYawAngle)) - (tempY * mSin(-1 * mCurrYawAngle)));
mTargetPos.y += ((tempY * mCos(-1 * mCurrYawAngle)) + (tempX * mSin(-1 * mCurrYawAngle)));
we will put them inside a If in that way
if(gEditingMission) // if the editor is on...
	  {
	  mTargetPos.x += ((tempX * mCos(-1 * mCurrYawAngle)) - (tempY * mSin(-1 * mCurrYawAngle)));
	  mTargetPos.y += ((tempY * mCos(-1 * mCurrYawAngle)) + (tempX * mSin(-1 * mCurrYawAngle)));
	  }
	  else
	  {
Then paste the code as Martin says, and finally add another "}" at the end of the codeblock.
Voila! We have free movement in the editor mode.

Edit: spell check...
#10
06/02/2007 (10:43 pm)
The RTSCamera can be kept within the mission area without changing the code. The code change provided by martin seems to reduce the frame rate. I have implemented this using script alone without any drop in frame rate. I can summarize it as follows.

-define global variables for the mission area width and height and load them when starting or joining the mission
-use schedule and get camera position ($RTSCamera.getPosition) every half a second
-if not in mission area then set camera position ($RTSCamera.setCameraPosition) to the nearest x y coordinates of mission area

You will notice that $RTSCamera.setCameraPosition does not set the position exactly where you define it. The position is always shifted back along the forward vector. I noticed that the extent of the shift back is affected by the height of the camera and the pitch angle. This can be accounted for and adjusted with seperate variables if needed.

There are several ways to achieve this goal even in script depending on game needs.
#11
06/13/2007 (7:13 pm)
Mhh sounds great. What method is used to see the FPSs and/or the average game performance?
#12
06/13/2007 (8:48 pm)
@Novack

metrics(fps)

and looking at ye old CPU usage monitor
#13
06/14/2007 (4:55 pm)
Thx :)
sounds reasonable :D