rts-like minimap

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
Nox
Posts: 304
Joined: Wed Jan 14, 2009 6:23 pm

rts-like minimap

Post by Nox »

Here is a snippet which may be helpful. Its a way to draw a minimap with a projection of the viewfrustum on the minimap. Drawingorder of the object depends on the insertionorder:
_Minimap.h

Code: Select all

class MiniMapObject; 

class MiniMap : public IGUIElement 
{ 
   rectf						MovementRect; 
   ISceneManager*				Smgr; 
   core::list<MiniMapObject*>	MMObjects; 
    
public : 
   MiniMap(ISceneManager*, IGUIEnvironment*, IGUIElement* parent, s32 id, rect<s32> MiniMapRect, aabbox3df MovementBox); 
   ~MiniMap(); 

   IVideoDriver*	GetDriver(void)				{ return Environment->getVideoDriver(); } 
   const rectf&		GetMovementRect(void)		{ return MovementRect; } 
   void				Add(MiniMapObject* obj)		{ MMObjects.push_back(obj); } 

   vector2df GetMovementSpacePosition(const vector2di& MinimapSpace); 
   void Remove(MiniMapObject* obj); 
   void draw(void); 
}; 

class MiniMapObject 
{ 
   friend MiniMap; 

protected : 
   bool				Minimap_visible; 
   SColor			Minimap_color; 
   ITexture*		Minimap_image; 
   dimension2df		ObjectSize; 
   MiniMap*			Minimap_Parent; 

public : 

   MiniMapObject(const MiniMapObject&);
   MiniMapObject(MiniMap* Parent, const dimension2df& objectsizeinprecent, const SColor& color); 
   MiniMapObject(MiniMap* Parent, const dimension2df& objectsizeinprecent, const char* image); 
   ~MiniMapObject(); 
    
   virtual void		DrawMiniMapObject(); 
   recti			GetMinimapSpaceRect(); 

   bool VisibleOnMinimap() const		{ return Minimap_visible; } 
   void SetMinimapVisibility (bool val)	{ Minimap_visible = val; } 

   virtual vector2df GetPosition(void) const = 0; 
};
_Minimap.cpp

Code: Select all

#include "irrlicht.h" 

using namespace irr; 
using namespace video; 
using namespace core; 
using namespace gui; 
using namespace scene; 

#include "_Minimap.h" 


vector2di Vector_SpaceToMinimap(const vector2df& posf, const rectf& movement, f32 width_scalfactor, f32 height_scalfactor) 
{    
   return vector2di((s32)( (posf.X - movement.UpperLeftCorner.X) * width_scalfactor + 0.5f), 
                (s32)(-(posf.Y + movement.UpperLeftCorner.Y) * height_scalfactor + 0.5f)); 
} 

MiniMap::MiniMap(ISceneManager* smgr, IGUIEnvironment* environment, IGUIElement* parent, s32 id, recti MiniMapRect, aabbox3df MovementBox) 
: IGUIElement(EGUIET_ELEMENT, environment, parent ? parent : environment->getRootGUIElement(), id, MiniMapRect), Smgr(smgr) 
{ 
   MovementRect = rectf(MovementBox.MinEdge.X, MovementBox.MinEdge.Z, MovementBox.MaxEdge.X, MovementBox.MaxEdge.Z); 
} 

MiniMap::~MiniMap() 
{ 
   for(core::list<MiniMapObject*>::Iterator it = MMObjects.begin(); it != MMObjects.end(); it++) 
      (*it)->Minimap_Parent = NULL; 
} 

vector2df MiniMap::GetMovementSpacePosition(const vector2di& MinimapSpace) 
{ 
   vector2df ret((f32)MinimapSpace.X, (f32)MinimapSpace.Y); 
   ret.X = ret.X * MovementRect.getWidth()  / getAbsolutePosition().getWidth()   + MovementRect.UpperLeftCorner.X; 
   ret.Y = -ret.Y * MovementRect.getHeight() / getAbsolutePosition().getHeight() - MovementRect.UpperLeftCorner.Y; 

   return ret; 
} 

void MiniMap::Remove(MiniMapObject* obj)    
{ 
   for(core::list<MiniMapObject*>::Iterator it = MMObjects.begin(); it != MMObjects.end(); it++) 
   { 
      if(obj == *it) 
      { 
         MMObjects.erase(it); 
         break; 
      } 
   } 
} 
    
void MiniMap::draw(void) 
{ 
   if(!IsVisible) 
      return; 

   //DEBUG
   GetDriver()->draw2DRectangle(0xFF000000, getAbsolutePosition());

   for(core::list<MiniMapObject*>::Iterator it = MMObjects.begin(); it != MMObjects.end(); it++) 
      (*it)->DrawMiniMapObject(); 

   const SViewFrustum* view = Smgr->getActiveCamera()->getViewFrustum(); 


   f32 width_scalfactor  = getAbsolutePosition().getWidth()  / GetMovementRect().getWidth(); 
   f32 height_scalfactor = getAbsolutePosition().getHeight() / GetMovementRect().getHeight(); 

   u16         index = 0; 
   plane3df   movementplanes[4]; 
   plane3df   plane(0,0,0,0,1,0); 
   vector3df   points[16]; 
   vector3df   conepoints[4]; 
   vector2di   linepoints[8]; 
  
   vector3df a(GetMovementRect().LowerRightCorner.X, 0, GetMovementRect().LowerRightCorner.Y); 
   vector3df b(GetMovementRect().UpperLeftCorner.X, 0, GetMovementRect().UpperLeftCorner.Y); 
   movementplanes[0].setPlane(a, vector3df(1,0,0)); 
   movementplanes[1].setPlane(a, vector3df(0,0,1)); 
   movementplanes[2].setPlane(b, vector3df(1,0,0)); 
   movementplanes[3].setPlane(b, vector3df(0,0,1)); 

   points[0]   = view->cameraPosition; 
   points[1]   = view->getFarLeftUp(); 
   points[2]   = view->cameraPosition; 
   points[3]   = view->getFarLeftDown(); 
   points[4]   = view->cameraPosition; 
   points[5]   = view->getFarRightDown(); 
   points[6]   = view->cameraPosition; 
   points[7]   = view->getFarRightUp(); 

   points[8]   = view->getFarRightDown(); 
   points[9]   = view->getFarRightUp(); 
   points[10]   = view->getFarRightUp(); 
   points[11]   = view->getFarLeftUp(); 
   points[12]   = view->getFarLeftUp(); 
   points[13]   = view->getFarLeftDown(); 
   points[14]   = view->getFarLeftDown(); 
   points[15]   = view->getFarRightDown(); 

   for(u16 counter = 0; counter < 16; counter+=2) 
   { 
      vector3df tempvec; 
      if(plane.getIntersectionWithLimitedLine(points[counter], points[counter+1], tempvec)) 
      { 
		if(index == 4)
			return;

		conepoints[index] = tempvec; 
		index++; 
      } 
   } 

   for(u16 counter = 0; counter < 4; counter++) 
   { 
      vector2df temppoint(conepoints[counter].X, conepoints[counter].Z); 
      if(MovementRect.isPointInside(temppoint)) 
      { 
         linepoints[counter]      = Vector_SpaceToMinimap(temppoint, MovementRect, width_scalfactor, height_scalfactor); 
         linepoints[counter+4]   = linepoints[counter]; 
      } 
      else 
      { 
         //correct the point position 
		 vector3df A = conepoints[counter];
		 vector3df B = conepoints[(counter+1)%4];
		 vector3df C = conepoints[counter];
		 vector3df D = conepoints[(counter+3)%4]; 

         for(u16 i = 0; i < 4; i++) 
         { 
			vector3df temppoint;

            if(movementplanes[i].getIntersectionWithLimitedLine(A, B, temppoint)) 
               A = temppoint; 
             
            if(movementplanes[i].getIntersectionWithLimitedLine(C, D, temppoint)) 
               C = temppoint; 
         } 
		 
		 linepoints[counter]   = Vector_SpaceToMinimap(vector2df(A.X, A.Z), MovementRect, width_scalfactor, height_scalfactor);
		 linepoints[counter+4] = Vector_SpaceToMinimap(vector2df(C.X, C.Z), MovementRect, width_scalfactor, height_scalfactor); 
	  } 
   } 

	for(u16 counter = 0; counter < 4; counter++) 
	{
		vector2di start	= linepoints[counter] + getAbsolutePosition().UpperLeftCorner;
		vector2di end	= linepoints[(counter+1)%4+4] + getAbsolutePosition().UpperLeftCorner;
		if(getAbsolutePosition().isPointInside(start) && getAbsolutePosition().isPointInside(end))
			GetDriver()->draw2DLine(start, end); 
	}
} 

MiniMapObject::MiniMapObject(const MiniMapObject &e)
: Minimap_visible(e.Minimap_visible), Minimap_color(e.Minimap_color), Minimap_image(e.Minimap_image), Minimap_Parent(e.Minimap_Parent), ObjectSize(e.ObjectSize) 
{
	if(Minimap_Parent) 
		Minimap_Parent->Add(this); 
}

MiniMapObject::MiniMapObject(MiniMap* map, const dimension2df& sizeinpercent, const SColor &_color) 
: Minimap_visible(true), Minimap_color(_color), Minimap_image(NULL), Minimap_Parent(map), ObjectSize(sizeinpercent) 
{  
	if(Minimap_Parent) 
		Minimap_Parent->Add(this);  
} 

MiniMapObject::MiniMapObject(MiniMap* map, const dimension2df& sizeinpercent, const char* image) 
: Minimap_visible(true), Minimap_color(0), Minimap_image(NULL), Minimap_Parent(map), ObjectSize(sizeinpercent) 
{
	if(Minimap_Parent) 
		Minimap_Parent->Add(this); 
   
	Minimap_image = Minimap_Parent->GetDriver()->getTexture(image);  
} 

MiniMapObject::~MiniMapObject() 
{ 
	if(Minimap_Parent) 
		Minimap_Parent->Remove(this); 
} 

void MiniMapObject::DrawMiniMapObject() 
{ 
   if(!Minimap_visible || !Minimap_Parent) 
      return; 

   recti drawrc = GetMinimapSpaceRect() + Minimap_Parent->getAbsolutePosition().UpperLeftCorner; 

   if(Minimap_image) 
      Minimap_Parent->GetDriver()->draw2DImage(Minimap_image, drawrc, recti(vector2di(), Minimap_image->getSize())); 
   else 
      Minimap_Parent->GetDriver()->draw2DRectangle(Minimap_color, drawrc, &Minimap_Parent->getAbsolutePosition()); 
} 

recti MiniMapObject::GetMinimapSpaceRect(void) 
{ 
   f32 width_scalfactor  = Minimap_Parent->getAbsolutePosition().getWidth()  / Minimap_Parent->GetMovementRect().getWidth(); 
   f32 height_scalfactor = Minimap_Parent->getAbsolutePosition().getHeight() / Minimap_Parent->GetMovementRect().getHeight(); 

   vector2di pos = Vector_SpaceToMinimap(GetPosition(), Minimap_Parent->GetMovementRect(), width_scalfactor, height_scalfactor); 

   return recti(   pos.X - (s32)(ObjectSize.Width  * Minimap_Parent->getAbsolutePosition().getWidth()), 
               pos.Y - (s32)(ObjectSize.Height * Minimap_Parent->getAbsolutePosition().getHeight()), 
               pos.X + (s32)(ObjectSize.Width  * Minimap_Parent->getAbsolutePosition().getWidth()), 
               pos.Y + (s32)(ObjectSize.Height * Minimap_Parent->getAbsolutePosition().getHeight())); 
}  
testmain.cpp

Code: Select all

#include <irrlicht.h> 

using namespace irr; 
using namespace video; 
using namespace core; 
using namespace gui; 
using namespace scene; 

#include "_Minimap.h"

struct Object : public MiniMapObject
{
	ISceneNode* cube;

	Object(ISceneManager *Smgr, vector3df pos, MiniMap* map)
		: MiniMapObject(map, dimension2df(0.05f,0.05f), 0xFF00FF00)
	{
		cube = Smgr->addCubeSceneNode(10.f, 0,-1,pos);
	}

	vector2df  GetPosition(void) const	{ return vector2df(cube->getPosition().X, cube->getPosition().Z); }
};

void main() 
{ 
	IrrlichtDevice *irr		= createDevice( video::EDT_OPENGL, dimension2du(1024,786)); 
	IVideoDriver *Video		= irr->getVideoDriver(); 
	ISceneManager *Smgr		= irr->getSceneManager(); 
	IGUIEnvironment *Gui	= irr->getGUIEnvironment(); 

	Smgr->addCameraSceneNodeFPS()->setPosition(vector3df(0,200,-10)); 

	aabbox3df MovementBox(-1000,-100,-1000, 1000, 100, 1000);
	MiniMap map(Smgr, Gui, 0, -1, recti(10,10,150,150), MovementBox);

	array<Object> testobjects;

	srand(irr->getTimer()->getTime());
	for(unsigned counter = 0; counter < 10; counter++)
	{
		vector3df pos;

		pos.X = MovementBox.MinEdge.X + MovementBox.getExtent().X * (rand() % 1000) / 1000.0f; 
		pos.Y = MovementBox.MinEdge.X + MovementBox.getExtent().Y * (rand() % 1000) / 1000.0f; 
		pos.Z = MovementBox.MinEdge.X + MovementBox.getExtent().Z * (rand() % 1000) / 1000.0f; 

		testobjects.push_back(Object(Smgr, pos, &map));
	}

	while( irr->run() ) 
	{ 
		Video->beginScene( true, true, video::SColor(255,100,101,140) ); 
		Smgr->drawAll(); 
		Gui->drawAll(); 
		Video->endScene(); 
	} 

	irr->drop(); 
} 
Last edited by Nox on Mon Feb 22, 2010 2:58 pm, edited 2 times in total.
shadowslair
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Post by shadowslair »

Useful indeed. Some screenshots of the map "in action" will be nice also. :wink:
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
Nox
Posts: 304
Joined: Wed Jan 14, 2009 6:23 pm

Post by Nox »

Thats a problem because i dont know a provider which does not drop an image after some time :? So the image will be invalid after a short while.
d3jake
Posts: 198
Joined: Sat Mar 22, 2008 7:49 pm
Location: United States of America

Post by d3jake »

You could sign up for an account on Photobucket and upload the pictures. So long as you log in every three or four months you should keep the account. I don't think there are any garunteed hosts... I could offer to upload scrrenshots to some web space that I have, but again, I can't be certain it'll never go down.
The Open Descent Foundation is always looking for programmers! http://www.odf-online.org
"I'll find out if what I deleted was vital here shortly..." -d3jake
Nox
Posts: 304
Joined: Wed Jan 14, 2009 6:23 pm

Post by Nox »

Well here is a little pic:

Image

there is a litte issue: objects at the border can draw other the border. But if the objects or the movementrect are choosen proberly this is no big deal. Or i will add some clipping in MiniMapObject::DrawMiniMapObject.
frost_bite
Posts: 28
Joined: Wed Dec 03, 2008 11:42 pm

Post by frost_bite »

Can someone post a test-case scenario that shows how to use this code? I've tried and it does not render the camera position on the minimap correctly.
Nox
Posts: 304
Joined: Wed Jan 14, 2009 6:23 pm

Post by Nox »

Can you provide some info? Maybe I can help you :)
woosup
Posts: 3
Joined: Sat Feb 20, 2010 8:05 pm

hey

Post by woosup »

i have tried this but it doesn't done.


Nox can you put test source pls?




thanks.
Nox
Posts: 304
Joined: Wed Jan 14, 2009 6:23 pm

Post by Nox »

i can provide some code snippets from my project but i have no stand-alone testsuite for it. Would consum some time. :? Would some snippets help you? Cant you provide your code or describe the problem a bit more accurate?
woosup
Posts: 3
Joined: Sat Feb 20, 2010 8:05 pm

np

Post by woosup »

Nox wrote:i can provide some code snippets from my project but i have no stand-alone testsuite for it. Would consum some time. :? Would some snippets help you? Cant you provide your code or describe the problem a bit more accurate?
yes, u are right.

but actually i have no project for use this lib so

i made test source

can u help me?


thanks.

Code: Select all

#pragma comment( lib, "irrlicht.lib" )

#include < irrlicht.h >
using namespace irr;

void addtarget( const char* RootNodeName, core::vector3df pos, const char* nodename )
{
	scene::ISceneNode * pNode = g_pSmgr->addCubeSceneNode(2,g_pSmgr->getSceneNodeFromName( RootNodeName ) );
	pNode->setPosition( pos + core::vector3df( 0, 1, 0 ) );
	pNode->setMaterialFlag(video::EMF_LIGHTING,false);
	pNode->setMaterialFlag(video::EMF_WIREFRAME,true);
	pNode->setName( nodename );

}

void main()
{
	IrrlichtDevice *pDevice = createDevice( video::EDT_DIRECT3D9 );
	
	pDevice->setWindowCaption(L"hello irrlicht 3d engine");
	video::IVideoDriver *pVideo = pDevice->getVideoDriver();
	scene::ISceneManager *pSmgr = pDevice->getSceneManager();
	gui::IGUIEnvironment *pGuiEnv = pDevice->getGUIEnvironment();

	pSmgr->addCameraSceneNode( 0,
		core::vector3df( 0, 30, -40 ), 
		core::vector3df( 0, 5, 0) ); 

	for( int i = 1 ; i <= 20 ; i++ )
	{
		for ( int j = 1 ; j <= 20 ; j++ )
		{
			addtarget( "woo/scene/target/root", core::vector3df((f32)((i*3)-30),0,(f32)((j*3))),"wall" );
		}
	}

	while( pDevice->run() )
	{
		pVideo->beginScene( true, true, video::SColor(255,100,101,140) );
		pSmgr->drawAll();
		pGuiEnv->drawAll();
		pVideo->endScene();
	}

	pDevice->drop();
}
Nox
Posts: 304
Joined: Wed Jan 14, 2009 6:23 pm

Post by Nox »

Based on your example I generated a little testcode and up it in the first post. I hope it works for the actual irrlichtversion because I use an old tweaked version. Hf :)

P.S. the view area is only shown if you are in a valid position.
woosup
Posts: 3
Joined: Sat Feb 20, 2010 8:05 pm

very nice

Post by woosup »

Nox wrote:Based on your example I generated a little testcode and up it in the first post. I hope it works for the actual irrlichtversion because I use an old tweaked version. Hf :)

P.S. the view area is only shown if you are in a valid position.
oh!!

its pretty work :D

thx alot ^^


i will learn from this code.

i will make other one minimap for my game

and show you

when i have done .


thanks again.
Post Reply